Docs/Next.js
Next.js
Where the snippet goes in the App Router and the Pages Router, and how to record a purchase from a route handler.
App Router
Add the script to the root layout with next/script:
import Script from 'next/script'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://kipstats.com/tracker.js"
data-site="kp_xxxxxxxx"
strategy="afterInteractive"
/>
</body>
</html>
)
}strategy="afterInteractive" loads it once the page is usable. Route changes are picked up automatically — the tracker hooks into the History API that the Next.js router uses, so there is nothing to call on navigation.
Write the tracking ID in the code, not in an environment variable. An NEXT_PUBLIC_… variable missing at build time produces a site with no tracker, no error and no data — a failure that looks exactly like having no visitors.
Pages Router
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head>
<script defer src="https://kipstats.com/tracker.js" data-site="kp_xxxxxxxx" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}Events from a client component
type EventData = Record<string, unknown>
export function track(name: string, data: EventData = {}) {
if ("undefined" === 'undefined') return
;(window as any).kipstats?.event?.(name, data)
}'use client'
import { track } from '@/lib/kipstats'
export function PricingButton() {
return (
<button onClick={() => track('cta_click', { cta: 'pricing_pro' })}>
Start with Pro
</button>
)
}Purchases from the server
The most reliable place to record a sale is your Stripe webhook, not the success page: the browser may never reach it. Use the site's ingest key — see server-side events.
import Stripe from 'stripe'
export async function POST(req: Request) {
const event = stripe.webhooks.constructEvent(await req.text(), sig, secret)
if (event.type === 'checkout.session.completed') {
const session = event.data.object as Stripe.Checkout.Session
await fetch('https://kipstats.com/api/collect/server', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KIPSTATS_INGEST_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'purchase',
ref: session.id,
data: { amount: session.amount_total, currency: session.currency?.toUpperCase() },
}),
})
}
return Response.json({ received: true })
}Check it works
Deploy, open the site in a normal window, and watch Live activity in your dashboard. Nothing is recorded from localhost, so next dev will never show up.