the stack notices how deep the call chain actually was
Check id error-stack-depth-fidelity
What an ordinary browser yields
With the frame limit raised and confirmed, calling sixteen levels deeper produces exactly sixteen more frames.
What a detector infers
DataDome's bytecode VM does something small and sharp: new Error(), read .stack, fold a hash over the text — we can read the exact opcodes, including its fallback to an empty string for engines that have no stack at all. So the shape of that string matters to a detector, which makes rewriting it tempting. This check does not compare your stack to anyone else's, because there is nothing to compare it to. It calls a function four levels deep, then twenty levels deep, and checks that the stack noticed the sixteen extra calls. The ground truth is generated at runtime — we know exactly how many calls we made — so there is nothing to maintain and nothing that can go stale. A real stack always notices; a canned string never does. The subtlety here is the one that nearly shipped as a bug, and it is worth knowing if you ever write this test yourself: V8's default Error.stackTraceLimit is 10, so the frame count SATURATES. Measured on a stock Chrome, depth 4 gives 8 frames and depth 20 also gives... 10. The naive form of this check — deeper chain means more frames — therefore computes a difference of 2 rather than 16 and accuses every unmodified Chrome on earth. Only after raising the limit AND confirming by reading it back does the response become linear: the same browser then reports 8 frames at depth 4 and 24 at depth 20, a difference of exactly 16. A difference between 1 and 15 is reported without being counted, because engines legitimately elide inlined frames and that behaviour does not get to accuse anyone.
How to resolve it
Error.stack is generated by the engine from the live call chain. A fixed or edited string satisfies anything that reads it once and fails the moment someone calls from a different depth and counts — which is cheap to do. There is no inexpensive way to fake this, which is the entire reason it is worth measuring.
Read in the wild by
DataDome
Its bytecode VM constructs a zero-argument Error, reads .stack, and folds a rolling hash over the text — with an explicit empty-string fallback for engines that expose no stack at all. The shape of that string is what reaches its server.
out.txt 0x491e-0x498f: GET_PROP_IMM "Error" -> NEW_U8 0 -> PUSH_IMM "stack" -> GET -> JNZ_KEEP with a PUSH_IMM "" fallback, then h=(h<<5)-h+c|0 over the string at 0x493f-0x498a
xKiian/datadome-vm — DataDome bytecode VM disassemblyEvery attribution traces to a published artifact. See the sources and their limits.
Other checks in Error subsystem
- every realm speaks the same error dialect
error-dialect-realm-agreementAn engine's error messages are a dialect hiding in plain sight. - the structured and string renderings of one call chain name the same frames
structured-stack-vs-string-stackChrome describes one call chain twice. Once as the human-readable string on Error.stack, and once as structured CallSite objects, through a… - a stack trace names the function it was thrown in
error-stack-livenessA stack trace is not a string, it is a measurement of the present moment — a function of who called whom, from what URL, at what column…
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 Error subsystem 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 Error subsystem — the family error-stack-depth-fidelity belongs to.