Bot Detection API for Headless Browsers, Automation & AI Agents
Add browser automation, tampering and network evidence to your signup or login flow. Maskbreak returns available signals such as device.automation, reason codes and a decision. No CAPTCHA is built into the check; your application decides when extra verification is needed.
What you're up against
Headless browsers with stealth patches
Off-the-shelf stealth plugins scrub navigator.webdriver, fake plugin lists, and spoof WebGL strings, so the JavaScript checks most sites rely on come back clean. The framework underneath is still Puppeteer — but nothing in the request says so.
CAPTCHAs that only stop humans
Solver farms clear a CAPTCHA for fractions of a cent, and modern vision models solve them outright. What's left is a challenge that costs you real-user conversion while the bots pay a rounding error to walk through.
Rate limits that never fire
Bot fleets rotate through residential proxy pools, so every request arrives from a fresh, clean-looking IP. Per-IP throttles and geo rules see a thousand different visitors where there is one script in a loop.
AI agents that browse like people
LLM-driven agents type plausibly, wait between clicks, and follow multi-step flows — behavioral heuristics tuned for dumb scripts don't trip. The tell isn't the behavior anymore; it's the automated environment the behavior runs in.
What Maskbreak does for you
- Flag Puppeteer, Playwright, and Selenium sessions with
device.automationwhen automation evidence is found — test your own stealth setups against it - Flag emulators and virtual machines behind device farms with their own reason codes
- Correlate device signals with network origin: datacenter ASN, provider name, proxy and VPN flags in the same response
- Route on machine-readable reason codes —
automation_detected,emulator_detected,virtual_machine,datacenter_asn— instead of a black-box score - Server-side decision with reason codes — no built-in challenge pages or puzzle-solving
Scalper bots on limited inventory: the tell is a headless or automated browser flagged on the first request, before any rate pattern has built. A worked model, not a customer result.
Read Full Case StudyWhere the check goes
Put the check in front of whatever the bots are hammering: signup, login, checkout, or any form POST. The client snippet rides along in your page and collects device evidence; your server asks Maskbreak for a verdict before the protected action runs, and routes on the reasons array. The example starts in watch mode: it logs each verdict, lets every request through and fails open if Maskbreak is unreachable. After a few days, compare the log with the Events in your dashboard, then uncomment the enforce line; the integration guide has the full enforce checks.
// Score the request before the protected action runs // Watch mode first: log the verdict, always continue, fail open const body = req.body || {}; // sentinel.js adds monocle + sentinel_fp to your form let risk = null; try { const verdictRes = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', signal: AbortSignal.timeout(5000), headers: { 'Authorization': 'Bearer ' + process.env.MASKBREAK_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ token: body.token || body.monocle, // network evidence fingerprintEventId: body.fingerprintEventId || body.sentinel_fp, // device evidence tz: body.tz || body.sentinel_tz }) }); if (verdictRes.ok) risk = await verdictRes.json(); } catch {} // unreachable or timed out: your handler still runs console.log('[maskbreak]', JSON.stringify({ decision: risk?.decision ?? null, reasons: risk?.reasons ?? null, risk_score: risk?.risk_score ?? null, degraded: risk ? !!risk.degraded : null, automation: risk?.device?.automation ?? null })); // Enforce later: if (risk?.device?.automation) return res.status(403).json({ error: 'Request rejected' });
What an automated session looks like. This is an excerpt of the public sample response, which is built by the same function as a live /v1/evaluate call (the legacy fields are left out):
curl "https://maskbreak.com/v1/evaluate/sample?scenario=bot"
{
"sample": true,
"decision": "block",
"risk_score": 83,
"network": {
"vpn": false,
"proxy": false,
"datacenter": false,
"anonymous": false,
"tor": false,
"residential": true,
"service": null
},
"device": {
"antidetect": true,
"automation": true,
"emulator": false,
"virtual_machine": false,
"incognito": false,
"privacy_mode": false,
"ip_blocklisted": false,
"high_activity": false,
"visitor_id": "demo_visitor_a8c91b",
"tampering_score": 0.78
},
"reasons": ["antidetect_browser", "automation_detected"],
"evaluated_in_ms": 28
}The network is clean here: a residential address, no proxy. The device layer is what blocks it: device.automation is true (reason automation_detected), and the same session also tripped the fake-browser check (antidetect_browser). Either one blocks by default; virtual_machine on its own asks for review, never a block. When the device check could not run, the device object is missing rather than all false, so check for it before you treat a result as clean.
Don't take the docs' word for it — run your own connection through the live scanner on the homepage, or point a headless browser at it and watch the verdict flip. Both are keyless previews with a reduced signal set — the full API adds device intelligence and multi-account linking.
The signals that matter here
Automation frameworks, read below the patches. Stealth plugins rewrite the JavaScript surface that naive checks inspect — but the device layer reads the environment underneath: rendering quirks, timing characteristics, and low-level attributes that patched Puppeteer and Playwright sessions don't always fake consistently. When automation evidence is found, the response carries device.automation: true and the automation_detected reason code — a hard signal that blocks by default. The same layer covers the broader headless-browser landscape, from vanilla headless Chrome to hardened forks.
Emulators and VMs: where bot farms actually live. Scaled operations don't run on someone's laptop — they run on Android emulator grids and cloud-provisioned virtual machines. Maskbreak returns emulator_detected and virtual_machine as separate reason codes with separate weights: an emulator is a strong fraud tell, while a VM alone is soft evidence (developers and corporate VDI users live in VMs too), so the score reflects the difference instead of flattening both into "bot".
Datacenter-origin correlation. A lot of automation runs on cloud servers, so every verdict pairs the device evidence with network origin: network.datacenter, the hosting provider when known, and proxy/VPN/Tor flags — built on provider-published IP ranges refreshed daily, not a stale ASN dump. The correlation matters in both directions: a clean-looking browser POSTing from an AWS range is worth a second look, and an automation-flagged device on a residential proxy is still flagged — the device evidence doesn't wash off with a better IP.
Reason codes, not a black box. Every verdict ships the individual signals and a reasons array — automation_detected, emulator_detected, virtual_machine, datacenter_asn, proxy_detected — so your policy lives in your code, not ours. Block hard automation, send VM-only traffic to review, exempt your own monitoring: no CAPTCHA required at any point, which also means no conversion tax on the humans. That routing flexibility is what separates a usable bot signal from a score you have to trust blindly — especially against AI agents whose behavior looks human even when their environment isn't.
What this won't catch — honestly. No bot detection API stops everything, and vendors who claim otherwise are selling you a fairy tale. A human at a real browser doing the abusive work manually — a paid click farm, a CAPTCHA-farm worker walking through your flow — presents genuine human signals, because they are one; you catch those operations on volume patterns and multi-account linking, not automation flags. A brand-new framework can have a window before its artifacts are profiled. And the device layer needs the client snippet to run — a bot that only hits your raw API endpoints and never loads your page yields network signals (datacenter, proxy, blocklist) but no device verdict. Treat Maskbreak as one layer in a stack that still includes rate limits and business-logic checks, not a replacement for all of them.
Common questions
Put a real bot signal in front of your forms
Free plan: 10,000 visitor checks a month, no card. Paid plans from €29 a month. Flags automation, emulators, virtual machines and cloud-server origin on live visits.