Skip to main content
This page builds a Next.js App Router app with two packages. Grain Tag (@grainql/tag) runs in the browser for page views, clicks, heatmaps, and the user ID. Analytics Web (@grainql/analytics-web) runs on the server with the SERVER_SIDE strategy. Each block names its package. For the Pages Router, read Next.js.

Environment variables

Put these in .env.local. Next.js sends every NEXT_PUBLIC_ variable to the browser. The secret key has no prefix, so it stays on the server.
Do not put the secret key in a NEXT_PUBLIC_ variable. Anyone who opens the site can read it.

Grain Tag in the root layout

Grain Tag runs in the browser. A Client Component calls init one time. init returns a no-op stub outside a browser, so the import is safe in a server render.

Route changes

Grain Tag (@grainql/tag) tracks the first page view and every App Router navigation. The App Router navigates through the History API, so a route change needs no component. If you set enablePageViews: false in init and track page views yourself, read the path from usePathname.

Identify with NextAuth

Grain Tag (@grainql/tag) attaches the user ID to every later event after identify. Read the session from NextAuth and call identify when it holds a user. Grain Tag has no method that clears the user ID.
identify called before init is queued and replayed after initialization. Read Identify users.

A client event

Call track from a Client Component.

A server-side event

A route handler uses Analytics Web (@grainql/analytics-web) with the SERVER_SIDE strategy and the secret key. Create the client one time at module scope. The { flush: true } option sends the event before the function returns. Without it, a serverless function can stop before the batch timer fires, and the event is lost. The userId field of the event object attaches the event to the user who placed the order.
auth is the NextAuth helper of your app. Read Node.js and servers and Authentication.