How to Integrate PostHog Analytics with Your Next.js App

Learn how to seamlessly integrate PostHog analytics into your Next.js application with a production-ready setup. This step-by-step guide covers everything from initializing PostHog only in production, identifying authenticated users, manually tracking pageviews, and bypassing ad blockers—ensuring accurate, privacy-friendly insights without compromising performance. Perfect for developers looking to supercharge their product analytics with open-source tools.

Vanshika Sharma

24 days ago

how-to-integrate-posthog-analytics-with-your-next-js-app

If you're building with Next.js and want deep, actionable insights into how users interact with your app — PostHog is a game changer.

PostHog is an open-source analytics platform that helps teams track events, monitor user behavior, and make data-driven product decisions. And the best part? It works beautifully with modern frameworks like Next.js — including support for client-side navigation.

In this post, I’ll show you how to set up a production-ready PostHog integration in your Next.js project. We’ll cover:

  • Initializing PostHog (only in production)

  • Setting up a PostHog Provider

  • Identifying logged-in users

  • Manually tracking pageviews

  • Avoiding ad blockers with proxy rewrites

Step 1: Install the Dependencies

First, add the necessary packages:

bash

CopyEdit

npm install posthog-js @posthog/react # or with pnpm pnpm add posthog-js @posthog/react

Step 2: Create a PostHog Provider Component

We’ll create a custom provider to initialize PostHog and wrap our app in context. This ensures PostHog runs only in production and allows us to track data globally.

tsx

CopyEdit

// src/app/_providers/posthogProvider.tsx "use client"; import { useEffect, Suspense } from "react"; import { PostHogProvider as PHProvider, usePostHog } from "posthog-js/react"; import posthog from "posthog-js"; import { useSession } from "next-auth/react"; import { usePathname, useSearchParams } from "next/navigation"; export function PostHogProvider({ children }: { children: React.ReactNode }) { useEffect(() => { if (process.env.NODE_ENV !== "development") { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY as string, { api_host: ${process.env.NEXT_PUBLIC_BASE_URL}/ingest, ui_host: "https://us.posthog.com", capture_pageview: false, // We'll handle this manually }); } }, []); if (process.env.NODE_ENV === "development") { return <>{children}</>; } return ( <PHProvider client={posthog}> <SuspendedPostHogPageView /> {children} </PHProvider> ); }

Step 3: Identify Authenticated Users

We’ll use next-auth (or your preferred auth method) to tie events to real users using PostHog’s identify method.

tsx

CopyEdit

function PostHogPageView() { const posthog = usePostHog(); const { data: session } = useSession(); useEffect(() => { if (session?.user.id) { posthog.identify(session.user.id, { email: session.user.email, }); } else { posthog.reset(); } }, [posthog, session?.user]); }

Step 4: Manually Track Pageviews

Since Next.js uses client-side navigation, automatic pageview tracking won’t work. Let’s handle it manually:

tsx

CopyEdit

function PostHogPageView() { const posthog = usePostHog(); const pathname = usePathname(); const searchParams = useSearchParams(); useEffect(() => { if (pathname && posthog) { let url = window.origin + pathname; if (searchParams.toString()) { url += "?" + searchParams.toString(); } posthog.capture("$pageview", { $current_url: url }); } }, [pathname, searchParams, posthog]); return null; }

Step 5: Use Suspense for Better Performance

To avoid degrading your app's SSR performance, wrap the tracker in a Suspense component.

tsx

CopyEdit

function SuspendedPostHogPageView() { return ( <Suspense fallback={null}> <PostHogPageView /> </Suspense> ); }

Step 6: Wrap Your App in the Provider

Include the PostHogProvider in your root layout so it's accessible across your app.

tsx

CopyEdit

// src/app/layout.tsx import { PostHogProvider } from "./_providers/posthogProvider"; export default function RootLayout({ children }: { children: React.ReactNode }) { return <PostHogProvider>{children}</PostHogProvider>; }

Step 7: Add Environment Variables

Make sure to include your PostHog keys in your .env file:

env

CopyEdit

NEXT_PUBLIC_POSTHOG_KEY=phc_xxx_your_key NEXT_PUBLIC_BASE_URL=https://yourdomain.com

Step 8: Proxy PostHog Requests to Bypass Ad Blockers

Many users have ad blockers that block analytics domains. By proxying requests through your own domain, you reduce this risk.

Add the following to next.config.mjs:

js

CopyEdit

async rewrites() { return [ { source: "/ingest/static/:path*", destination: "https://us-assets.i.posthog.com/static/:path*", }, { source: "/ingest/:path*", destination: "https://us.i.posthog.com/:path*", }, ]; }

Final Thoughts

With this setup, you now have a clean, production-ready PostHog integration in your Next.js app:

  • Analytics only run in production

  • Logged-in users are identified

  • Pageviews are manually tracked on client-side routes

  • SSR remains optimized

This is just the beginning — you can build on this to track custom events, A/B tests, funnel analysis, and much more.

Happy tracking!