← Incognito Tracking

About this demo

Audio fingerprinting is a method to uncover & track users without cookies, even in incognito browsers. We found it on 20 major sites, after pulling on a thread about an AliExpress tab breaking someone’s Bluetooth headphones.

Watch it happen

A name is registered in a normal window, then the same URL is opened in a fresh incognito window: no cookies, empty localStorage, no login — and the page still names the visitor, because both windows produce the same device hash.

How we built this

The whole demo is two files: a page that measures your device, and a server that keeps a map from those measurements to a name. There is no cookie, no account, no client-side storage of any kind.

1. Measure the device

public/fingerprint.js collects signals any page can read without asking:

 audio     OfflineAudioContext: a ~10 kHz tone through a DynamicsCompressor,
           rendered into a buffer (never to a speaker), samples summed.
           Your CPU and audio stack round the maths their own way.
 webgl     unmasked GPU vendor + renderer string
 screen    resolution, colour depth
 device    CPU core count, platform, timezone
 canvas    how your machine rasterises one line of text (precise, but
           browser-specific — so it is kept in a separate hash)

2. Hash it twice — and once more, coarsely

 hardware id = sha256( audio ## webgl ## screen/device )
 full id     = sha256( audio ## webgl ## screen/device ## canvas )
 soft id     = sha256( webgl ## device, minus screen size )

 hardware id → survives a new profile, incognito, often a different browser
 full id     → more unique, but changes between browser engines
 soft id     → last resort for Safari Private Browsing (see below); coarse
               enough that whole groups of identical devices share one

Deliberately excluded: devicePixelRatio. It changes with page zoom, and zoom is per-profile, so it would break recognition for anyone who had zoomed in.

3. Recognize, and prove it

api/fp.js stores hash → { name, badge }. The badge is the honest part: the emoji and colour are rolled at random the first time the server sees a device and then kept in that record. They are not computed from the hash, so two browsers cannot arrive at the same badge by coincidence:

 normal window          incognito window
 ─────────────          ────────────────
 hash 5f1c9a…    ──►    hash 5f1c9a…          same device, same hash
 server rolls 🦦        server looks up 🦦    the badge only matches because
 stores it + "Jared"    returns "Jared"       the server recognized the hash

Location is read off the IP address every request carries anyway — no navigator.geolocation call, so there is no prompt to decline. City-level, often wrong by a metro area, and never stored.

4. Where it stops working: Safari Private Browsing

Since Safari 17, iOS and macOS Safari run advanced tracking and fingerprinting protection — on by default in Private Browsing, optional everywhere else. It does not block the APIs used here; it makes their answers unreliable (WebKit’s writeup):

 audio samples   every sample multiplied by 1 ± 0.001 of fresh random noise
 canvas pixels   per-pixel noise, salted per session and per site
 screen.width/   replaced by the window’s innerWidth / innerHeight, which
 .height         differs between tabs and shifts as the URL bar collapses

So the hardware and full ids change on every single page load in a private tab — not just between tabs. There is nothing precise left to match on, which is why this demo now falls back to the coarse soft id. That one is honest about what it is: it identifies a kind of device (same GPU strings, same core count, same platform, same timezone), not a device, so the page labels such a match “a guess”, and the server refuses to use a coarse key at all once two different people share it. Every browser sends that coarse id, not just Safari — Safari is only where it is the last thing standing — so a “guess” anywhere can name the wrong person.

Honest limits: this maps a name you typed to a device hash — it doesn’t discover your real identity out of thin air (a real tracker does that by linking the fingerprint to an account or an ad-network profile). Matching across two different browser engines is unreliable, especially on machines using software rendering. And no microphone is involved anywhere: the audio never leaves the browser’s own pipeline.

Sites doing this today

From a single instrumented run of 20 major shopping sites (Firefox + Chromium, August 2026). Bot-detection scripts branch per session and region, so treat this as “observed at least once,” not a permanent property of each site.

BehaviorSites
Held a live audio path open to the speakers (zero volume, never closed — this is what broke the original reporter’s Bluetooth) aliexpress.com, ebay.com
Ran the one-shot offline audio hash temu.com, shein.com, shopee.com, dhgate.com, banggood.com, walmart.com, ebay.com
Shipped audio-fingerprinting code that didn’t fire during our visit alibaba.com, lazada.com (same Alibaba script), amazon.com (via AWS WAF)
Other fingerprinting only (canvas, WebGL, device attributes) — no audio taobao.com, tmall.com, wish.com
Nothing observed jd.com, miniinthebox.com

It is not a China story: US eBay held the live audio path open exactly like AliExpress, while Chinese JD.com came back clean. It’s the shared anti-fraud vendors (Alibaba’s fireyejs, HUMAN/PerimeterX, AWS WAF) that spread it — which is also what makes one fingerprint useful for linking you across unrelated sites. No site we tested touched the microphone.

Sources and tools