Subchapter 49.9
references/nextjs.mdMarkdown6 KBView on GitHub
Required
Terminal
PostHog AI
npm install @opentelemetry/sdk-logs @opentelemetry/exporter-logs-otlp-http @opentelemetry/api-logs @opentelemetry/resources2
Required
You’ll need your PostHog project token to authenticate log requests. This is the same key you use for capturing events and exceptions with the PostHog SDK.
Important: Use your project token which starts with
phc_. Do not use a personal API key (which starts withphx_).
You can find your project token in Project Settings (opens in a new tab).
3
Required
Note: For Next.js 15 and later, the instrumentation hook is enabled by default. You can skip this step if you’re on Next.js 15+.
Add the following to your next.config.js (or next.config.mjs) to enable the instrumentation hook:
JavaScript
PostHog AI
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
instrumentationHook: true,
},
}
module.exports = nextConfig4
Required
Create an instrumentation.ts (or instrumentation.js) file in the root of your project (or inside src/ if you use that folder).
typescript
PostHog AI
import { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs'
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'
import { logs } from '@opentelemetry/api-logs'
import { resourceFromAttributes } from '@opentelemetry/resources'
// Create LoggerProvider outside register() so it can be exported and flushed in route handlers
export const loggerProvider = new LoggerProvider({
resource: resourceFromAttributes({ 'service.name': 'my-nextjs-app' }),
processors: [
new BatchLogRecordProcessor(
new OTLPLogExporter({
url: 'https://us.i.posthog.com/i/v1/logs',
headers: {
Authorization: 'Bearer <ph_project_token>',
'Content-Type': 'application/json',
},
})
),
],
})
export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
logs.setGlobalLoggerProvider(loggerProvider)
}
}Note: The
loggerProvideris created outside ofregister()so it can be exported and used to flush logs in route handlers. This pattern is necessary because Route Handlers complete execution before batched logs have a chance to be sent to the collector. By exporting the provider, we can manually flush logs at the end of each request.
Important: The
Content-Type: application/jsonheader is required.
Alternatively, you can pass the API key as a query parameter:
typescript
PostHog AI
new OTLPLogExporter({
url: 'https://us.i.posthog.com/i/v1/logs?token=<ph_project_token>',
headers: {
'Content-Type': 'application/json',
},
})5
Required
Now you can use OpenTelemetry logging in your server-side code (API routes, Server Components, etc.):
typescript
PostHog AI
import { SeverityNumber } from '@opentelemetry/api-logs'
import { after } from 'next/server'
import { loggerProvider } from '@/instrumentation'
const logger = loggerProvider.getLogger('my-nextjs-app')
export async function GET() {
logger.emit({
body: 'API request received',
severityNumber: SeverityNumber.INFO,
attributes: {
endpoint: '/api/example',
method: 'GET',
},
})
// Ensure logs are flushed before the serverless function freezes
after(async () => {
await loggerProvider.forceFlush()
})
return Response.json({ success: true })
}Important: Without calling
forceFlush(), your logs may not be sent. Route Handlers complete execution before the OpenTelemetry batch processor has a chance to send logs to the collector. Theafter()function fromnext/serverruns code after the response is sent, ensuring logs are flushed before the serverless function freezes.
6
Recommended
Once everything is configured, test that logs are flowing into PostHog:
Checkpoint
What you can do with your logs
| Action | Description |
|---|---|
| Why you need logs (opens in a new tab) | What logs show you that nothing else does |
| Search logs (opens in a new tab) | Use the search interface to find specific log entries |
| Filter by level | Filter by INFO, WARN, ERROR, etc. |
| Link session replay (opens in a new tab) | Connect logs to users and session replays by passing posthogDistinctId and sessionId |
| Link logs to a person (opens in a new tab) | Surface every log emitted on behalf of a user on their PostHog person profile |
| Logging best practices (opens in a new tab) | Learn what to log, how to structure logs, and patterns that make logs useful in production |
Ask a question
HelpfulCould be better