Heretic and FingerprintJS
A browser fingerprint is a hash of what the browser reported about itself. That is a useful thing to have and it is not a measurement of a machine. The difference decides which problems each one can close.
What FingerprintJS does
The open-source library collects browser-exposed values and hashes them into a visitor identifier. Fingerprint Pro, the commercial product, adds server-side processing and a set of signals covering bot detection, VPN and proxy indicators, incognito mode, tampering and virtual machine hints, and publishes accuracy figures for returning-visitor identification.
It is a mature product and the identification is good. If the job is recognising a returning visitor, it does that job.
The input is the client's own account of itself
The classic fingerprint surface is navigator properties, screen dimensions, timezone,
language list, font metrics, a canvas render, a WebGL render, an audio render. Every one of
those is a JavaScript property or a JavaScript call, and every one can be replaced before your
page loads.
That is not a theoretical weakness. It is a product category. An anti-detect browser is a control panel where the operator picks the operating system, the GPU string, the core count, the timezone and the screen size, and injects per-profile noise into the canvas so the hash rotates per profile. Forty profiles produce forty identifiers. One household laptop shared by three people produces one.
So a fingerprint hash merges the people you needed separated and separates the accounts you needed linked, and collecting more properties does not fix it, because the adversary controls all of them.
Claim on the left, measurement on the right
| Value | What a fingerprint reads | What Heretic measures |
|---|---|---|
| navigator.platform | a JavaScript property | the operating system that built the TCP SYN |
| navigator.hardwareConcurrency | a JavaScript property | work delivered under a fixed parallel load |
| WebGL renderer string | a JavaScript property | limits the driver reports, tested by allocating past them |
| Intl timezone | a JavaScript property | round trip against the distance that zone implies |
| User agent | a request header and a property | TLS extension order, GREASE, HTTP/2 settings |
| Canvas hash | a render the client can noise | realm agreement across window, worker and frame |
The right-hand column is not reachable from the page. There is no navigator.tcpWindowScale, and no stealth plugin patches a kernel.
What we do about identity, and what we admit
Heretic derives two identifiers from measurements rather than claims: an instance identifier and a machine identifier, scoped per site key so they are not a cross-customer tracking token, and normalised for screen orientation so a phone turning sideways is not a new device.
Both are marked conditional, and we would rather say that here than in a footnote. Browser measurements of compute and rendering are affected by scheduling, JIT warmup, thermal state and power management, none of which we control. A matching machine identifier is strong evidence that the same hardware came back. It is not proof, and we will not report it as proof.
When strong evidence is not enough, there is a device ceremony that ends with a passkey signing the measurements and returns the device it ruled on. Its limits are documented too: it binds browser-supplied bytes to a challenge, and it is not hardware attestation.
Which one you want
For recognising a returning visitor in a low-stakes flow, a fingerprint identifier is the right tool and always was. Accept that it is wrong at the edges.
For deciding whether the machine in front of you is what it says it is, the input has to be something the machine did rather than something it said. That is the whole distinction, and everything else follows from it.
Run it against this browser.
The live probe measures the browser you are reading this in and shows the claims and the measurements side by side, with every finding it produced.