Skip to content

Features

Cookieless analytics features

Three things you get the day you paste the script.

  • Pageviews after Reject

    The script does not set a cookie or wait for a banner. If it is on the page, the pageview is counted — even after a visitor clicks Reject.

  • Source and campaign

    The landing keeps utm_source, utm_medium, utm_campaign, utm_content, and utm_term. Every other query key is dropped in the browser.

  • Watch

    On Starter and Growth we check that a hostname you already added still answers. More than a ping: HTTP, TLS, and DNS from Europe. Not a real browser.

Also free: Site Check for Chrome — cookies and trackers a page sets before and after you reject its banner. Sharing findings is opt-in.

Sample data, last 30 days

View sample dashboard

Unique visitors

845

Total visits

1,280

Total pageviews

2,574

Views per visit

2.01

Bounce rate

31%

Visit duration

5m 8s

Sample data — the same six tiles after you paste the script.

For marketers

Start here. Growth funnels are a straight path on the same calendar day — midnight starts a new person. That is the privacy trade, not a hidden cap.

  • Now

    Campaigns with five UTM tags, not a query-string landfill

    utm_source, medium, campaign, content, term. Everything else is dropped in the browser.

    More

    Only those five tags leave the tab. Tokens and emails in other query keys never reach us. Inner pages in a single-page app do not inherit the landing UTMs. The dashboard groups campaigns, channels, ads, and keywords. Messy URLs stay messy on your site.

  • Now

    Six tiles on the curve, click to overlay

    Unique visitors, visits, pageviews, views per visit, bounce, duration. Line, bars, or auto.

    More

    The numbers sit on the chart. Click a tile to overlay. Compare draws the previous window as a dashed line. Unique visitors reset at midnight UTC. A visit is the same person within 30 minutes. Visit duration is last minus first pageview in that visit. One-page visits are 0 seconds. No heartbeat, no extra script.

  • Now

    Live — last page, five minutes

    Who is on which path right now, without a heartbeat.

    More

    People on the site in the last five minutes. The path is their last pageview. A tab left open does not ping. No extra script. The pill at the top of the dashboard jumps to the list.

  • Now

    Watch — hear about downtime first

    Around the clock we check that your site still answers. More than a ping — you should know before the client does.

    More

    They clicked Reject. The hostname still has to answer. HTTP, TLS, and DNS on a site you already added. Frankfurt every window; Dublin confirms a fail or a slow response; London is a third sample only after a fail. Down means both failed. Slow means both cities were slow, two windows in a row — one city does not. A public status page and a monthly report. Visitor 404s via cfa('404'), 500s via cfa('500'). Heartbeat for cron jobs on Starter and Growth. Not a real browser: no JavaScript, no scripted checkout. Down windows shade the analytics chart. No Watch SKU — it follows the invoice. Recipe: /docs/watch.

What Watch checks

Watch is more than a ping. Each check is an HTTP GET from Europe — not a real browser. It is included on Starter and Growth, on a hostname you already added.

  • Three European cities

    Frankfurt checks every window. Dublin runs when Frankfurt failed, or when Frankfurt answered but first byte was slow. London is a third sample only after a fail — not for slowness.

  • DNS

    Each check resolves the hostname (IPv4, then IPv6 when needed) before it requests the URL. If the address set moves, we mail you.

  • HTTP status

    The response must match the status you expect. The default is 200–399. You can require a single code.

  • Redirects

    A redirect that leaves your hostname fails the check.

  • Page content

    You can require a short phrase in the body, or forbid one. A keyword check is its own row — the page can be up while the phrase is missing.

  • Speed

    We record first byte (TTFB) and total load time. Slow is based on first byte. The default threshold is 3 seconds; 0 turns Slow off.

  • Daily sitemap

    Once a day we fetch /sitemap.xml (or the path you set) and visit the first 40 URLs on the same hostname. Off-host URLs are skipped. A bad result is checked again after 30 minutes before we alert. Not an HTML crawl.

  • Certificate

    On a successful HTTPS check we read the leaf certificate visitors see. Mail at 14 days left, an incident at 3. We do not walk the full chain or grade ciphers.

  • Domain expiry

    Once a day we look up the registry (RDAP). Mail at 30 days left, an incident at 7.

  • Visitor 404s and 500s

    Watch counts cfa('404') and cfa('500') events from real visitors in the last hour. Over the threshold (default 10; 0 is off) we mail you. The hostname can still be Up.

  • Heartbeat

    On Starter and Growth you can POST a heartbeat for a cron or a job. If no beat arrives within the grace you set (minimum 60 seconds, maximum 24 hours), Watch opens a heartbeat incident. Empty grace is off.

  • TCP port

    You can add a TCP check for one port on a hostname you already added. That is a connect, not a port scan.

  • What Watch is not

    Watch is not a real browser and not a transaction test. It does not run JavaScript or click through a checkout.

A single slow sample never sends mail. Slow mail goes out only after Dublin confirms slowness in two consecutive windows. A real outage — two windows where Frankfurt and Dublin both failed — alerts promptly. One city down and one up stays Up.

Starter checks every 3 minutes (10 pages). Growth checks every minute (25 pages). Hobby shows the Watch tab; checks start on Starter.

Ping vs Watch

  • What it sends

    A simple ping
    Often ICMP echo, or one HTTP request
    Watch
    An HTTP GET — not a rendered page
  • Where from

    A simple ping
    Usually one location
    Watch
    Frankfurt every window; Dublin confirms a fail or a slow first byte; London only after a fail
  • What counts as up

    A simple ping
    Any answer may count as up
    Watch
    DNS, the status you expect (default 200–399), and no redirect off your hostname. Optional must-contain or must-not-contain phrases.
  • Speed

    A simple ping
    Sometimes round-trip time
    Watch
    First byte and total load time. Slow is first byte over your threshold (default 3 seconds).
  • Certificate and domain

    A simple ping
    No
    Watch
    Leaf certificate: mail at 14 days, incident at 3. Registry expiry (RDAP, once a day): mail at 30 days, incident at 7.
  • Sitemap and visitor errors

    A simple ping
    No
    Watch
    Daily sitemap, first 40 same-host URLs. Hourly visitor 404 and 500 rates from cfa('404') and cfa('500').
  • Cron jobs

    A simple ping
    No
    Watch
    Optional heartbeat on Starter and Growth. Empty grace is off.
  • When it alerts

    A simple ping
    Often on the first failed ping
    Watch
    Down after two windows where Frankfurt and Dublin both fail. Slow after two windows where both are slow. One slow sample never mails.
  • Browser checkout test

    A simple ping
    No
    Watch
    No — Watch does not run JavaScript or click through a checkout.
  • Now

    Goals — the action, billed as nothing

    A signup is a signup. It is not another pageview on the invoice.

    More

    Ask whoever ships the site to call cfa('signup') when the thing happens. There is no tag-manager UI yet. Events are not billed. Marketers without a developer still get pageviews, sources, and landing campaigns from the paste. Hobby and Starter keep a single named goal.

  • Now

    Monday in the inbox, not a login habit

    The briefing you already see, mailed once a week. No extra tracking.

    More

    Monday, once. Visitors, pageviews, top page and source from the last 7 days. Unsubscribe is a link. Switch it off in account settings. Not a daily drip.

  • Now

    Period briefing — a note you can paste to leadership

    The pattern, the mix, what to open next. Dashboard numbers only — no hashes.

    More

    Owner click. Grok writes from the tiles you already see. Copy it into a Monday email. Hobby 6 a day, Starter 12, Growth 20. Cached reads are free. The weekly mail is the same numbers, not a second tracker.

  • Now

    Notes on the curve — yours, or a campaign that just showed up

    You write a launch. The first day a UTM campaign arrives, we stamp it. Volume stays on the chart.

    More

    Vertical line, tooltip, list. Type a note, or we add “Campaign: …” the first time that campaign (or source / medium) is seen. Day-over-day traffic % is not a note — the tiles already show that. The Monday briefing is separate.

  • Now

    Search Console queries — clicks, impressions, CTR, position

    Sign in with the Google account that owns Search Console. Empty until then — we only show clicks Google reported.

    More

    Connect Google on the dashboard. You grant Search Console read on a site you own. We show totals plus top queries and Google landing pages for the same range as the board: clicks, impressions, CTR, and average position. Empty until you connect — we only show clicks Google reported.

  • Now

    Stripe charges on the same range

    Connect the Stripe account that takes payment. Empty until then — we only show charges Stripe reported.

    More

    OAuth, read-only. Gross, refunds, net, and charge count for the board range. If Checkout already stored utm_source / medium / campaign in metadata, we list those tags. Clicking one filters your pageviews. It does not prove that visit paid. Stripe account, not this hostname. Not mixed into visitor rows.

  • Now

    Locations: countries, regions, cities — still no café

    Click a country to zoom. Tabs for regions and cities. No map tiles, no postcode.

    More

    A country outline on the dashboard. Click to filter. Regions and cities are labels on the request, not a café database. No IP on the row, no coordinates, no postal code.

  • Now

    Many sites. Viewers. A public code.

    Starter: 5 sites, 3 viewers. Growth: 10 sites, 10 viewers. A public link plus a snippet for the website.

    More

    Invite colleagues at /app/team — they sign in and see dashboards, not settings. A public /s/… link needs no account. Viewers are included in the plan, not a seat SKU. Past 10 viewers, email hello@cookiefreeanalytics.com.

  • Now

    Funnels — linear, same day, Growth

    Drop-off between pages and events. Midnight starts a new person.

    More

    Growth only. Linear path, same UTC day. Midnight resets the person. That is the privacy trade, not a hidden cap. Two to eight steps: a path or a named event. Hobby and Starter keep a single named goal. No extra script. No session replay.

  • Now

    First byte and Lighthouse — lab scores from Google

    A Frankfurt GET we run. Google lab scores 0–100. The 1 KB script does not guess dwell or LCP.

    More

    First byte is four signals from a GET we make in Frankfurt, then what to do. Lighthouse (Performance, Accessibility, Best Practices, SEO) comes from PageSpeed Insights. Lab, not field. Refresh always runs a new audit. Scores are not cached. Not a Core Web Vitals product.

  • Now

    Buttons, files, outbound — named clicks, not heatmaps

    Opt-in. The 1 KB file stays 1 KB. A second helper counts the click.

    More

    Tick “also count clicks” in site settings. That adds a second file, cf-clicks.js: outbound hosts, file extensions (pdf, zip, …), buttons, and anything with data-cfa="…". Same beacon, named events, not billed. Not a heatmap. The default script does not listen.

  • Now

    Set up this site — from pages you already have

    A checkout path and goals from events that already fire. You confirm. We only use pages and events already on the site.

    More

    The dashboard can read your homepage menu and the paths that already have pageviews. On Growth it can save same-day funnels if those URLs exist — not a second copy of one you already added. Goals still need a named event that already fired. Owner click, not a silent rewrite.

  • Now

    WordPress snippet

    Paste the snippet in your theme header, or use any header-scripts plugin. Pageviews without a MonsterInsights cookie.

    More

    No plugin download yet; the WordPress.org listing comes later. WordPress.com sites on any paid plan can add the snippet too. Serving the file from your own hostname so blockers miss us is optional — recipe on /docs. Topic: /wordpress-analytics.

For teams with tooling

Claude, Cursor, and other MCP clients read the same numbers as the dashboard. No visitor hashes. Read API and MCP on /docs/api.

  • Now

    Serve the file from your hostname

    Optional. List-based blockers never see our hostname if the file comes from yours. On Hobby.

    More

    A path rewrite of /cf.js, or a CNAME on a subdomain such as c.yourdomain.com. CNAME keeps visitor IP, city, and same-day uniques. Path rewrites recover blockers but collect through the host. Shopify and other closed builders: paste the snippet, then CNAME. Recipe: /docs/proxy.

  • Now

    Read API — the dashboard as JSON

    A hashed bearer. The same visitors, pages, sources, and live you already see.

    More

    Starter and Growth. Mint a token on Account. We store a hash, show the secret once. Sites, overview, pages, sources, live. Growth adds funnels. No visitor hashes. No raw pageview dump. The bearer stays off Hobby. Hobby (free) gets 5 MCP tools through OAuth; paid plans get all 13. Recipe: /docs/api.

  • Now

    MCP — the dashboard in Claude and Cursor

    Ask after a deploy. OAuth 2.1 at https://www.cookiefreeanalytics.com/mcp, or the hashed bearer.

    More

    Hobby (free) gets 5 MCP tools through OAuth: traffic pulse, top pages, Watch status, add a website, and the tracking code, capped at 20, 10, 10, 10, and 30 calls a day. Paid plans get all 13. Claude, Cursor, ChatGPT, and Grok sign in on this host. curl on a paid plan still uses the token from Account. The model sees aggregates, not hashes. Recipe: /blog/cookieless-analytics-mcp.

  • Now

    Export — Excel from the dashboard

    Pages, referrers, campaigns, and the rest of the board as a workbook. We do not keep the file.

    More

    The Excel button on the dashboard downloads what you are looking at. Account can export and delete. No sales call. No weekly dump we host for you.

For engineers

The moat is how we collect and how we forget. Full recipe on /methodology.

How do you count a unique visitor without cookies?
HMAC-SHA256 of site, IP and user-agent, keyed with a server pepper and a random salt that exists only for that UTC day. We store 16 bytes. The IP is discarded. Tomorrow the salt is deleted, so the same person is a new digest.
Why not just SHA-256(site + IP + UA + date)?
That is deterministic. Anyone with edge IP logs and the formula can remake Monday’s hash. A deleted random salt plus a pepper that is not in the database cannot. HMAC is the keyed primitive; concatenation is not. This is the visitor-side moat — recipe on /methodology.
How does the beacon leave the browser?
POST JSON via navigator.sendBeacon. The payload is not in the URL, so CDN access logs do not see ?email= or ?token=. The shipped script does not GET. Collect is POST only — GET returns 204 and writes nothing.
Which query parameters do you keep?
utm_source, utm_medium, utm_campaign, utm_content, utm_term. The script allowlists them. The server allowlists them again. Everything else is dropped before it leaves the tab.
Do you store the full referrer?
No. Origin + path, no query. Source labels (Google, Hacker News, Direct) come from the hostname. Tokens in a referrer query never land on the row.
Does it count client-side / SPA navigations?
Yes. pushState, replaceState, popstate. The same path is not counted twice. Campaign tags stick to the first pageview in the tab — inner routes do not inherit them. After the landing, the referrer we send is the previous path on your host, so those hits are Direct, not another HN session.
How small is the file with all of that?
Under 1 KB gzipped, measured from /cf.js on this build. HMAC is server-side. POST, the allowlist, SPA hooks, and a prerender skip are in the script. Auto click-listeners are not.
Do prefetch and bots inflate the count?
Prerender/prefetch is dropped in the script (document.prerendering) and again if Sec-Purpose says prefetch. Library and crawler user-agents are dropped. Hostname must belong to the site, except on the public demo. Trailing slashes are folded so /pricing and /pricing/ are one path.
Do you store city-level location?
The edge already classified the request. We copy country, ISO 3166-2 region (as US-CA so California is not Canada), and a city name. We do not store IP, latitude, longitude, or postal code, and we do not run MaxMind or any other geo-IP database. If the host sent nothing, the fields are empty.
What stops someone flooding /api/collect?
Public ingest is not unforgeable. 60 beacons per hashed IP per minute — one flood, not a busy site. The counter lives in Postgres, so every Frankfurt isolate shares it. Over that IP quota we return 204 and write nothing. A popular site is not dropped. Raw IP is not stored on that row.
Is Watch just a ping?
No. A simple ping asks whether a host answers. Watch sends an HTTP GET from Frankfurt every window, confirms a fail or a slow first byte from Dublin, and uses London only after a fail. It checks DNS, the status you expect, redirects that leave your hostname, optional page phrases, first byte and total load time, the leaf certificate, domain expiry, a daily sitemap of the first 40 same-host URLs, visitor 404 and 500 rates, an optional TCP port, and heartbeats for cron jobs. Slow mail waits for two confirmed windows. Down mail waits for two windows where Frankfurt and Dublin both failed. It does not run JavaScript or click through a checkout.