Anti-Bot

What Is Call Stack Depth Fingerprinting?

What Is Call Stack Depth Fingerprinting? — conceptual illustration
On this page

Stack depth fingerprinting measures the maximum JavaScript recursion depth a browser allows before throwing a RangeError: Maximum call stack size exceeded. In plain terms: it counts how many times a function can call itself before the engine runs out of "stack" space - the limited area where JavaScript tracks calls that are still in progress, like a stack of plates that can only get so tall. That ceiling is decided by the engine (V8, SpiderMonkey, JavaScriptCore), the platform, the CPU architecture, and how much space the test function uses per call. Because the number comes from the real engine and OS - not from the User-Agent (UA), the browser-and-OS label a session claims - it is a cheap way to tell which engine is actually running, and it exposes tools that claim to be one browser while running another underneath.

Quick facts

MeasuresMax recursion depth before RangeError (Maximum call stack size exceeded)
Varies byJS engine, OS, CPU architecture, and the test function frame size
RevealsThe real engine - V8 vs SpiderMonkey vs JavaScriptCore
CatchesFirefox-based tools (Camoufox) presenting a Chrome User-Agent
VariantMeasured separately on main thread, Workers, and WASM

How the limit is measured

The test is short: write a function that bumps a counter and then calls itself, let it recurse until it crashes, and record the counter. That final number is surprisingly specific. V8 (Chrome), SpiderMonkey (Firefox), and JavaScriptCore (Safari) each set aside stack space differently and enforce different ceilings, so the depth falls into a distinct range for each engine. The exact value also shifts with CPU architecture (x86-64 vs ARM64), the operating system (default stack sizes differ), and how much space each call uses - so probes fix the function's shape (the number of arguments and local variables) to keep results comparable across runs.

Because the number is produced by the engine actually executing real instructions, you cannot move it from JavaScript - there is no property to overwrite; the limit is simply where execution genuinely runs out of room.

Why it catches engine spoofing

The most powerful use is catching tools whose engine does not match their claimed browser. Camoufox is Firefox under the hood; if it presents a Chrome User-Agent, its recursion depth lands in the SpiderMonkey range rather than the V8 range - an immediate contradiction. The same goes for any "Chrome" that is really something else, or a JavaScript runtime pretending to be a browser. Measuring the depth in several places - the main thread, a Web Worker (a background JavaScript thread), and WebAssembly (WASM, a lower-level code format browsers can run) - adds even more resolution, because the ratios between those contexts are also engine-specific.

This is one of a family of engine-level probes (alongside Math precision and WASM measurements) that read the real implementation instead of the advertised one. Because the limit is set inside the engine, the value reported by a session is consistent only when the engine actually running matches the browser it identifies as - for example a Chrome-based engine reporting a Chrome User-Agent; the depth is determined at the C++ level and cannot be altered from JavaScript.

Code example

javascript
// Measure max recursion depth (fix the frame shape for comparability)
function maxStackDepth() {
  let depth = 0;
  function recurse() { depth++; recurse(); }
  try { recurse(); } catch (e) { /* RangeError */ }
  return depth;
}

// Indicative ranges (vary by OS/arch/version - the engine clustering is the point):
//   V8 / Chrome           ~ 10k-15k
//   SpiderMonkey / Firefox~ different band
//   JavaScriptCore/Safari ~ different band
//
// A Chrome User-Agent whose depth lands in the SpiderMonkey band
// is a Firefox-based tool (e.g. Camoufox) wearing a Chrome UA.

Related terms

What Is Math & JS Engine Fingerprinting?
Math fingerprinting identifies a browser by running math functions (sin, cos, tan, exp, log, pow) on fixed inputs and reading the very last …
What Is WASM Fingerprinting?
WebAssembly (WASM) fingerprinting is a newer anti-bot technique that identifies a browser by measuring how its actual CPU behaves, instead o…
What Is Browser Fingerprinting?
Browser fingerprinting is a technique that identifies and tracks a visitor by combining dozens of small, observable characteristics of their…
What Is Fingerprint Lie Detection?
Fingerprint lie detection is the practice of verifying that the signals a browser reports are internally consistent and untampered, rather t…
What Is Camoufox?
Camoufox is a fork of Firefox with anti-fingerprinting patches applied at the C++ build level. That phrase matters: most anti-fingerprinting…
Anti-Bot Vendor Detection Cheatsheet
A useful first step when working with any protected site you are authorized to access is identifying which anti-bot vendor sits in front of …
What Is Anti-Bot Detection?
Anti-bot detection is the set of techniques websites use to tell automated traffic apart from real human visitors — and then block, challeng…
What Is Headless Browser Detection?
Headless browser detection is the set of probes anti-bot systems use to distinguish a headless or instrumented Chrome session from a real us…
How Browser Fingerprinting Works
Browser fingerprinting is how a site combines signals — canvas, WebGL, audio, fonts, navigator probes, TLS (the encryption layer behind http…
How Do Websites Detect Web Scrapers?
Websites spot scrapers by gathering hundreds of small clues about each visitor, then scoring how human the whole picture looks. No single cl…

Concept map

How Stack Depth Fingerprinting 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

Why does maximum recursion depth differ between browsers?

Because it is set by the JavaScript engine and the operating system, not by the browser brand. V8, SpiderMonkey, and JavaScriptCore reserve stack space and enforce limits differently, and the value also shifts with CPU architecture and how much space each call uses. As a result, the depth clusters by the real engine running - which is exactly what makes it a fingerprint.

Can I spoof my stack depth from JavaScript?

No. The limit is a consequence of how the engine actually executes code - there is no property to overwrite, and no way to make recursion fail at a different point without changing the engine itself. That is precisely why it catches tools whose underlying engine differs from the User-Agent they advertise.

How does stack depth catch Camoufox?

Camoufox is a Firefox fork, so its recursion depth falls in the SpiderMonkey range. If it presents a Chrome User-Agent, that depth contradicts the range V8 (Chrome's engine) would produce, revealing a Firefox engine hiding behind a Chrome identity. Measuring depth separately on the main thread, in Web Workers, and in WASM adds further engine-specific detail.

Last updated: 2026-05-31