Bots and anti-detect browsers spoof browser signals to pass as real users. The primary detection layer is a cross-signal consistency check that spots incoherent signal combinations. This page covers the full architecture from signal capture to the challenge-or-deny decision.
The job
Automated browsers and anti-detect tools try to pass as genuine users. Bots aim for throughput: scraping, credential stuffing, account creation at scale. Anti-detect browsers aim for identity separation: each session presents a synthetic browser profile that looks plausibly human but is unrelated to the actual hardware. Both categories fail when the fingerprinting layer checks not just what signals are reported, but whether those signals are consistent with each other and with the reported browser environment.
For bot and anti-detect detection, the primary signal is `consistency.spoofLikelihood`, not the `hardwareFingerprint` hash. A real browser on real hardware produces signals that agree across subsystems: reported GPU matches canvas output, reported fonts match what layout actually measures, audio pipeline output matches the reported audio engine. A spoofed browser generates contradictions. This page covers the full architecture for reading that consistency score and applying the challenge-or-deny rule.
What the consistency signal measures
`getFingerprint` returns a `consistency` object alongside the fingerprint hashes. It contains `spoofLikelihood`, which is one of `'low'`, `'medium'`, or `'high'`. A `high` value means the collected signals show cross-subsystem contradictions consistent with a browser that is actively manipulating its reported environment. A `low` value means the signals are mutually coherent and match the expected fingerprint topology for the reported browser and platform.
The scoring covers three categories of checks: consistency checks (do reported values agree across browser subsystems?), automation checks (are automation-runtime tells present?), and incognito checks (are storage and quota values consistent with normal browsing?). The `spoofLikelihood` label summarises across all categories into one actionable tier. You do not need to inspect sub-scores to act on bot and anti-detect traffic.
The end-to-end flow
| Step | What happens |
|---|---|
| 1. Capture | On page load or at the action you want to protect, call getFingerprint() client-side. You get fingerprint, hardwareFingerprint, and consistency (including spoofLikelihood). No server involved yet. |
| 2. Send | POST the fingerprint hashes and the full consistency result to your backend over your existing API. Decide server-side: never trust a verdict computed in the browser. |
| 3. Store | Optionally persist { hardwareFingerprint, fingerprint, spoofLikelihood, firstSeen, lastSeen } keyed by hardwareFingerprint, so repeat offenders are flagged without recapturing. For pure bot detection, a session-scoped record is often enough. |
| 4. Look up | For the consistency check, the score is already in the payload. If you want to check whether this device has previously been flagged, query your store by hardwareFingerprint. Use compareFingerprints in cross-browser mode for a matchScore when a returning bot may have changed browsers. |
| 5. Decide | high spoofLikelihood: challenge or deny the request immediately. medium spoofLikelihood: apply step-up friction (CAPTCHA, email verification). low spoofLikelihood: allow through. |
| 6. Act and log | Challenge, deny, or allow. Log the spoofLikelihood and which category triggered it for tuning review. Update lastSeen if you maintain a device record. |
The decision rule
For bot and anti-detect detection, the decision rule is tiered on `spoofLikelihood` rather than on a count. Act on the label directly. The threshold for what constitutes `high` versus `medium` is determined by the cross-signal consistency scoring built into `getFingerprint`; you are consuming the output label, not setting internal cutoffs.
Bot and anti-detect gate by spoofLikelihood
| spoofLikelihood value | Recommended action |
|---|---|
| 'low' | Signals are mutually coherent. Treat as a genuine browser session and allow through. |
| 'medium' | Some inconsistency detected. Apply step-up friction: CAPTCHA, rate-limit, or require email verification before continuing. |
| 'high' | Strong cross-subsystem contradiction. Challenge with a hard gate or deny the request outright. Log for audit. |
| Any value on a device already flagged 'high' in a prior session | Persistent offender: deny immediately and escalate to IP-level block or account suspension. |
npm install doorman-bennyimport { getFingerprint } from 'doorman-benny';
// STEP 1-2: capture in the browser, send hashes and consistency to your backend.
async function submitAction(actionPayload: Record<string, unknown>): Promise<void> {
const result = await getFingerprint();
await fetch('/api/action', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...actionPayload,
hardwareFingerprint: result.hardwareFingerprint,
fingerprint: result.fingerprint,
spoofLikelihood: result.consistency.spoofLikelihood,
}),
});
}Client side. Capture on any action you want to protect: signups, logins, form submissions, API calls. The consistency verdict arrives in the same getFingerprint() call as the hashes.
// STEP 3-6: optionally store, look up prior flags, and decide on the server.
// `db` is your own datastore, indexed by hardwareFingerprint.
async function evaluateAction(payload: {
hardwareFingerprint: string;
fingerprint: string;
spoofLikelihood: 'low' | 'medium' | 'high';
}): Promise<{ action: 'allow' | 'challenge' | 'deny'; reason: string }> {
// Check whether this device has a prior 'high' record.
const existing = await db.devices.findByHardwareId(payload.hardwareFingerprint);
if (existing?.lastSpoofLikelihood === 'high') {
return { action: 'deny', reason: 'persistent-offender' };
}
// Act on the current session's consistency label.
if (payload.spoofLikelihood === 'high') {
await db.devices.upsert({
hardwareFingerprint: payload.hardwareFingerprint,
fingerprint: payload.fingerprint,
lastSpoofLikelihood: 'high',
lastSeen: new Date(),
});
return { action: 'deny', reason: 'high-spoof-likelihood' };
}
if (payload.spoofLikelihood === 'medium') {
return { action: 'challenge', reason: 'medium-spoof-likelihood' };
}
await db.devices.upsert({
hardwareFingerprint: payload.hardwareFingerprint,
fingerprint: payload.fingerprint,
lastSpoofLikelihood: 'low',
lastSeen: new Date(),
});
return { action: 'allow', reason: 'low-spoof-likelihood' };
}Server side. The decision is driven by the spoofLikelihood label. Optionally store the label per device so repeat offenders are caught even if they suppress the consistency signal in a later session.
Which signals and which mode
For bot and anti-detect detection, the `consistency` field is the primary signal. The `hardwareFingerprint` is a secondary anchor: it lets you build a reputation store for devices that have previously been flagged, so a returning bot that has changed browser profiles still matches its prior high-spoof record.
If you also want to check whether a device that was flagged in one browser has returned in a different browser, use `compareFingerprints` in `cross-browser` mode against the stored record. A matching `hardwareMatch` result combined with a prior high-spoof record is strong evidence of a persistent automated actor.
For deeper reading on what the consistency and automation scores cover at a category level, see the /docs/scoring-consistency and /docs/scoring-automation reference pages.
Handling false positives
A `high` spoofLikelihood on a legitimate user session is rare but possible. Privacy-enhancing browser configurations (Brave's fingerprint randomization, for example) can raise the consistency score for genuine users. Two practices manage this.
First, route `high` results to a challenge rather than a hard deny wherever the product experience allows. A CAPTCHA or a brief email confirmation resolves the case for a genuine user while still blocking automated actors. Second, log the contributing category (consistency, automation, or incognito) alongside the spoofLikelihood label so your support team can triage appeals with context.
A `medium` result should almost never hard-deny. Step-up friction is the right response: it is proportionate for a genuine user and sufficient friction to deter most automated traffic.
Frequently asked questions
What is the difference between the consistency check and a CAPTCHA?
A CAPTCHA challenges the user to prove human intent. The consistency check runs silently and asks whether the browser's own signals are mutually coherent. They are complementary: use consistency scoring to decide whether to show a CAPTCHA, rather than showing one unconditionally.
Can a sophisticated bot pass the consistency check?
A bot running a real browser on real hardware with no signal manipulation will score low spoofLikelihood because its signals are genuinely coherent. The consistency check is most effective against browsers that substitute synthetic signal values to evade fingerprinting. Behavioral signals and rate limiting are complementary layers for fully real-browser bots.
Does Brave browser always produce a high spoofLikelihood?
No. The scoring includes Brave-aware suppression logic that prevents Brave's privacy features from systematically producing false-positive high scores on genuine Brave users. Medium results are more likely on Brave than on other browsers, but high results indicate additional anomalies beyond Brave's standard behaviour.
How should I handle the medium spoofLikelihood tier?
Step-up friction is the right response: a CAPTCHA, a rate limit, or an email verification request. A hard deny at medium is too aggressive for a live product and will affect genuine users. Medium is a signal to raise the cost of the action, not to block it outright.
Is this compliant with GDPR or ePrivacy?
Fingerprinting for fraud prevention generally qualifies for a security and fraud-prevention exemption under GDPR and most ePrivacy frameworks, provided the processing is proportionate and disclosed in a privacy notice. The laws/fingerprinting-anti-fraud-exemption page covers the landscape. This is engineering documentation, not legal advice.
Get started
Build the bot detection gate
npm install doorman-benny. Cross-signal consistency scoring, automation detection, and hardware-bound device identity in one package. No cookies required for the consistency check.
Last reviewed June 20, 2026

