The measured JS engine matches the engine the User-Agent claims
Check id js-engine-identifier-vs-ua
What an ordinary browser yields
An ordinary browser measures an id matching the family its own UA names — e.g. id 80 = V8 on Chrome — and passes.
What a detector infers
Two values are read straight out of the JavaScript engine itself: the character length of the RangeError message thrown by `(-1).toFixed(-1)`, and the length of the Array constructor's own source text with every occurrence of its name removed. Their sum is a stable engine fingerprint — 80 identifies V8, 58 SpiderMonkey, 77 JavaScriptCore — because it comes from wording and source formatting compiled into the binary, on a surface no User-Agent string, CDP override, or `navigator.userAgentData` shim ever touches. The check then compares that measured family against the family the UA claims (Firefox/FxiOS → SpiderMonkey; Edg/Chrome/Chromium/CriOS → V8; iPhone/iPad/iPod or Safari-without-Chrome → JavaScriptCore). When the two disagree, a detector can infer that the identity presented in HTTP and JS headers was written by a layer above the engine, and that inference is reliable precisely because the engine's own error text is not part of any spoofing surface. Severity is critical. Crucially, when the measured id is not one of the three known values, or the UA names no family the check adjudicates, `pass` is null — indeterminate, not a failure, and it is excluded from the score. That branch matters: engines reword error messages between versions, so a check that failed on an unrecognised id would fire on every real browser running a future release. An honest detector distinguishes "this contradicts" from "I don't know".
How to resolve it
Make the User-Agent match the engine that is actually executing. This contradiction cannot be resolved from inside JavaScript: patching `navigator` leaves the RangeError text and Array constructor source untouched, so a Gecko or WebKit engine presenting a Chrome UA stays visible. Either run the engine the UA claims, or claim the engine you run.
Read in the wild by
CreepJS
CreepJS — an open-source research demo rather than a production detector — runs nine deliberately broken snippets through `new Function`, collects each engine-authored `err.message`, and hashes the set into its fingerprint, filing the probe under the engine section of its source tree and treating the engine's own error wording as an engine-level signal.
src/engine/index.ts:22-32: `const errorTests = [() => new Function('alert(")')(), … () => new Function('null.bar')(), … () => new Function('(1).toString(1000)')(), … () => new Function('var x = new Array(-1)')(), …]` (nine entries), collected at line 12 via `errors.push(err.message)`; hashed in src/creep.ts:202 `hashify((consoleErrorsComputed || {}).errors)`, imported at src/creep.ts:7 as `import getConsoleErrors, { consoleErrorsHTML } from './engine'`.
Akamai
Lists error-message format as a JavaScript-environment signal, noting it "differs by engine" — which is exactly what this oracle measures.
signal_categories.md - 6. JavaScript Environment - Error messages
Edioff/akamai-analysis — signal_categories.mdDataDome
Provokes a TypeError inside a Worker and ships the message text verbatim; the wording is V8's, so the string itself names the engine.
mUMHqX = base64 "WorkerCaughtErr: Err: TypeError: Cannot read properties of null (reading '…'"
glizzykingdreko/datadome-encryption — tests/original.jsonEvery attribution traces to a published artifact. See the sources and their limits.
Other checks in Engine & OS oracles
- Math.tanh rounds the way the claimed OS's libm rounds
math-tanh-os-vs-uaIEEE 754 fixes how a double is stored but does not require transcendental functions to be correctly rounded, so every operating system's C… - which OS hyphenation engine the browser hyphenates through
hyphenation-engine-osWhen CSS asks a browser to hyphenate a long word, the break points come from a dictionary supplied by the operating system — and the… - the CPU architecture matches the architecture the browser claims
cpu-arch-nan-vs-uachIEEE-754 fixes the exponent and the quiet bit of a NaN but leaves the sign bit to the hardware, and the hardware disagrees: an x86 FPU… - the three heap numbers describe a possible heap
jsheap-triplet-orderingThis check replaces a retired one, and the swap is the lesson. - the platform's system font belongs to the operating system claimed
system-font-vs-claimed-osThe CSS2 system-font keywords — caption, icon, menu, message-box, small-caption and status-bar — are resolved by the HOST platform's font… - typefaces the claimed OS ships as separate faces measure as separate faces
claimed-os-typefaces-are-distinctA font request is answered by the host's font stack, not by the browser and not by anything the user agent sets, so changing…
Clearcote is a browser built for fingerprint coherence
It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.
This audit takes no position on how Clearcote scores on Engine & OS oracles checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.
See the other checks in Engine & OS oracles — the family js-engine-identifier-vs-ua belongs to.