Next.js error tracking installation

Last updated:

|Edit this page|

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

    Required

    Install posthog-js using your package manager:

    npm install --save posthog-js

    Add 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.local
    NEXT_PUBLIC_POSTHOG_KEY=<ph_project_api_key>
    NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com

    These 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 the posthog-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 your app/layout file and wrap your app with it.

    // app/layout.jsx
    import './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

    Required

    You can capture exceptions in client-side code in two ways:

    1. Manual capture: Use posthog.captureException() in components that include 'use client'.
    2. 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 the window.onerror and window.onunhandledrejection listeners.

    Manual error capture

    It is also possible to manually capture exceptions using the captureException method:

    JavaScript
    posthog.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 Components
    import 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 Components
    import 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>
    )
    }
  3. Verify error tracking

    Checkpoint
    Confirm events are being sent to PostHog

    Before proceeding, let's make sure exception events are being captured and sent to PostHog. You should see events appear in the activity feed.


    Activity feed with events
    Check for exceptions in PostHog
  4. Installing PostHog SDK for server-side

    Required
    Your 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 --save

    For the backend, we can create a lib/posthog-server.js file. In it, initialize PostHog from posthog-node as a singleton with your project API key and host from your project settings.

    This looks like this:

    lib/posthog-server.js
    import { PostHog } from 'posthog-node'
    let posthogInstance = null
    export 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.

    JavaScript
    const 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. Verify server-side exceptions

    Checkpoint
    Confirm capture is working server-side

    You should also see events and exceptions in PostHog coming from your server-side code in the activity feed.

    Check for server events in PostHog
  6. Capturing server-side exceptions

    Required
    Your 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 a onRequestError hook that you can use to capture errors.

    Importantly, you need to:

    1. Set up a posthog-node client in your server-side code. See our doc on setting up Next.js server-side analytics for more.
    2. Check the request is running in the nodejs runtime to ensure PostHog works. You can call posthog.debug() to get verbose logging.
    3. Get the distinct_id from the cookie to connect the error to a specific user.

    This looks like this:

    JavaScript
    // instrumentation.js
    export 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 = null
    if (request.headers.cookie) {
    const cookieString = request.headers.cookie
    const 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.

  7. Upload source maps

    Required

    Great, you're capturing exceptions! If you serve minified bundles, the next step is to upload source maps to generate accurate stack traces.

    Let's continue to the next section.

    Upload source maps for Next.js

Questions? Ask Max AI.

It's easier than reading through 698 pages of documentation

Community questions

Was this page useful?

Next article

Python error tracking installation

In your app, import the posthog library and set your project API key and host before making any calls. You can find these in the project settings page in PostHog. Note: As a rule of thumb, we do not recommend having API keys in plaintext. Setting it as an environment variable is best. To debug, you can toggle debug mode: To make sure no calls happen during tests, you can disable PostHog, like so: Before proceeding, enable debug and call posthog.capture('test_event') to make sure you can…

Read next article