~/blog/tracked-without-askingPOSTED
by Shady Nathan Tawfik · October 9, 2026 · 9 min

Tracked Without Asking: How the Web Identifies You After Cookies

Third-party cookies are going away, and tracking did not. Fingerprints are recomputed on every load, the TLS handshake is an identifier before any script runs, client hints re-expose a frozen user agent, and state hides in caches and first-party subdomains. A fresh-profile lab run shows a visitor leaving zero cookies and still being unique — and what actually helps.

Interactive[blog-2.0]

TL;DR: The third-party cookie was a container, never the tracker. Regulators and browsers attacked the container; identification moved into the fingerprint, the connection, the cache and the site's own subdomains. A clean profile left behind zero cookies and was still unique — and only one of the mechanisms in this article needs JavaScript at all. "We do not use cookies" answers a question nobody serious was asking.

The scenario

I audit websites for a living, so I open a lot of them the way a sceptical visitor would: fresh profile, no history, no consent, one page load. That setup is the only honest test of what a site does to someone who has agreed to nothing.

On a good day the cookie jar comes back empty and the site congratulates itself in the privacy notice. On the same page load, a fingerprint computed from screen, fonts and GPU has already made me one-of-one; the TLS ClientHello my client sent has already been hashed by a fingerprinting service upstream; and a subdomain of the site has quietly answered from an advertising network's address. None of that needed a cookie, a click, or a dialog.

This article is about that gap. I already wrote about what a browser hands over — the live banner under this site's navigation shows it to every visitor. This is the other half: what the receiving end does with it, in the post-cookie world we actually live in.

I keep the technical claims reproducible and the lab local. No real visitor, no third-party service is probed in a way that identifies anyone.

The pattern

The mental model most people carry — tracking = cookies — was always a simplification, and in 2026 it is actively wrong. Here are the places identity now lives instead.

The fingerprint, computed on every visit

A fingerprint is not a file. It is a recomputation: a script reads values the platform exposes anyway — screen and pixel ratio, time zone and language, CPU cores and estimated memory, the WebGL renderer string, the set of installed fonts, the exact pixels a canvas produces — and hashes the combination.

The arithmetic is unforgiving. Around 33 bits of entropy are enough to single out one person in the world; a single modern machine routinely offers 20 to 30 bits of usable uniqueness from a handful of values. Nothing is persisted, because nothing needs to be: the value is derived fresh from the same hardware every time. There is no cookie to decline, and "clear your cookies" removes none of it.

The connection is an identifier before JavaScript exists

Long before the page runs, the server has already seen the client's TLS handshake — the ordered list of ciphers, elliptic curves and extensions — and its HTTP/2 settings frame. That pattern is stable per client implementation and is captured as JA3/JA4 (TLS) and the Akamai fingerprint (HTTP/2). Header order and casing add a little more.

This matters because it is server-side and passive. No script, no storage, no consent dialog. Even a bare curl is a signature. A tracker that fingerprints at the handshake has identified the connection before deciding whether to bother with the page at all.

Client hints re-open a door that was politely closed

User-Agent strings were reduced because they leaked too much. The replacement, Client Hints, lets a site ask for the detail back with an Accept-CH header: full version list, platform version, device model, and more. The browser then sends those on subsequent requests — no prompt, no opt-in that a visitor would recognise.

So the entropy did not disappear; it became opt-in for the site, not for the user. A page that wants the old precision simply requests it, and a Chromium browser obliges. (Support differs by engine — which, conveniently, is itself a fingerprinting signal.)

State hides in caches, not cookies

"We do not use cookies" is a statement about one storage API. Identity also lives in localStorage, sessionStorage, IndexedDB and the Cache API — all same-origin, all persistent, none of them a cookie, none of them requiring a cookie banner. The HTTP cache can do the same trick: an ETag or a cache-timing probe turns "do I still have this resource?" into a stable bit of state.

The container changed. The storage did not go anywhere.

The tracker that wears your own domain

Ad blockers block third-party hosts by name. The counter was elegant: give the tracker a CNAME on a subdomain of the site (metrics.example.com → vendor.tracker.net). The browser now sees a first-party host, blockers leave it alone, and the visitor's consent — given to the website — silently covers a vendor. Analysing where a site's subresources actually terminate is now a security-review step, not an ad-blocker feature.

Visitor with no cookiesHandshake fingerprint: JA3 JA4 HTTP2, server sideJS census: screen type GPU fonts canvasStorage: localStorage IndexedDB Cache API ETagClient hints: Accept-CH asks for full version againRecomputed identity, per loadSame visitor recognised, never asked

Because it was convenient for everyone. For sites, a cookie notice looks like consent. For regulators, the cookie is a visible, legible object. For vendors, cookie-based tracking was easy to explain and easy to bill. The fingerprint, the handshake and the cache have none of those properties — which is exactly why they are where the tracking went.

TL;DR: Third-party cookies were the container, not the tracker. With the container gone, identification moved into the fingerprint, the connection, the cache and the first-party subdomain. A fresh profile leaves zero cookies and is still unique — and only one of these mechanisms needs JavaScript at all.

Findings

SeverityMechanismWhy it matters
HIGHServer-side TLS/HTTP2 fingerprinting (JA3/JA4)Identifies at the connection layer, before any script or consent — invisible to cookie controls
HIGHFirst-party subdomain pointing at a third party (CNAME cloaking)Defeats hostname blocking; moves a vendor inside the site's consent
MEDIUMJavaScript device fingerprinting (canvas, WebGL, fonts, hardware)Re-identifies with no storage and no cookie; recomputed per visit
MEDIUMClient Hints (Accept-CH)Re-exposes the user-agent detail that was deliberately reduced
MEDIUMNon-cookie storage (localStorage, IndexedDB, Cache API, ETag)Persistent identifiers outside the scope of cookie consent
LOWReduced user-agent string treated as privacyVersion reduction without disabling hints is cosmetic
INFO"We do not use cookies" claimsTechnically true, materially misleading

The attack path

  1. Fingerprint passively. Hash the handshake before the page loads. Cheap, server-side, and outside every cookie rule a visitor has ever been shown.
  2. Enrich in-page. Add the JavaScript census — canvas, fonts, GPU — to raise confidence from "a client" to "this machine".
  3. Persist without permission. Use a cache entry or an ETag so a return visit is recognised even after a cookie wipe.
  4. Absorb the vendor. Point a first-party subdomain at the ad network, so blocking tools and the site's own consent both look satisfied.
  5. Profile and monetise. Combine the above into an audience, sell it, and let the visitor keep clicking "reject all" — which, for none of these mechanisms, changes anything.

Reproducing it in the lab

I ran a clean browser profile against a controlled stack and captured, in order: the cookie jar, the third-party requests, the in-page census and the handshake signature.

ScenarioMeasured result
Fresh profile, no interaction0 cookies, 0 third-party hosts — and a unique fingerprint
Same profile, cookies cleared and reloadedfingerprint unchanged (hardware did not change)
Scripts disabledfingerprint gone; handshake signature still present
Cookie-wipe onlynothing changes for the server-side and fingerprint layers
Hardened browser (canvas/WebGL resistance)device signal collapsed toward a generic bucket

The last row is the only one that moves the needle, and it is a browser change, not a click. That is the uncomfortable summary: consent toggles are the wrong control for most of what identifies you.

How to detect it in your own estate

  • Assume the connection is observed. Treat JA3/JA4 and HTTP/2 settings as an identifier you neither control nor hide by policy — audit what your edge logs and with whom it is shared.
  • Inventory subresources by where they terminate. Follow every CNAME. A first-party metrics. host that resolves to a vendor is the finding, not a footnote.
  • Read your own Accept-CH. If you ask for full versions and platform versions, know that you have re-opened entropy deliberately.
  • Fresh-profile test per release. Watch cookies and storage and third-party hosts on first paint — not just the cookie banner.
  • Ask what you actually need. Most analytics answer their question with far less entropy than a full device census.

How to fix it (in this order)

  1. P0 — Stop requesting entropy. Drop Accept-CH requests you do not need; do not fingerprint at the edge.
  2. P0 — Fix the vendor boundary. No third-party subresources, no CNAME-to-vendor subdomains; if a service must run, run it first-party under your own contract and disclose it.
  3. P1 — Choose privacy-preserving measurement. First-party, cookieless analytics that cannot re-identify, documented in the privacy notice.
  4. P1 — Send a strict Referrer-Policy and cut metadata leakage to everyone downstream.
  5. P2 — Make it visible. Show the visitor what the page can read about them, and be specific about what leaves the browser. Transparency does not stop a determined tracker — it stops the quiet ones who assumed nobody checks.

Once an attacker gains access, they can perform the following actions:

A visitor who never accepted cookies is still re-identified across sessions and sites by a fingerprint recomputed on every load.
Profiles built this way are sold, enriched and used for price splitting and ad targeting — without any act the visitor could point to.
A first-party subdomain that CNAMEs to a third party defeats hostname-based blocking and moves the vendor inside the consent you gave the site.

The takeaway

The cookie was never the tracking; it was the receipt. The tracking is the recomputation of who you are from a machine that answers the same way every time — plus a connection that identifies itself before you can be asked, and a vendor hiding behind your own domain. Clearing cookies is hygiene. Understanding what is being derived, and refusing to derive it, is the actual defence.

If you are curious what your own browser gives away on this site, the banner under the navigation is the live version of exactly this article.

Shady Nathan Tawfik

Founder & Cyber IT Security Engineer in Bielefeld. Offensive security, audits and full-stack builds. More at

For educational purposes only. Every reproducible command targets my own lab environment (localhost), never a live system. © 2026