Overview
Automation scoring is a separate concern from consistency scoring. Consistency catches anti-detect browsers that spoof signals to look like a real human. Automation catches drivers that just need to work and do not try to hide.
The two evidence sets barely overlap: a stealth-wrapped Puppeteer instance can still trip automation checks even when its consistency surface looks clean, and an anti-detect browser can trip consistency without leaving any driver footprint at all. Backend rules should consume both buckets independently.
The result is an AutomationResult attached to FingerprintResult.automation and DeviceIdResult.automation. It exposes a normalised score, a list of fired flag names, and a bucketed automationLikelihood of 'low' | 'medium' | 'high'.
// AutomationResult shape (src/types.ts)
interface AutomationResult {
score: number; // 0.0 to 1.0
flags: string[]; // names of fired checks
automationLikelihood: 'low' | 'medium' | 'high';
}
// Defensive fallback: a broken check is treated as passing.
// If anything in the automation pipeline throws, the result is:
return { score: 1.0, flags: [], automationLikelihood: 'low' };Exact check count, score formula, threshold map, and per-check internals are deliberately not published. Treat automationLikelihood as the stable interface; the underlying check set evolves between releases.
What is checked, at a glance
Checks cover several independent surfaces: standard WebDriver leaks required by the W3C spec, headless-mode artefacts (UA strings, software renderers), CDP traces from Chromium's DevTools Protocol, Playwright binding residue, stealth-patched native functions and their self-reflection failures, and structural anomalies in window and navigator state that headless modes historically expose.
Specific check names, the exact thresholds that map flag counts to likelihood buckets, the internal globals or descriptor probes used, and which checks are sync vs async are not part of the public contract. Some checks have a wider blast radius than others; consumers should not assume any single flag is load-bearing.
Brave-aware false-positive suppression
Brave private windows alter a small number of Chromium globals in ways that overlap with stealth-wrapper signatures. When Brave is confirmed by the consistency pipeline, automation scoring suppresses the one or two Brave-only false positives so a normal Brave session does not read as automation.
Real automation evidence on Brave (driver artefacts, headless GPU strings, Playwright bindings, stealth-patched natives, structural anomalies) all still surface through the unsuppressed portion of the check set. The suppression is scoped and additive — never broad enough to mask a real driver.
Things worth knowing
- If the automation pipeline throws an uncaught error, it returns { score: 1.0, flags: [], automationLikelihood: 'low' }. A broken check is treated as passing so that an internal bug cannot break the fingerprint result.
- Cross-browser coverage is uneven. Driver detection is strongest on Chromium-derived browsers; coverage on Firefox- and WebKit-based automation is intentionally narrower because the most reliable signals are Chromium-specific.
- Flag names are exposed as opaque strings for telemetry. Consumers should forward them to their backend and key business rules off automationLikelihood, not off individual flag names — the set evolves between releases.
- The automation check set is tuned to catch the deployment shape rather than any one tool. A stealth-wrapped automation stack typically forges some of the checked surfaces but leaves others intact; redundancy across vectors is the point.
Last reviewed 2026-06-04

