Why instability is a red flag
On a real device, reading the canvas or audio fingerprint twice gives the same answer - the computation is deterministic for that hardware and software. Some privacy tools defend against tracking by injecting random noise so the value differs on every read. Detectors exploit that: a simple check renders a known pattern and verifies the pixels, and per-call noise makes the output deviate from the deterministic baseline, exposing the modification. When consecutive reads disagree, a consistency tool reports the value as unstable. So randomisation that is too aggressive trades one signal (a unique fingerprint) for a louder one (an impossible, ever-changing fingerprint).
How tools measure persistence
Consistency tools such as CreepJS collect raw signals across many APIs and compute more than one identifier from them: a stable, exact identity hash plus a looser, fuzzy hash that groups similar browsers. Comparing those identifiers across reloads and sessions answers the persistence question - does this profile stay the same when it should? A genuine browser holds steady; a profile whose values drift between reads stands out. The same tools pair this with consistency checks that look for values contradicting each other, so an unstable fingerprint and an internally inconsistent one are flagged by the same machinery.
Why stability matters for scraping
The practical lesson is that blending in is about coherence and stability, not noise. A profile drawn from a real browser population and kept consistent across a session looks ordinary; one that scrambles its fingerprint on every request looks like nothing a real user runs. This is also why a profile should return the same fingerprint when it reconnects through the same network and TLS context - a fingerprint that resets unpredictably between reconnects is as anomalous as one that changes mid-session. Stability is the goal; randomisation is the tell.
Stability is checked per layer, and the layers disagree independently
Reconnect stability is not one property but several, measured at different layers of the stack, and a session can be stable at one layer while drifting at another.
| Layer | What must stay constant | What drift indicates |
|---|---|---|
| TLS | The JA4 class of the ClientHello across every connection | Requests in one session originating from more than one client stack |
| HTTP/2 | SETTINGS values, window sizes, pseudo-header order | A different client library handling some requests |
| Network | The exit address, or at least its ASN and country | Per-request proxy rotation inside a single logical session |
| Browser | Canvas, WebGL, audio, and font readings | A fresh device profile generated per page load |
| Locale | Timezone, languages, and their agreement with the exit IP | Environment settings applied inconsistently between requests |
The subtle case is TLS, where the correct expectation is not literal byte-identity. Browsers deliberately shuffle the order of some ClientHello extensions on every connection as part of anti-ossification behaviour, so a genuine browser produces a ClientHello that varies in ordering while remaining constant in its cipher list, supported groups, and ALPN set. A client that emits a byte-identical ClientHello every single time is as anomalous as one that changes cipher suites between requests - stability has to be measured on the properties that ought to be stable, not on the raw bytes.
Why rotation applied at the wrong granularity backfires
Rotation is a sound idea applied at the wrong scope more often than not. The intuition that varying identity reduces trackability is correct across sessions and wrong within one, because a session is defined by continuity: one visitor, one device, one network path, for the duration of a visit. Real users do not acquire new GPUs between page loads, and their exit address does not change halfway through a checkout flow.
When rotation happens per request rather than per session, the resulting pattern is not anonymity but impossibility. A sequence of requests carrying one cookie while presenting several canvas hashes, several TLS profiles, or several countries describes a device that cannot exist. This is the same lesson as cross-API coherence, extended along the time axis: coherence has to hold across requests as well as across APIs.
The correct granularity is the session boundary. Pin one device profile, one exit address, one locale, and one client stack for the whole of a logical session; change all of them together when a new session begins. That gives variety between sessions without producing contradictions inside one.
Getting this right is largely a state-management problem rather than a fingerprinting one - it requires whatever issues proxies and whatever runs browsers to agree on what a session is and to keep them bound together. Managed web data APIs expose exactly this as a session primitive, which is why session-scoped stability tends to be a configuration choice there rather than an infrastructure project.
