The three classes of lie
1. Tampering lies. When a script replaces a built-in function - say navigator.webdriver or HTMLCanvasElement.prototype.toDataURL - the replacement no longer prints as [native code] the way a genuine browser function does. Asking Function.prototype.toString.call(fn) what the function looks like - and checking that toString itself has not been tampered with - exposes the patch. See function toString inspection.
2. Contradiction lies. Two reported values cannot both be true: a Windows User-Agent paired with a Linux font set, a navigator.platform of Win32 but a math signature (tiny rounding differences unique to each JS engine) from a different engine, userAgentData.mobile = true alongside maxTouchPoints = 0 (a touchscreen with zero touch points), or a screen availWidth larger than its width.
3. Scope lies. The most elegant: spawn a Web Worker (a background JavaScript thread) and read navigator from inside it. Many spoofing tools only patch the main-thread navigator and forget the worker scope, so the two disagree. CreepJS leans heavily on this.
Why lie detection beats spoofing
Single-value spoofing assumes the vendor reads each signal on its own. Lie detection assumes nothing and instead measures coherence - whether everything fits together. To pass, a scraper must present a fingerprint where every signal - UA, platform, fonts, canvas, WebGL renderer, math, timezone, languages, worker scope - matches one real, existing device. That is why the durable approach is to run a genuine browser on genuine hardware (or a deeply patched build like Camoufox / CloakBrowser) rather than overriding properties at runtime.
You can see exactly which lies your own browser exposes - and the trust score they add up to - in the Browser Fingerprint Checker.
Why coherence is the unit of measurement
The lesson from lie detection is that detectors measure the whole identity, not any single field. Once a detector cross-checks the User-Agent against the JS engine math, the font set against the OS, the GPU string against the renderer, and the timezone against the IP geolocation, a value changed in isolation only creates a new contradiction. Any field that differs has to be consistent with every field that did not.
This is why tools built around a real, internally consistent device profile — the approach managed scraping APIs and patched browsers such as Camoufox take — behave differently from runtime property overrides. A coherent stack (engine, fonts, canvas, WebGL, headers, network) has no seam for cross-checks to catch, whereas JavaScript overrides layered on top of a headless Chrome still surface contradictions the detector can read.
