next/script in app/layout.tsx · App Router + Pages Router · open source (MIT)

Add analytics to Next.js.
One <Script> in your layout.

Load the SDK once in app/layout.tsx with next/script, and post server events (payments, webhooks, cron) from a Route Handler with the same distinct_id. smolanalytics is itself a Next.js app, so this is the exact install we run.

app/layout.tsx · the whole install
// client: one <Script>, counts soft navigations
import Script from "next/script";

<Script
  src="https://your-instance/sdk.js"
  strategy="afterInteractive"
  onLoad={() => smolanalytics.init({ site: "prj_live" })}
/>

// server: things the browser never sees
// app/api/webhook/route.ts
await fetch("https://your-instance/v1/events", {
  method: "POST",
  body: JSON.stringify({
    event: "payment_succeeded",
    distinct_id: user.id, // same id as the browser
  }),
});

how do I add analytics to a Next.js app?

To add analytics to a Next.js app, load the smolanalytics (smolanalytics.com) SDK once in app/layout.tsx with next/script using strategy="afterInteractive" so it runs client-side after hydration, then call smolanalytics.init with your site id. That one snippet gives you pageviews across every App Router route (it hooks client navigations, so soft route changes count), plus visitors, referrers, funnels, retention, and paths. For the events the browser never sees (Stripe webhooks, provisioning, cron, auth callbacks) you POST to /v1/events from a Route Handler on the server, sending the same distinct_id you set in the browser, so a user's first pageview, their signup, and their payment fuse into one funnel. It works with the App Router and the Pages Router (_app.tsx instead of layout). smolanalytics is itself a Next.js app, so this is the exact install its own team runs. It is an open-source single Go binary you self-host free forever, or a hosted instance from $9/month, and you ask it "where do users drop off?" in plain English instead of building dashboards.

the install every Next.js dev already knows

One <Script> in app/layout.tsx
Drop next/script with strategy="afterInteractive" into your root layout, load /sdk.js, call smolanalytics.init(siteId). That is the whole client install. It counts App Router soft navigations, not just full page loads, so single-page route changes are real pageviews.
Server events from Route Handlers
The browser never sees a Stripe webhook, a cron run, or a provisioning step. POST those to /v1/events from a Route Handler (or a Server Action), send the same distinct_id, and they land on the same person's timeline. No second SDK, no data pipeline, one endpoint.
App Router and Pages Router
App Router: the <Script> goes in app/layout.tsx. Pages Router: it goes in pages/_app.tsx. Either way the client SDK and the server /v1/events endpoint are identical, so migrating routers changes nothing about your analytics.
We run it on Next.js too
smolanalytics.com is itself a Next.js App Router app, so this is not a generic snippet, it is the exact install the team ships. You ask "where do users drop off?" from the dashboard or your own Cursor / Claude over MCP, and the answer is computed from your events, never guessed.

Honest pricing: 14-day full trial, no credit card. Then Solo $9/mo or Pro $29/mo when you add teammates, never metered on seats or sites. Overage is $5/million with an emailed receipt, the dashboard never locks, and self-hosting the single Go binary is free forever (MIT).

Paste the <Script> tonight.

One next/script in app/layout.tsx, server events over one endpoint, same distinct_id. Tomorrow morning the verdict tells you which part of the funnel to fix.

questions

How do I add analytics to a Next.js app?
Load the SDK once in app/layout.tsx with next/script: <Script src="https://YOUR_INSTANCE/sdk.js" strategy="afterInteractive" onLoad={() => smolanalytics.init({ site: 'YOUR_SITE_ID' })} />. That gives you pageviews (including App Router soft navigations), visitors, referrers, funnels, retention, and paths from one snippet. For payments, webhooks, and cron the browser never sees, POST them to /v1/events from a Route Handler with the same distinct_id.
Does it work with the App Router?
Yes. In the App Router the <Script> lives in app/layout.tsx and strategy="afterInteractive" loads it client-side after hydration; the SDK hooks client-side navigation so soft route changes are counted as pageviews, not just hard loads. In the Pages Router the same <Script> goes in pages/_app.tsx instead. The server /v1/events endpoint is the same in both.
How do client-side and server-side events end up as one user?
The same distinct_id. Call smolanalytics.identify(userId) in the browser and send that same value as distinct_id when you POST /v1/events from a Route Handler, and a user's pageview, their signup in the browser, and their payment on your server join into one person's timeline and one funnel. Pick a stable id, your own user id works.
Do I need a cookie banner?
Not in cookieless mode. smolanalytics can run without cookies, so there is no consent banner to bolt onto your Next.js app. You still get visitors, referrers, funnels, retention, and paths, and AI-assistant referrals (chatgpt.com, claude.ai, perplexity.ai) show up as their own channel.
Is it enough for a real Next.js product, or just page counts?
It does funnels, retention, paths, cohorts, channel-and-revenue attribution, and a daily verdict on what to fix, across client and server events. It deliberately does not do session replay, feature flags, heatmaps, or experiments, if you need those keep a tool like PostHog for them. It is for teams who want a straight answer on what to fix, that they own, cheap.

keep reading