flowsk.com
Next.js guide

First-party attribution for Next.js

Next.js gives you middleware that runs on every request at the edge — the ideal place to mint a durable, server-set visitor id before a single byte of React ships. Most Next.js sites instead load a client-side tag in `app/layout.tsx` and inherit every ITP problem for free.

Quick answer

Durable id (server-set) + client events (behaviour) + server events (truth) + dedup key

Middleware sets the id cookie; a route handler proxies events; server actions confirm conversions. The one decision that matters on Next.js: who writes the visitor id. Written by JavaScript it lives 7 days in Safari; written by a server it lasts as long as you set it.

Use `middleware.ts` to mint the id, and a `app/api/events/route.ts` handler to forward events to the attribution API — that is proxy mode, and it is ITP-proof.

What Next.js gives you for free

Every stack has a natural advantage for first-party measurement. Use it before reaching for a tag manager.

Middleware runs before render, on your domain — perfect for a server-set HttpOnly cookie

Route handlers let you proxy events through your own origin, so nothing cross-origin is blocked

Server actions give you an authoritative place to confirm conversions

What breaks on Next.js

The failure modes specific to this stack — the ones a generic install guide will not warn you about.

Client-side navigation fires no pageview

The App Router changes routes without a document load, so a naive tag records only the first page.

Fix  Hook the router events, or use a tracker that patches history navigation.

Static generation caches the cookie

A statically generated page cannot set a per-visitor cookie.

Fix  Set it in middleware, which runs per request even for static pages.

Double-firing in React Strict Mode

Effects run twice in development, sending every event twice.

Fix  Guard on a module-level flag, and send a dedup key so duplicates collapse anyway.

Frequently asked questions

Where should I set the visitor cookie in Next.js?

In `middleware.ts`. It runs on every request before rendering, on your own domain, so the cookie goes out in an HTTP response header — durable in Safari, invisible to ad blockers.

How do I track App Router navigations?

Subscribe to route changes (`usePathname` + `useSearchParams` in a client component, or patch `history.pushState`) and emit a pageview on each change. A document-load-only tag will undercount badly.

Why proxy events through my own API route?

Because a POST to your own origin is not a cross-origin request, is not on any tracker blocklist, and cannot be blocked by third-party request filtering. You forward server-to-server from there.

Does this work with the Pages Router?

Yes. Use `middleware.ts` the same way and hook `router.events.on('routeChangeComplete')` for navigations.

See the receipt for every conversion.

Flowsk Signals stitches the anonymous click to the email to the purchase — first-party, server-side, de-duplicated on a key you choose. One snippet, $29/mo, and a journey you can inspect event by event.