For the complete documentation index, see llms.txt. This page is also available as Markdown.

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-side

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?