Next.js Native Open-Source Analytics
100% server-side. No client JavaScript. No cookies. No GDPR banners.
Just accurate analytics that respect your users.
Website · Integrations · Demo
Nextlytics is a server-side analytics library for Next.js. It tracks page views automatically via middleware and lets you send custom events from server components, server actions, and API routes.
There's no client-side JavaScript involved. Events go directly from your server to your analytics backend. This means no ad blockers, no cookies, and accurate data.
It works with multiple backends — Segment, PostHog, Google Analytics, or you can write directly to a database like ClickHouse or Postgres.
npm install @nextlytics/core1. Configure your backend (src/nextlytics.ts)
import{Nextlytics}from"@nextlytics/core/server";import{segmentBackend}from"@nextlytics/core/backends/segment";// Nextlytics runs in Next.js middleware (Edge runtime), so it can't import// your main auth.ts if it pulls in Prisma, nodemailer, or other Node.js deps.// Instead, create a lightweight auth instance from your edge-safe base config.// See: https://authjs.dev/guides/edge-compatibilityimportNextAuthfrom"next-auth";importauthConfigfrom"./auth.config";const{ auth }=NextAuth(authConfig);exportconst{ middleware, analytics }=Nextlytics({backends: [segmentBackend({writeKey: process.env.SEGMENT_WRITE_KEY!,}),],// Optional but recommended: identify authenticated userscallbacks: {asyncgetUser(){constsession=awaitauth();if(!session?.user)returnnull;return{userId: session.user.id,traits: {email: session.user.email,name: session.user.name},};},},});2. Add to layout (src/app/layout.tsx)
import{NextlyticsServer}from"@nextlytics/core/server";exportdefaultfunctionRootLayout({ children }){return(<htmllang="en"><body><NextlyticsServer>{children}</NextlyticsServer></body></html>);}3. Export middleware (src/middleware.ts)
import{middleware}from"./nextlytics";export{middleware};That's it. Every page view is now tracked server-side.
Use analytics().sendEvent() to emit your own events from the server.
In the App Router (server components, server actions, route handlers) call it with no argument — the
request context is read from next/headers:
import{analytics}from"@/nextlytics";exportasyncfunctionsignUp(formData: FormData){"use server";// ...create the user...await(awaitanalytics()).sendEvent("signup",{props: {plan: "pro"}});}In Pages Router API routesnext/headers is unavailable, so pass the request object:
importtype{NextApiRequest,NextApiResponse}from"next";import{analytics}from"@/nextlytics";exportdefaultasyncfunctionhandler(req: NextApiRequest,res: NextApiResponse){await(awaitanalytics(req)).sendEvent("email_opened",{props: {campaign: "welcome"}});res.status(200).end();}This also works for standalone routes with no preceding page render (e.g. email pixels or redirect endpoints) — the event is sent without a parent page-view. A NextRequest (App Router route handler) may be passed the same way.
Nextlytics also supports the Pages Router. The middleware works the same way, but instead of
NextlyticsServer, use getNextlyticsProps in your _app.tsx:
1. Configure your backend (same as App Router - see above)
2. Add to _app.tsx (pages/_app.tsx)
importtype{AppContext,AppProps}from"next/app";import{NextlyticsClient,getNextlyticsProps,typeNextlyticsContext}from"@nextlytics/core";typeMyAppProps=AppProps&{nextlyticsCtx: NextlyticsContext};functionMyApp({ Component, pageProps, nextlyticsCtx }: MyAppProps){return(<NextlyticsClientctx={nextlyticsCtx}><Component{...pageProps}/></NextlyticsClient>);}MyApp.getInitialProps=async(appContext: AppContext)=>{return{pageProps: appContext.Component.getInitialProps
? awaitappContext.Component.getInitialProps(appContext.ctx)
: {},nextlyticsCtx: getNextlyticsProps(appContext.ctx),};};exportdefaultMyApp;3. Export middleware (same as App Router)
| Backend | Type |
|---|---|
| Segment or Jitsu | CDP |
| PostHog | Product Analytics |
| Google Analytics | Web Analytics |
| ClickHouse | Database |
| Neon / Supabase | Database |
MIT