Skip to main content
ASoc
Comparison

Fathom vs. Vercel Analytics: Portability, Priced

Both are cookieless with a one-line install. The difference is what happens when you leave your host, measured against this site's live CSP, event wrapper and Lighthouse run.

The ASoc Team9 min read

Both of these are cookieless, GDPR-friendly analytics with a one-line install, and both will give you page views without a consent banner. The real difference is not the dashboard. It is what happens to your measurement the day you leave your host — and one of them answers that question with undefined.

The short answer

Choose Vercel Web Analytics if you deploy on Vercel and want zero configuration, first-party requests and no extra script host. Choose Fathom if you host anywhere else, run several sites, or need the data to outlive your hosting decision. Fathom is a product you buy; Vercel Analytics is a feature of a platform you already pay for.

The comparison, on the axes that actually diverge

Fathom AnalyticsVercel Web Analytics
Works off your hostYes — any host, any stackNo — production Vercel deployments only
InstallA script tag, or a framework packagenpm i @vercel/analytics, then one component
Cookies / consent bannerNoneNone
Script originThird-party host, or your own via custom-domain routingSame-origin first-party path in production
Custom eventsYesYes, with key–value properties
Data if you migrate hostsStays yours, keeps collectingStops at the migration
Pricing modelSubscription, by pageview volumeIncluded allowance on your Vercel plan, then per-event
Billing couplingIndependent of hostingSame invoice as your hosting

Pricing on both moves often enough that quoting today's numbers would mislead you by the time you read this — check their own pricing pages, and compare on events per month, because a custom-event-heavy site prices very differently from a brochure site on both.

What "one line" means in each case

This site runs Vercel Web Analytics. The entire installation is an import and a component in the root layout:

import { Analytics } from "@vercel/analytics/next";

// …inside <body>, after the app's children:
<Analytics />

That is genuinely all of it. No site ID, no API key, no account linking, because the deployment already knows which project it is. Fathom's install is comparable in size but not in kind: you paste a script tag carrying a site ID, or install its package and configure that ID — which is precisely what makes it portable. The ID belongs to you, so the same snippet works from Netlify, a VPS, or a static bucket.

That difference is the whole comparison in miniature. Zero configuration and portability are the same trade seen from two sides.

The part the docs bury: no extra CSP host in production

If you run a Content-Security-Policy, third-party analytics usually costs you two allowances — a script-src for the script and a connect-src for the beacon. Vercel Web Analytics costs one. This is our live policy, from next.config.ts:

script-src  'self' 'unsafe-inline' https://va.vercel-scripts.com …
connect-src 'self' <supabase-origin>

connect-src stays 'self'. In production the beacon posts to a same-origin path on your own domain, so there is no cross-origin destination to allow. Fathom solves the same problem the other way round, with optional custom-domain routing — you point a subdomain at their collector, which also makes the requests first-party and, as a side effect, harder for blockers to drop. Both approaches work; the Vercel one is free and automatic, the Fathom one is portable and deliberate.

Custom events are where you should actually decide

Page views are a commodity. The question worth answering is whether the tool can tell you which page did the work, and both can — the difference is in the shape of the data.

We wrap Vercel's track in one typed module (src/lib/analytics.ts) so an event name is a union rather than a string:

type ConversionEvent =
  | "preview_opened"
  | "buy_clicked"
  | "waitlist_joined"
  | "blog_cta_clicked"
  | "wishlist_added";

export function track(event: ConversionEvent, props?: Record<string, string | number>) {
  try {
    vercelTrack(event, props);
  } catch {
    // Analytics must never break UX — swallow any client-side error.
  }
}

Five events, each carrying properties: blog_cta_clicked sends { post, target }, which is what makes an article attributable to a specific product page rather than to a session. Vercel's query API can then group by eventData/<property> and filter with OData expressions, and vercel metrics does the same from the CLI. Fathom's model is closer to goals-and-conversions than to arbitrary property dimensions; if your analysis is "which of 238 articles sent buyers to which of 111 products", check that the shape you need is expressible before you commit.

Two implementation notes that apply to either tool, and both are visible in that snippet:

  • Wrap the vendor call. It is five lines, it gives you a typed event vocabulary so a typo cannot silently create a new event, and it is the only thing that makes swapping the vendor a one-file change. If you are genuinely undecided between these two, write the wrapper first.
  • Never let analytics throw. The catch is not defensive padding. A tracking call sits inside a click handler on a buy button; an exception there costs you the sale it was measuring.

The cost nobody puts in the comparison table

track() no-ops off a Vercel deployment — the injected script only exists there. That is convenient in local development and it is also the exact shape of the lock-in: every custom event you instrument is measurement that exists only while you stay. Two consequences we hit directly:

Local Lighthouse runs score 96 on Best Practices, not 100. The only failing audit is errors-in-console, and it is entirely the analytics beacon 404-ing locally, because /_vercel/insights/script.js is injected at the edge on real deployments only. On the deployed site it reads 100. It is a measurement artifact rather than a defect — but it is one you have to explain every time someone runs Lighthouse against localhost, and portable analytics does not produce it.

There is no local or preview signal. Events are counted on production deployments. You cannot smoke-test an instrumentation change by clicking it in dev; you ship it and watch. That is a real workflow cost on a site where the conversion events are the product feedback.

Neither is a reason to avoid Vercel Analytics. They are the reasons to be honest that "included with your host" is a price, not the absence of one.

Which one we would pick, and when

SituationPick
One site, already on Vercel, want numbers todayVercel Web Analytics
Several sites across different hostsFathom
Hosting decision is under active reviewFathom — do not couple measurement to it
Strict CSP and no appetite for a third-party hostVercel (or Fathom with custom-domain routing)
Need property-dimensioned custom eventsVercel, or verify Fathom covers your shape
Want analytics on a separate invoice from hostingFathom

We are in the first row and chose accordingly. The wrapper above is the hedge: five lines that mean the second row stops being a rewrite.

Mistakes and how they show up

SymptomCauseFix
No data at all after deployingWeb Analytics not enabled for the projectTurn it on in the project's Analytics tab; it is opt-in per project
Events fire locally, nothing in the dashboardCounted on production deployments onlyVerify on a production URL, not localhost or a preview
Console 404 for /_vercel/insights/script.jsRunning off-platformExpected locally; it resolves on a real deployment
Script blocked by your own CSPscript-src missing the analytics hostAdd https://va.vercel-scripts.com; connect-src needs nothing extra
Numbers far below server logsAd blockers dropping a third-party scriptFirst-party routing — built in on Vercel, custom-domain on Fathom
A misspelled event name creates a new eventRaw string passed to the vendor SDKWrap it and type the name as a union
A tracking call breaks a buttonVendor SDK threw inside a click handlerWrap the call in try/catch

Frequently asked questions

Do either of these need a cookie banner? Both are designed to avoid one: neither sets identifying cookies for analytics by default. Consent law depends on what your whole site does, so a checkout, a chat widget or an ad pixel can still put you in banner territory regardless of your analytics choice.

Can I run both? Yes, and it is a reasonable way to compare them for a month — you will see how much traffic blockers remove. Keep it short: two scripts is two scripts, and reconciling two sets of slightly different numbers forever is its own tax.

What happens to my Vercel Analytics data if I leave Vercel? Collection stops with the deployment. Export what you need through the Web Analytics API before you migrate; there is no portable agent that keeps running elsewhere. This is the single strongest argument for Fathom.

Is Vercel Web Analytics free? There is an included allowance on Vercel plans and per-event pricing beyond it, so "free" holds until it does not. Price it on your expected events per month — a site firing five custom events per session reaches the boundary far sooner than the pageview count suggests.

Where to take this next

Analytics is one of four scripts most sites end up loading, and the CSP interaction above is the one that breaks deploys. Setting a Content-Security-Policy in Next.js is the full policy this excerpt came from, error monitoring in Next.js covers the other half of production visibility, and our Lighthouse pass explains the 96-vs-100 artifact in more detail.

Templates in this post

ASoc Nexus, ASoc Nimbus and ASoc Nova are built the way this post describes — cookieless analytics behind a typed wrapper, a CSP that already allows the beacon, and no consent banner to retrofit.

Browse the full sets: Next.js landing page templates, Tailwind landing page templates.

Keep reading

Comparison11 min read

Gumroad Alternative: The Six Jobs You Take Back In-House

A hosted storefront does six jobs. Another one changes the fee; owning your storefront takes them back as code — 1,607 lines here, file by file.

Read more