Next.js is a SSR framework with both client-side and server-side rendering. To track errors in your Next.js app, you need to install and configure the PostHog SDK for both client-side and server-side.
- 1
Install PostHog SDK client-side
RequiredInstall
posthog-js
using your package manager:npm install --save posthog-jsAdd your environment variables to your
.env.local
file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project API key in your project settings..env.localNEXT_PUBLIC_POSTHOG_KEY=<ph_project_api_key>NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.comThese values need to start with
NEXT_PUBLIC_
to be accessible on the client-side.Integration
Next.js 15.3+ provides the
instrumentation-client.ts|js
file for a quick, lightweight setup. Add it to the root of your Next.js app (for both app and pages router) and initialize PostHog in it like this:import posthog from 'posthog-js'posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,defaults: '2025-05-24'});Using Next.js 15.2 or older?
Older versions of Next.js don't support the
instrumentation-client.ts|js
file. You can use the following setup instead:If your Next.js app uses the app router, you can integrate PostHog by creating a
providers
file in your app folder. This is because theposthog-js
library needs to be initialized on the client-side using the Next.js'use client'
directive.// app/providers.jsx'use client'import posthog from 'posthog-js'import { PostHogProvider as PHProvider } from 'posthog-js/react'import { useEffect } from 'react'export function PostHogProvider({ children }) {useEffect(() => {posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,defaults: '2025-05-24',})}, [])return (<PHProvider client={posthog}>{children}</PHProvider>)}Then, import the
PostHogProvider
component into yourapp/layout
file and wrap your app with it.// app/layout.jsximport './globals.css'import { PostHogProvider } from './providers'export default function RootLayout({ children }) {return (<html lang="en"><body><PostHogProvider>{children}</PostHogProvider></body></html>)}PostHog is now set up and ready to go. It will begin to autocapture events and pageviews. Files and components accessing PostHog on the client-side need the
'use client'
directive. - 2
Capture client-side exceptions
RequiredYou can capture exceptions in client-side code in two ways:
- Manual capture: Use
posthog.captureException()
in components that include'use client'
. - Autocapture: PostHog will automatically capture
$exception
events when errors are thrown.
Setting up exception autocapture
Note: A minimum SDK version of v1.207.8 is required, but we recommend keeping up to date with the latest version to ensure you have all of error tracking's features.
You can enable exception autocapture for the JavaScript Web SDK in the Error tracking section of your project settings.
When enabled, this automatically captures
$exception
events when errors are thrown by wrapping thewindow.onerror
andwindow.onunhandledrejection
listeners.Manual error capture
It is also possible to manually capture exceptions using the
captureException
method:JavaScriptposthog.captureException(error, additionalProperties)Next.js uses error boundaries to handle uncaught exceptions by rendering a fallback UI instead of the crashing components.
To set one up, create a
error.tsx
file in any of your route directories. This triggers when there is an error rendering your component and should look like this:error.tsx"use client"; // Error boundaries must be Client Componentsimport posthog from "posthog-js";import { useEffect } from "react";export default function Error({error,reset,}: {error: Error & { digest?: string }reset: () => void}) {useEffect(() => {posthog.captureException(error);}, [error]);return (...);}You can also create a Global Error component in your root layout to capture unhandled exceptions in your root layout.
app/global-error.tsx'use client' // Error boundaries must be Client Componentsimport posthog from "posthog-js";import NextError from "next/error";import { useEffect } from "react";export default function GlobalError({error,reset,}: {error: Error & { digest?: string }reset: () => void}) {useEffect(() => {posthog.captureException(error);}, [error]);return (// global-error must include html and body tags<html><body>{/* `NextError` is the default Next.js error page component */}<NextError statusCode={0} /></body></html>)} - Manual capture: Use
- 4
Installing PostHog SDK for server-side
RequiredYour goal in this step: Install the PostHog Node.js SDK for server-side error tracking.Next.js enables you to both server-side render pages and add server-side functionality. To integrate PostHog into your Next.js app on the server-side, you can use the Node SDK.
First, install the
posthog-node
library:npm install posthog-node --saveFor the backend, we can create a
lib/posthog-server.js
file. In it, initialize PostHog fromposthog-node
as a singleton with your project API key and host from your project settings.This looks like this:
lib/posthog-server.jsimport { PostHog } from 'posthog-node'let posthogInstance = nullexport function getPostHogServer() {if (!posthogInstance) {posthogInstance = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY,{host: process.env.NEXT_PUBLIC_POSTHOG_HOST,flushAt: 1,flushInterval: 0,})}return posthogInstance}You can now use the
getPostHogServer
function to capture exceptions in server-side code.JavaScriptconst posthog = getPostHogServer()try {throw new Error("This is a test exception for error tracking")} catch (error) {posthog.captureException(error, {source: 'test',user_id: 'test-user-123',})} - 5
Capturing server-side exceptions
RequiredYour goal in this step: Capture your first server-side exception event.To capture errors that occur in your server-side code, you can set up a
instrumentation.ts
file at the root of your project. This provides aonRequestError
hook that you can use to capture errors.Importantly, you need to:
- Set up a
posthog-node
client in your server-side code. See our doc on setting up Next.js server-side analytics for more. - Check the request is running in the
nodejs
runtime to ensure PostHog works. You can callposthog.debug()
to get verbose logging. - Get the
distinct_id
from the cookie to connect the error to a specific user.
This looks like this:
JavaScript// instrumentation.jsexport function register() {// No-op for initialization}export const onRequestError = async (err, request, context) => {if (process.env.NEXT_RUNTIME === 'nodejs') {const { getPostHogServer } = require('./lib/posthog-server')const posthog = await getPostHogServer()let distinctId = nullif (request.headers.cookie) {const cookieString = request.headers.cookieconst postHogCookieMatch = cookieString.match(/ph_phc_.*?_posthog=([^;]+)/)if (postHogCookieMatch && postHogCookieMatch[1]) {try {const decodedCookie = decodeURIComponent(postHogCookieMatch[1])const postHogData = JSON.parse(decodedCookie)distinctId = postHogData.distinct_id} catch (e) {console.error('Error parsing PostHog cookie:', e)}}}await posthog.captureException(err, distinctId || undefined)}}You can find a full example of both this and client-side error tracking in our Next.js error monitoring tutorial.
- Set up a
- 6