Next.js
Next.js (App Router and Pages) + @millimetric/track. Covers RSC and edge.
Install
npm i @millimetric/track # browser
npm i @millimetric/track-node # server-sideApp Router — the recommended pattern
A tiny client component you mount in the root layout:
// app/_components/Analytics.tsx
"use client";
import { useEffect } from "react";
import { init } from "@millimetric/track";
export function Analytics() {
useEffect(() => {
init({
key: process.env.NEXT_PUBLIC_AOA_KEY!,
host: process.env.NEXT_PUBLIC_AOA_HOST ?? "https://api.millimetric.ai"
});
}, []);
return null;
}The SDK patches history.pushState, so App Router navigations auto-fire $pageview without any extra hook.
Identify after auth resolves
Mount once next to <Analytics />. With Clerk / Auth.js / Supabase Auth, replace useUser() with the appropriate hook.
Server-side events from a Route Handler
Use @millimetric/track-node with an sk_* key. Never put sk_* in a NEXT_PUBLIC_* env var — it'll ship to the browser bundle.
For long-running route handlers (rare in serverless), flushAt: 50 + a periodic flush() is fine.
Server Actions
Same pattern. Init the Node SDK once at module scope; call flush() before the action returns.
Edge Runtime
@millimetric/track-node works on the edge — it uses global fetch, no Node built-ins. Just set runtime:
Pages Router
(With Pages Router you do need to wire pageviews manually — next/router events don't go through history.pushState in the same way.)
Don't init in middleware / RSC
Middleware runs per-request — initialising the browser SDK there does nothing useful. RSC components run on the server — they don't have localStorage. Keep all SDK calls inside "use client" boundaries.
Env vars cheat-sheet
NEXT_PUBLIC_* ships to the browser. The plain AOA_SK does not — keep your secret keys naked, no prefix.
Last updated
Was this helpful?