Skip to content
Chapter 93Lesson 1

The cookieless analytics floor

Ship Vercel Web Analytics and Speed Insights as the cookieless, no-consent baseline that answers traffic and real-user performance before you reach for a product-analytics platform.

Your product is live on Vercel: the marketing site and the app are both serving real traffic. Three questions are now due, and you can’t answer any of them yet.

How much traffic is the app getting, and from where? Which pages turn visitors into sign-ups, and which quietly lose them? Is the experience fast enough that Google’s ranking and your conversion rate aren’t punished for it? Answering these takes no event schema and no product-analytics platform: just two installs, @vercel/analytics and @vercel/speed-insights, and two lines of JSX in a file you already have. By the end of this lesson all three are answered in a dashboard, with no event code written.

You already have what this builds on: a Next.js App Router app on Vercel, an app/layout.tsx at the root, and the consent gate from the security chapter that holds non-essential tracking behind an explicit yes. That gate matters here, but not in the way your instinct expects, and correcting that instinct is the most important thing this lesson does.

Three questions the floor answers, five it can’t

Section titled “Three questions the floor answers, five it can’t”

Every team running a web app asks these three from the first day of production onward:

  • Traffic. How many people, and from where? Volume and referrers tell you whether your launch tweet did anything and whether that blog post is sending real humans.
  • Behavior, lightly. Which pages do people land on, and which do they leave from? You don’t need a funnel to notice that the pricing page gets traffic but the sign-up that should follow it doesn’t.
  • Performance. Is the page fast for real users on real devices? Not fast on your laptop, but fast on a mid-range phone over hotel wifi, which is what Google scores you on.

Two installs answer all three. That’s the floor: the analytics layer that’s correct to ship before you’ve decided anything else, because it costs nothing and answers questions you have today.

A web app’s analytics stack has two tiers, and this lesson ships the bottom one.

Two tiers. The floor ships on every project; the top tier is an optional layer you add only when a real need calls for it.

The bottom tier, the cookieless floor, ships on every Vercel project with no conditions. The top tier is PostHog , and it has a trigger: you add it only when one of exactly five questions becomes real. You cross the threshold the moment you need to know:

  • Who. A specific identified user, not an anonymous visitor.
  • What they did. An event with properties (plan: 'pro', seats: 12), not just a page view.
  • Across sessions. A funnel that stitches a sign-up today to a paid invoice next week.
  • Gated by a flag. Rolling a new feature out to 10% of orgs first.
  • In replay. Watching the actual session where a user rage-clicked and left.

Until one of these is a real, present need, the floor is your entire analytics stack. Notice that none of them is “how much traffic do I get.” That’s the floor’s job, and it does it for free.

Most tools in this course are conditional: you reach for them only once a threshold is crossed. The floor is the inverse. You ship it on every project by reflex, the way you add a favicon, for three reasons.

It’s cookieless. Vercel Web Analytics sets no cookies, so it runs for every visitor without a consent prompt. That’s most of its value, and its own section below works through the legal shape of it.

It’s free on every plan, including Hobby. The only cost is a cap on captured events, generous enough that a pre-PMF app stays inside it. That’s a volume cost, not an engineering one: there’s no event schema to design and budget for.

It’s zero-effort. The whole install is two <script> injections from two official packages, and the data model is fixed (page views, referrers, geography, device). No schema to design, keep aligned across the codebase, or watch rot when someone renames a thing and forgets the analytics call.

Contrast the top tier. PostHog is powerful, but everything it gives you is weight: an SDK in your bundle, an event schema to govern, a consent gate to route every call through, a quota to watch. That’s the right cost to pay once a real need shows up, but it is a cost, and the floor has none of it.

Web Analytics gives you a focused set of traffic metrics:

  • Page views and unique visitors: your volume.
  • Top pages and top referrers: what’s getting attention and what’s sending it.
  • Country, OS, browser, and device class: the shape of your audience.

Each of these is aggregated and anonymized at the point of ingest, so no personal data leaves the visitor’s device. The script also discovers its ingest endpoints at runtime instead of hard-coding one, which is how it keeps reporting through the URL patterns ad-blockers target.

The Web Analytics overview — visitors, page views, and top pages. This is what 'verified' looks like once the floor is wired.

Web Analytics does support custom events, but treat them as out of scope: the data model around them is shallow (no funnels, no cohorts, no cross-session identity), and they are a Pro and Enterprise feature, absent from the free Hobby tier. Wanting to fire a custom event is not a signal to upgrade your Vercel plan; it’s the signal to reach for PostHog.

The second install, @vercel/speed-insights, answers the third question: is the page fast for real people? It samples Core Web Vitals from your live production traffic. You’ll see five named on the dashboard, so meet them as vocabulary now: LCP, INP, CLS, TTFB, and FCP. The performance chapter later defines each one and how to fix it.

The idea worth holding is the difference between two kinds of performance data. Lab data comes from a synthetic test: one run, one machine, controlled conditions. Field data comes from your real users on their own devices and networks, and Speed Insights reports field data. That distinction decides your search ranking, because Google ranks on field data scored at the 75th percentile: a perfect lab score means little when real users on real phones wait.

Installing Web Analytics and Speed Insights

Section titled “Installing Web Analytics and Speed Insights”

Two packages, two components, one dashboard toggle, one verification.

  1. Install both packages with pnpm.

    Terminal window
    pnpm add @vercel/analytics @vercel/speed-insights
  2. Add both components to your root layout, inside <body>, after {children}.

  3. Enable Web Analytics and Speed Insights in the Vercel project dashboard, per environment. This is the step people forget. The package ships the script either way, but until you flip the toggle the data goes nowhere: no error, no warning, just an empty dashboard. Turn it on as you ship the code.

  4. Verify in production. Load a page on your live site and watch the dashboard. The first data takes thirty seconds to a minute to arrive, so an empty panel for the first minute is expected, not a bug. Once a view lands, you’re done.

import { Analytics } from '@vercel/analytics/next';
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}

Both imports come from each package’s Next.js subpath, the entry point built for the App Router. One import per capability.

import { Analytics } from '@vercel/analytics/next';
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}

Your root layout stays a server component: no 'use client', no provider, because each component handles its own client behavior internally.

import { Analytics } from '@vercel/analytics/next';
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}

Drop both in once, at the root, after {children}. Every route renders inside the root layout, so this single placement covers every page.

1 / 1
Section titled “Why the cookieless floor skips the consent gate”

Here is the correction. In the security chapter you learned that nothing non-essential fires before the user consents: every tracker routes through your useConsent() source of truth and stays dark until the user accepts. So the natural next move, having just installed two analytics tools, is to wrap <Analytics /> and <SpeedInsights /> in that same gate. Don’t.

The gate exists to protect the user’s personal data, and these two collect none: no cookies, no fingerprinting, everything aggregated and anonymized at ingest. Under most jurisdictions that puts them in the “essential” or “legitimate interest” category for traffic analytics, which does not require consent. That is why they sit outside the gate by design.

Gate them anyway and you pay for it. On a marketing page most visitors never click accept; they read what they came for and leave, or dismiss the banner. Behind the gate, every one of them is invisible to you. You throw away the bulk of your traffic data, the exact data you installed these for, and gain no compliance benefit, because the tools never needed consent. Gate by what a tool collects, never by reflex.

That rule cuts both ways. PostHog does handle personal data: distinct user IDs, IP addresses, event properties that carry user state. So PostHog routes through the consent gate, and a later lesson in this chapter wires exactly that. The floor skips the gate because it is cookieless; PostHog goes through it because it isn’t.

The cookieless floor goes straight to ingest; PostHog fires only after the user clears the consent gate.

One caveat: “most jurisdictions” is doing real work in that sentence. A few stricter regimes draw the line differently, and the final call on what your product needs is your legal team’s, not your framework’s. Leaving these two cookieless tools ungated is the engineering default, not a guarantee.

Where to enable it: production, preview, dev

Section titled “Where to enable it: production, preview, dev”

The dashboard toggle is per-environment, so you decide separately for each. The defaults are easy:

  • Production: on. This is where real traffic lives.
  • Preview deployments: opt in. Turn it on for a preview URL when you want to QA against real traffic on that deploy; otherwise leave it off, so your test clicks don’t muddy production-shaped data.
  • Development: off. There’s nothing useful to capture from clicking around on localhost.

One dependency under all of this is a silent failure waiting to happen: @vercel/analytics needs Vercel’s edge network to ingest its data. On the course’s Vercel-hosted stack that’s the default. But ship this package on a static export hosted elsewhere and the script loads, runs, and catches nothing, because there’s no edge endpoint to send to.

You’ve shipped the floor. The decision left is when to add the next tier, so you reach for it on purpose rather than out of anxiety. Each of the five threshold signals names a question the floor structurally cannot answer, which is what makes the line real rather than arbitrary:

  • Who. The floor has no identity, so it counts anonymous visitors but can’t tell you what this signed-in user did.
  • What they did. The floor has no event schema, so it records page views, not “clicked upgrade” with plan: 'pro' attached.
  • Across sessions. The floor doesn’t stitch sessions, so it can’t follow one person from sign-up today to first paid invoice next week.
  • Gated by a flag. The floor has no flags, so it can’t roll a feature out to 10% of orgs or kill-switch a broken one.
  • In replay. The floor has no replay, so it can’t show you the session behind a bug that never threw an error.

If none of those are real for your product right now, stay on the floor. The moment one becomes a genuine, present need, that’s your signal, and the next lesson lands exactly that decision.

One tool you might expect here and won’t see: Google Analytics 4, the historical default. Its session-and-hit data model fits product analytics awkwardly, its consent UX is heavier than what we just built, and its exports are rigid. The split is clean: Vercel for traffic, PostHog for product analytics. GA4 stays a marketing-team conversation, not an engineering one.

A pre-PMF marketing site with one pricing page wants to know how many visitors it gets and which posts drive sign-ups. What’s the right analytics stack?

The cookieless floor on its own.
PostHog from day one, floor optional.
GA4 for the marketing numbers.
The floor plus PostHog’s four primitives — events, flags, replay, experiments — wired up now so they’re ready later.

The official quickstarts cover the wiring. Two deeper references back the lesson’s load-bearing ideas: why these tools skip the consent gate, and what the Speed Insights metrics mean.