← Back to blog

9 Headless Browsers Tested Against Three-Phase Bot Detection

detect-botbot-detectionheadless-browsersfingerprintingbehavioral-analysis
9 Headless Browsers Tested Against Three-Phase Bot Detection

The detect-bot project runs three detection phases: static browser fingerprinting (Phase 1), environment consistency cross-referencing (Phase 2), and behavioral interaction analysis (Phase 3). A test harness ran 9 headless browser configurations through all three phases against the live detect-bot test page. Chrome 148 was installed on the test server to remove binary-availability as a variable.

Browser Engine Phase 1+2 Phase 3
Vanilla Playwright Chromium 0/100 BOT 100/100
Stealth Playwright Chromium 0/100 BOT 100/100
Full Stealth Playwright Chromium 0/100 BOT 100/100
Patchright 1.60 Chromium 0/100 BOT 100/100
nodriver 0.50.3 Chromium CDP -35/100 BOT 100/100
SeleniumBase UC 4.49 Chromium UC -20/100 BOT 100/100
CloakBrowser 0.3.31 Chromium 146 30/100 SUSPICIOUS 100/100
Camoufox 0.4.11 Firefox C++ 35/100 SUSPICIOUS 100/100
invisible-playwright 0.2.0 Firefox 150 35/100 SUSPICIOUS 100/100

Phase 1 Signal Breakdown

Signal Vanilla Stealth Full St. Patchright nodriver SB UC Cloak Camoufox invis.pw
navigator.webdriver true patched patched true true true false ✓ false ✓ false ✓
navigator.plugins 0 0 5 ✓ 0 5 ✓ 5 ✓ 5 ✓ 5 ✓ 5 ✓
window.chrome missing missing missing missing missing missing 3 keys ✓ N/A N/A
chrome.runtime missing missing missing missing missing missing missing N/A N/A
performance.now() sub-ms ✓ integer integer sub-ms ✓ integer sub-ms ✓ integer integer integer
Stack trace clean ✓ eval origin eval origin clean ✓ clean ✓ clean ✓ eval origin clean ✓ clean ✓
Notification.permission denied denied denied default ✓ default ✓ denied denied denied denied

Phase 2 Signal Breakdown

Signal Vanilla Stealth Full St. Patchright nodriver SB UC Cloak Camoufox invis.pw
GPU Renderer ANGLE ✓ ANGLE ✓ SwiftShader ANGLE ✓ ANGLE ✓ ANGLE ✓ RTX 4060 ✓ spoofed ✓ spoofed ✓
GPU vs UA Platform match ✓ match ✓ macOS + SwShader match ✓ match ✓ match ✓ match ✓ match ✓ match ✓
Timezone vs Locale match ✓ match ✓ match ✓ match ✓ UTC + en-US match ✓ UTC + en-US UTC + en-US UTC + en-US
Language Depth 2+ ✓ 2+ ✓ 2+ ✓ 2+ ✓ 2+ ✓ 2+ ✓ single 2+ ✓ single
Browser Chrome present ✓ present ✓ present ✓ present ✓ missing present ✓ present ✓ present ✓ present ✓
Viewport 1280 ✓ 1280 ✓ 1280 ✓ 1280 ✓ 780×580 1280 ✓ 1280 ✓ 1280 ✓ 1280 ✓

Phase 3 behavioral scores were 100/100 across all browsers. Playwright's .click() and .type() methods generate proper mousemove and keydown events - the behavioral phase is designed to catch AI agents that teleport to click coordinates and paste-fill forms, not CDP-based automation that moves the cursor.

Phase 1+2: Static Fingerprints

Phase 1 checks the browser's JavaScript surface - navigator.webdriver, plugin arrays, window.chrome object, performance.now() precision, stack trace analysis, and DevTools Protocol detection. Phase 2 cross-references environment signals - does the GPU renderer match the reported platform? Does the timezone match the locale?

The Playwright variants, Patchright, nodriver, and SeleniumBase all scored in the BOT range. The three Chromium-based Playwright variants hit 0/100 on navigator.webdriver=true (vanilla), a detectable undefined override plus empty plugins (stealth), and SwiftShader GPU on a macOS user agent (full stealth). Patchright showed the same detection surface.

nodriver scored -35/100 with flags on navigator.webdriver, integer-only performance.now(), no browser chrome, a viewport mismatch (outer 780×580 vs inner 780×493 from a missing window frame), and UTC timezone. SeleniumBase UC's undetected-chromedriver mode only reached -20/100 - navigator.webdriver remained true in the CDP connection, window.chrome was missing, and Notification.permission defaulted to denied.

CloakBrowser (Chromium 146, 57 patches), Camoufox (Firefox fork, C++ level patches), and invisible-playwright (Firefox 150, 1,089 GitHub stars) reached 30-35/100. All three escaped the BOT verdict but couldn't hide from the signal combination. CloakBrowser spoofed the GPU to an NVIDIA RTX 4060 - passing the Phase 2 GPU consistency check - but its single language entry, eval-origin stack traces, integer-only performance.now(), and UTC timezone accumulated penalties. Camoufox and invisible-playwright tied at 35/100 - both Firefox forks with similar detection profiles: integer performance.now() timing, UTC timezone with regional English locale, and Notification.permission set to denied. invisible-playwright patches navigator.webdriver and the GPU renderer at the Firefox 150 source level but can't hide from OS-level timing and timezone signals.

Phase 3: Behavioral Analysis

Phase 3 tracks mouse movement continuity, scroll patterns, and keyboard interaction timing - the techniques described in FP-Agent[^1], which achieved 0.9993 F1 on AI agent detection using behavioral signals alone. It checks for teleporting clicks (no mousemove within 250ms), scroll events arriving in discrete bursts with uniform intervals, and forms filled via paste events rather than keystrokes.

Every browser scored 100/100 on Phase 3. Playwright's .click() method moves the cursor to the target before clicking - it generates mousemove events. .type() fires keydown and keyup with realistic inter-key latency. The harness didn't scroll programmatically or paste-fill forms. Phase 3 is designed to catch AI agents - Operator, Claude Computer Use, Manus - that teleport to click coordinates and fill forms without generating intermediate events. None of the tested automation tools exhibit that behavior.

The Two Detection Surfaces

Phase 1+2 and Phase 3 target different automation styles. Playwright-style automation controls a real browser via CDP - it patches browser attributes to hide itself but moves the mouse, types keystrokes, and scrolls like a human. The behavioral layer sees a human. The static fingerprint layer sees a bot.

The anti-detection browsers (CloakBrowser, Camoufox, invisible-playwright) close the static fingerprint gap. They patch at the C++/source level so navigator.webdriver, plugins, and GPU renderer return realistic values. But they can't patch operating-system-level signals - performance.now() precision is a headless-mode artifact below the browser, and the system timezone is set by the host.

The FP-Agent paper showed that Cloudflare's browser fingerprinting caught 1 of 7 AI agents tested. Behavioral analysis caught all 7. Those agents ran on real Chrome with human-like browser fingerprints - Phase 1+2 would have passed them. The behavioral signals - teleporting clicks, paste-only form fills, absent scroll movement - were the only reliable detector.

For detect-bot, the three-phase approach means different detection layers catch different automation tiers. Phase 1+2 catches tooling that patches browser attributes but can't hide from OS-level signals. Phase 3 catches AI agents that bypass fingerprint checks but can't fake continuous mouse movement. A browser that clears Phase 1+2 is a partially-patched automation tool - CloakBrowser, Camoufox, or invisible-playwright. A browser that clears Phase 3 is Playwright or an AI agent running on real Chrome. The combination narrows the evasion space.

[^1]: Ethan Wang, Zubair Shafiq, Yash Vekaria. "FP-Agent: Fingerprinting AI Web Agents Through Browser Automation Traces." arXiv:2605.01247, May 2026.

Termagotchi
_

Ryan Underdown

Autodidact. Rarely listens to advice.

Follow on X @catamarammed or GitHub @underdown