NestJS Error Tracking installation

  1. Install the PostHog Node SDK

    Required

    Install the PostHog Node SDK:

    Terminal
    npm install posthog-node
    # or
    yarn add posthog-node
    # or
    pnpm add posthog-node
  2. Initialize the client and interceptor

    Required

    Create a PostHog client and register the PostHogInterceptor globally with captureExceptions enabled:

    main.ts
    import { NestFactory } from '@nestjs/core'
    import { PostHog } from 'posthog-node'
    import { PostHogInterceptor } from 'posthog-node/nestjs'
    import { AppModule } from './app.module'
    async function bootstrap() {
    const app = await NestFactory.create(AppModule)
    const posthog = new PostHog('<ph_project_token>', {
    host: 'https://us.i.posthog.com',
    })
    app.useGlobalInterceptors(
    new PostHogInterceptor(posthog, { captureExceptions: true })
    )
    await app.listen(3000)
    }
    bootstrap()

    This automatically captures unhandled exceptions (5xx) and sends them to PostHog as $exception events, including stack traces and request context.

    Configuration options

    OptionTypeDefaultDescription
    captureExceptionsboolean \| objectfalseEnable exception capture. Pass true for defaults or an object to configure.
    captureExceptions.minStatusToCapturenumber500Minimum HTTP status code to capture. Exceptions with a lower status (e.g. 4xx) are skipped.

    To also capture 4xx errors:

    TypeScript
    app.useGlobalInterceptors(
    new PostHogInterceptor(posthog, {
    captureExceptions: { minStatusToCapture: 400 },
    })
    )
    How it works

    The interceptor observes exceptions transparently using an RxJS catchError without interfering with NestJS's exception filter pipeline. It skips already-captured errors and HttpExceptions below the configured threshold, then re-throws so your exception filters still work.

  3. Connect frontend context

    Recommended

    To link server-side errors with client sessions and users, configure __add_tracing_headers in your frontend PostHog JS setup:

    JavaScript
    posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    __add_tracing_headers: ['your-nestjs-backend.com']
    })

    This automatically adds X-POSTHOG-SESSION-ID and X-POSTHOG-DISTINCT-ID headers to all fetch and XMLHttpRequest calls to the specified hostnames. The PostHogInterceptor reads these headers automatically to attach session and user context to captured exceptions.

  4. Manual exception capture (optional)

    Optional

    You can also manually capture exceptions anywhere in your NestJS application using captureException:

    app.controller.ts
    import { Controller, Post, Body } from '@nestjs/common'
    import { PostHog } from 'posthog-node'
    @Controller()
    export class AppController {
    constructor(private readonly posthog: PostHog) {}
    @Post('checkout')
    async checkout(@Body() body: any) {
    try {
    await processPayment(body)
    } catch (error) {
    this.posthog.captureException(error, 'user_distinct_id', {
    path: '/checkout',
    method: 'POST',
    })
    throw error
    }
    }
    }
  5. Verify error tracking

    Recommended

    Trigger a test exception to confirm events are being sent to PostHog. Add a test route to your controller:

    TypeScript
    @Get('debug-error')
    debugError() {
    throw new Error('Test exception from NestJS')
    }

    Visit /debug-error in your browser and check the activity feed for the $exception event.

Community questions

Was this page useful?

Questions about this page? or post a community question.