Cookieless analytics

Cookieless analytics for Next.js — no banner, one line of setup

Count your traffic without storing anything on a visitor's device. Marsad derives unique visitors from a daily-rotating hash on the server, so there is no cookie to disclose and no consent flow to build.

Why there's nothing to consent to

Analytics normally needs a consent banner for one reason: it stores an identifier on the visitor's device so it can recognise them later. That identifier is what turns a page view into personal data.

Marsad never stores one. When a view arrives, the ingest endpoint hashes the current day, the project id, the request IP and the user-agent together with a secret salt that never leaves the server, then keeps only that hash. The raw IP is used and dropped — it is never written to the event. Because the day is part of the input, the same person hashes to a different value tomorrow, so the ids can't be linked across days and can't be reversed.

The honest trade-off: unique visitors are a daily number. We can't tell you that Monday's visitor came back Thursday, because by design we no longer hold anything that connects them. What you get instead is a number you can publish without a legal review — and no banner in front of your own product.

Setup, in full

Page views are captured automatically in the browser — on load and on every App Router navigation. There is no analytics-specific code and no separate script tag.

instrumentation.ts (server)ts
export { register, onRequestError } from "@marsadco/sdk/nextjs";
app/marsad-init.tsx (client, mounted once in app/layout.tsx)tsx
"use client";
import { useEffect } from "react";
import { initBrowser } from "@marsadco/sdk/nextjs";

export function MarsadInit() {
  useEffect(() => initBrowser(), []);
  return null;
}

That's the whole integration. It reads NEXT_PUBLIC_MARSAD_KEY from your environment, and the same call also starts error, network and Web Vitals capture.

What you get

  • Page views and unique visitors over time, with the path only — never the query string, so tokens and emails in URLs can't leak into analytics.
  • Top pages, top referrers, and UTM campaigns parsed and grouped (source, medium, campaign, term, content).
  • Devices, browsers, operating systems and countries, bucketed server-side from the user-agent. Country only — no city, no coordinates.
  • Live visitors in the last few minutes.
  • Core Web Vitals — LCP, CLS, INP, FCP, TTFB — broken out per page, so a bad score points at the route that owns it.
  • Custom events via track("signup", { plan }) when you want product analytics next to your traffic.

It's the same SDK as your error tracking

This is the part a standalone analytics script can't do. Because your traffic and your exceptions arrive through one pipeline, a drop in conversions and a spike in errors on the same route are one screen, not two tabs and a guess. Errors are grouped into ranked issues with source-mapped stack traces; traces show the requests behind a slow page; Web Vitals attach to the routes you already care about.

The same package covers Expo and React Native — see Expo error tracking.

Pricing

The free plan includes 10,000 page views and 5,000 errors a month with no credit card. Paid plans are flat and per-organization — never per seat — starting at $9/mo for 100,000 page views and unlimited projects. Go over and you get a grace period with reminders, never a surprise charge. Full detail on pricing.

Start watching your apps in minutes

Drop in the SDK and watch your first page views and errors arrive. Free plan, no credit card, no cookie banner.