Next.js web analytics setup
Use the generated Next.js component and server Route Handler when you want the browser to send analytics to your own domain before the request is forwarded to Gumanalytics.
Generate the Next.js setup
- Open the project in Gumanalytics and choose Settings.
- Enable session replay or heatmaps if you want to collect them.
- In Setup, choose the Next.js tab.
- Copy the generated client component and Route Handler into the displayed paths.
- Render the Gumanalytics component once from your root layout.
Add the client component
import Script from "next/script";
export function Gumanalytics() {
return (
<Script
id="gumanalytics"
strategy="afterInteractive"
src="https://gumanalytics.com/js/analytics.js?v=be9add48f624"
data-domain="example.com"
data-endpoint="/api/gumanalytics/watch"
data-replay-endpoint="/api/gumanalytics/replay"
data-heatmap-endpoint="/api/gumanalytics/heatmap"
data-latency-endpoint="https://gumanalytics.com/api/ping"
/>
);
}The Setup panel adds replay, heatmap, and sampling attributes when those capture features are enabled. Keep the generated values aligned with the project settings.
Add the server Route Handler
import { NextRequest, NextResponse } from "next/server";
const ALLOWED_ROUTES = new Set(["watch", "replay", "heatmap"]);
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ route: string }> },
) {
const { route } = await params;
if (!ALLOWED_ROUTES.has(route)) {
return NextResponse.json({ error: "Not found" }, { status: 404 });
}
const headers = new Headers({ "content-type": "application/json" });
const forwardedFor =
request.headers.get("x-forwarded-for") ||
request.headers.get("x-real-ip");
if (forwardedFor) {
headers.set("x-forwarded-for", forwardedFor.split(",")[0].trim());
}
const userAgent = request.headers.get("user-agent");
const country =
request.headers.get("cf-ipcountry") ||
request.headers.get("x-vercel-ip-country");
const city =
request.headers.get("cf-ipcity") ||
request.headers.get("x-vercel-ip-city");
if (userAgent) headers.set("user-agent", userAgent);
if (country) headers.set("cf-ipcountry", country);
if (city) headers.set("cf-ipcity", city);
const response = await fetch(
"https://gumanalytics.com/api/" + route,
{
method: "POST",
headers,
body: await request.text(),
cache: "no-store",
},
);
return new NextResponse(null, {
status: response.ok ? 204 : response.status,
});
}Why use a same-origin analytics proxy?
A same-origin endpoint reduces browser blocking of requests sent directly to an external analytics API. It does not guarantee collection when a browser blocks the analytics script itself, JavaScript, or all measurement requests.