Fastify
Contents
Use the PostHog Node.js SDK to capture events and request errors from your Fastify app.
Installation
Install the SDK in your Fastify app:
This guide uses Fastify 5 and posthog-node 5.52.1 on Node.js. Get your project token and API host from your project settings.
Set up PostHog
Create one PostHog client for your app. Register the hooks and error handler in the same Fastify scope as your routes, before those routes.
Process-level enableExceptionAutocapture does not capture errors that Fastify handles. Use setErrorHandler to capture these errors.
Request context and identity
Keep onRequest callback-based, not async. Calling done inside withContext continues the request in that context. { fresh: true } prevents inheritance from an outer context.
request.user belongs to your application. It is not a built-in Fastify identity. Populate it with a verified user and a string id in an earlier authentication hook. Without authentication, this example captures exceptions without creating person profiles.
If authentication runs later, pass the verified ID directly to captureException instead of undefined.
Do not use x-posthog-distinct-id as proof of identity. Tracing headers are client-controlled analytics values, and this example does not read them. To link Session Replay, you can explicitly add a validated sessionId to the context. Never use it for authorization.
Trace context
This optional setup requires the Node SDK release with posthog-node/otel and ContextOptions.signal. The base SDK version stated above does not include these APIs.
To add browser session and person IDs to application spans, register the optional Node context processor on your existing OpenTelemetry provider before requests start. Reuse the posthog client above and keep the existing exporter and sampler.
Configure tracing_headers for your backend hostname in the browser SDK. Replace the earlier onRequest hook with this Node.js setup:
Keep this hook after authentication and before routes, in the same Fastify scope. The helper adds missing sessionId and posthogDistinctId attributes to an active request span. The processor adds them to child spans when they start. Explicit canonical attributes take precedence; missing IDs stay absent.
The signal ends context when the response finishes, closes, or the request is aborted. Do not abort when done() returns: the handler can still be running. Existing spans keep their IDs; new spans in detached work after expiry omit them. Background jobs need their own explicit context. Keep your existing error and shutdown handlers.
Capture events
Add this route before app.listen() to capture an event for an authenticated request. The event inherits the verified identity and request properties from withContext.
See the Node.js capture documentation for more event options.
Error handling
The HTTP status filter is optional application logic, not an SDK default. Remove the if condition to capture handled 4xx errors too. Unknown-route 404 responses do not pass through setErrorHandler.
If you already have an error handler, add the capture call there instead of replacing your response behavior. Avoid capturing the same error again in another hook.
The example records the route pattern, not the raw URL. This avoids collecting query strings or path parameter values. Review error messages and other properties for sensitive data before capture.
Fastify's default error response includes the error message. Use your application's response policy to hide internal details.
Shutdown
During graceful termination, call await app.close() from your application's shutdown handler. Fastify then runs onClose, which waits for PostHog to drain buffered events.
Do not call shutdown() per request. Do not exit the process before it finishes. Abrupt termination can lose queued events.
Next steps
See the Node.js SDK documentation for Feature Flags, group analytics, and other SDK features.











