@posthog/next
v0.1.0
Published
PostHog integration for Next.js
Downloads
540
Readme
@posthog/next
The official PostHog integration for Next.js. Provides analytics, feature flags, and event capture across the App Router (React Server Components), Pages Router, and middleware — with a single unified package.
Features
- App Router support with a server-component
PostHogProviderthat bootstraps feature flags via SSR - Pages Router support via
PostHogProvider,PostHogPageView, andgetServerSidePostHog - Middleware for identity cookie seeding and optional API proxying
- Server-side feature flags via
getPostHog()in server components and route handlers - Automatic pageview tracking with the
PostHogPageViewcomponent - Consent-aware — all server-side code respects the user's opt-in/opt-out preference
- Static-safe by default — the provider does not call dynamic APIs unless you enable
bootstrapFlags
Install
npm install @posthog/next
# or
pnpm add @posthog/next
# or
yarn add @posthog/nextPeer dependencies: next >= 13.0.0, react >= 18.0.0, react-dom >= 18.0.0
Quick Start (App Router)
1. Set environment variables
NEXT_PUBLIC_POSTHOG_KEY=phc_your_key_here
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com # optional2. Add middleware
// middleware.ts
import { postHogMiddleware } from '@posthog/next'
export default postHogMiddleware({ proxy: true })
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}3. Wrap your layout
// app/layout.tsx
import { PostHogProvider, PostHogPageView } from '@posthog/next'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<PostHogProvider clientOptions={{ api_host: '/ingest' }} bootstrapFlags>
<PostHogPageView />
{children}
</PostHogProvider>
</body>
</html>
)
}4. Use PostHog
// In a client component
'use client'
import { usePostHog, useFeatureFlag } from '@posthog/next'
export function MyComponent() {
const posthog = usePostHog()
const showNewUI = useFeatureFlag('new-ui')
return <button onClick={() => posthog.capture('clicked')}>Click me</button>
}// In a server component
import { getPostHog } from '@posthog/next'
export default async function Page() {
const posthog = await getPostHog()
const flags = await posthog.getAllFlags()
posthog.capture({ event: 'page_viewed' })
// ...
}For detailed usage including Pages Router, consent management, middleware composition, and all API options, see USAGE.md.
Entry Points
| Import path | Environment | Purpose |
| --------------------- | --------------- | ---------------------------------------------------------------------------------- |
| @posthog/next | Client + Server | PostHogProvider, PostHogPageView, hooks, getPostHog(), postHogMiddleware() |
| @posthog/next/pages | Client + Server | PostHogProvider, PostHogPageView, getServerSidePostHog() for Pages Router |
Environment Variables
| Variable | Required | Description |
| -------------------------- | --------------------------- | ------------------------------------------------------------ |
| NEXT_PUBLIC_POSTHOG_KEY | Yes (unless passed as prop) | Your PostHog project API key (phc_...) |
| NEXT_PUBLIC_POSTHOG_HOST | No | Custom PostHog host (defaults to https://us.i.posthog.com) |
How It Works
Middleware runs on every request and seeds an identity cookie (
ph_<key>_posthog) with a UUIDv7 anonymous ID if none exists. It optionally proxies SDK API calls through your domain.PostHogProvider (a React Server Component) reads that cookie. When
bootstrapFlagsis enabled, it evaluates feature flags server-side viaposthog-nodeand passes the results to the client as bootstrap data — so hooks return real values immediately without a network round-trip.Client components use
posthog-jsunder the hood. The SDK is initialized eagerly during render (not in auseEffect) so that child components and hooks can access a fully configured instance immediately.Server utilities (
getPostHog()) read the same identity cookie and scope theposthog-nodeclient per request viaenterContext(), so events and flag evaluations are attributed to the correct user.Consent is checked at every layer. If the user has opted out (via the consent cookie), the middleware skips cookie seeding, the provider skips flag evaluation, and
getPostHog()skips context setup.
