PostHog
Send analytics events to PostHog for product analytics and session replay. Server-side tracking with full user identification support.
Nextlytics is a server-side analytics library for Next.js. No client JavaScript, no cookies, GDPR compliant. Learn more →
Configuration
import { Nextlytics } from "@nextlytics/core/server";
import { posthogBackend } from "@nextlytics/core/backends/posthog";
export const { middleware, analytics } = Nextlytics({
backends: [
posthogBackend({
// Required. Your PostHog project API key.
// Find it: PostHog -> Project Settings -> Project API Key
apiKey: process.env.POSTHOG_API_KEY!,
// Optional. PostHog host (default: "https://app.posthog.com")
// Use your own host if self-hosting PostHog
host: "https://app.posthog.com",
}),
],
});How It Works
The PostHog backend sends events directly to PostHog's HTTP API. No client-side JavaScript required. All events are captured server-side with full context.
Events are sent to PostHog's /capture/ endpoint with:
distinct_idfrom userId (if identified) or anonymousUserId- All event properties mapped to PostHog's expected format
- User traits sent via
$setfor identified users
Event Mapping
All Nextlytics events are sent to PostHog via HTTP POST:
| Nextlytics | PostHog |
|---|---|
pageView | event: "pageView" |
formSubmission | event: "formSubmission" |
| Custom events | event: "yourEvent" |
Properties Mapping
Server context:
| Nextlytics Property | PostHog Property |
|---|---|
serverContext.host + serverContext.path | $current_url |
serverContext.path | $pathname |
serverContext.host | $host |
serverContext.ip | $ip |
serverContext.method | http_method |
serverContext.collectedAt | server_collected_at |
serverContext.search | query_params |
serverContext.requestHeaders | request_headers |
serverContext.responseHeaders | response_headers |
Referrer and User-Agent (falls back to server request headers if client context unavailable):
| Nextlytics Property | PostHog Property |
|---|---|
clientContext.referer or serverContext.requestHeaders["referer"] | $referrer |
clientContext.userAgent or serverContext.requestHeaders["user-agent"] | $user_agent |
Client context:
| Nextlytics Property | PostHog Property |
|---|---|
clientContext.locale | $locale |
clientContext.path | client_path |
clientContext.collectedAt | client_collected_at |
clientContext.screen.width | $screen_width |
clientContext.screen.height | $screen_height |
clientContext.screen.innerWidth | $viewport_width |
clientContext.screen.innerHeight | $viewport_height |
clientContext.screen.density | $device_pixel_ratio |
Nextlytics metadata:
| Nextlytics Property | PostHog Property |
|---|---|
eventId | nextlytics_event_id |
parentEventId | nextlytics_parent_event_id |
collectedAt | nextlytics_collected_at |
User Identification
When a user is identified via callbacks.getUser, their userId becomes the distinct_id and
traits are sent via PostHog's $set mechanism:
export const { middleware, analytics } = Nextlytics({
callbacks: {
getUser: async (ctx) => {
const session = await getSession(ctx);
if (!session?.user) return undefined;
return {
userId: session.user.id,
traits: {
email: session.user.email,
plan: "pro",
},
};
},
},
backends: [posthogBackend({ apiKey: "..." })],
});For anonymous users, Nextlytics' anonymousUserId is used as the distinct_id.
Self-hosted PostHog
If you're self-hosting PostHog, specify your host:
posthogBackend({
apiKey: process.env.POSTHOG_API_KEY!,
host: "https://posthog.yourcompany.com",
});Custom Events
const { analytics } = await import("./nextlytics");
const api = await analytics();
await api.sendEvent("purchase", {
props: {
product: "Pro Plan",
value: 99.99,
currency: "USD",
},
});Limitations
- No event updates: PostHog doesn't support updating events after they're sent
- No session replay: Server-side tracking doesn't capture session recordings
Ready to add server-side analytics?
Get started with Nextlytics in 3 simple steps.