Skip to content
On this page

Cross-API coherence checking is a detection method that asks the browser the same question through two or more independent APIs and compares the answers. Instead of measuring how rare a value is, it measures whether the browser is internally consistent: does navigator.userAgent agree with the User-Agent request header, does screen.width agree with a CSS media query, does the WebGL renderer describe the same GPU as the WebGPU adapter. A real browser answers coherently because every answer is generated by the same engine reading the same machine. A modified one usually answers coherently on the surface that was modified and truthfully everywhere else.

Quick facts

Core ideaAsk one question through two unrelated code paths; compare the answers
DetectsPatched getters, partial edits, headless defaults left in place
Signal typeBinary contradiction, not statistical rarity
Typical pairsHeader vs runtime, JS vs CSS, window vs worker, WebGL vs WebGPU, IP vs timezone
Why it is hard to satisfyA consistent answer must be produced everywhere at once, not per surface

Rarity fingerprinting vs coherence checking

Classical browser fingerprinting is an entropy problem: collect many values, hash them, and ask how many other visitors share that hash. The measure of interest is rarity, quantified in bits of fingerprint entropy. Coherence checking is a different question entirely. It does not care whether your configuration is rare. It cares whether your configuration is possible.

The distinction matters because the two produce opposite failure modes. A rarity check flags you for being unusual - which real users with unusual hardware also are, so it carries false positives and is usually scored probabilistically. A coherence check flags you for being self-contradictory, and a real browser is essentially never self-contradictory, because a single engine computes both answers from the same underlying state. That makes contradictions cheap to act on: a site can block on one hard contradiction with far more confidence than on a rare hash.

The practical consequence is that a value can be perfectly ordinary and still fail. A User-Agent string claiming a current desktop Chrome release is the most common string on the web. It fails instantly if the same request arrives without the matching Sec-CH-UA client hints, or if window.chrome is missing, or if the CSS engine does not support a Blink-only feature that shipped in the version being claimed.

The main coherence pairs

Most checks in this family fall into a handful of structural patterns. Each pair below is a question with two independent answer paths inside one browser:

PairQuestion asked twiceContradiction it exposes
Wire vs runtimeWhat browser is this? Read the User-Agent header, then navigator.userAgentA header rewritten by a proxy or client library while the JS runtime still reports the original
JS vs CSSHow big is the screen? Read screen.width, then ask matchMediaA patched screen object; the CSS layout engine is a separate code path and is rarely patched too
Window vs workerWhat is the timezone / GPU / platform? Ask the page, then ask a WorkerPage-world patches that never reach other realms
API vs APIWhat GPU is this? Read the WebGL renderer, then the WebGPU adapterOne graphics API edited, the other left at its real or default value
Claim vs capabilityYou say you are Chrome 1xx - do you have what that build has?A version claim not backed by the matching JS globals, codecs, or CSS features
Clock vs clockWhat time is it? Compare Date.now() with the monotonic timerA wall clock moved without the performance clock, or vice versa
Network vs localeWhere are you? Compare the exit IP against the browser timezone and languagesA timezone that no country on that IP observes

None of these require novel measurement. They reuse surfaces the glossary already documents individually; the detection value comes entirely from reading two of them together.

Why a partial edit scores worse than no edit at all

This is the counterintuitive result that shapes the whole field. A default headless browser is identifiable - it has known tells, and a site can score it as automation. A browser with one surface edited and the rest untouched is incoherent, which is a stronger and more actionable signal, because incoherence has no innocent explanation. Rare hardware explains a rare hash. Nothing explains a screen.width of 1920 that CSS measures as 800.

That is the same conclusion the corpus reaches from every other direction: a believable identity is a coherent set of values harvested from one real machine, not a pile of individually plausible edits. It is why lie detection and fingerprint clustering have displaced per-field property overrides, and why engine-level tools that generate every surface from one internally consistent device profile behave differently from JavaScript patches applied after the page loads.

For teams collecting public web data at scale, the takeaway is that coherence is an infrastructure property, not a script you can add. A managed web data API keeps browser sessions, network egress, and locale settings aligned by construction, so the answers agree no matter which path a page uses to ask.

Code example

javascript
// Four coherence checks, each asking one question through two code paths.
// Real browsers agree on all four; partial edits usually fail at least one.

// 1. JS screen object vs the CSS layout engine
const cssAgrees = matchMedia(`(device-width: ${screen.width}px)`).matches;

// 2. Main thread vs Worker realm (same question, different global)
const workerSrc = `postMessage({
  tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
  ua: navigator.userAgent,
  cores: navigator.hardwareConcurrency
})`;
const w = new Worker(URL.createObjectURL(new Blob([workerSrc])));
w.onmessage = (e) => {
  const sameTz = e.data.tz === Intl.DateTimeFormat().resolvedOptions().timeZone;
  const sameUa = e.data.ua === navigator.userAgent;
  console.log({ sameTz, sameUa });
};

// 3. Wall clock vs monotonic clock (should reconstruct to within a few ms)
const clockDrift = Math.abs(performance.timeOrigin + performance.now() - Date.now());

// 4. Version claim vs the capabilities that version shipped with
const claimsChrome = /Chrome\/(\d+)/.test(navigator.userAgent);
const hasChromeGlobals = typeof window.chrome === 'object';
const hasBlinkCss = CSS.supports('overflow-anchor: auto');   // Blink-only
const claimBacked = !claimsChrome || (hasChromeGlobals && hasBlinkCss);

console.log({ cssAgrees, clockDrift, claimBacked });

Next in Coherence and lie detection · 3 of 8

Now apply it across execution contexts, not just APIs.

What Is Realm Coherence Detection?

Related terms

Concept map

Concept map

How Cross-API Coherence Checking connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Anti-Bot
Building map…

Frequently asked questions

How is coherence checking different from normal browser fingerprinting?

Normal fingerprinting measures how rare your combination of values is, producing a probabilistic score. Coherence checking measures whether your values contradict each other, producing a near-binary verdict. Rare hardware is a legitimate explanation for a rare fingerprint, but there is no legitimate explanation for a browser whose CSS engine and JavaScript engine report different screen sizes.

Can a coherence check produce a false positive?

Rarely, but it happens. Privacy browsers and hardened configurations deliberately normalise some surfaces, which can create genuine mismatches for real users. Corporate proxies that rewrite headers, aggressive content blockers, and accessibility tooling also perturb specific pairs. Well-built detection systems weight a single mismatch lower than a cluster of them for this reason.

Why do coherence checks catch modifications that individual surface checks miss?

Because a modification usually lands on one code path. Overriding a property on the navigator object changes what JavaScript reads, but not what the network stack sends, what the CSS engine computes, or what a Web Worker sees. The check does not need to identify the modification itself - it only needs to notice that two answers to the same question disagree.

Last updated: 2026-07-30 · Facts last verified: 2026-07-30