We instrumented headless Chrome with a universal API interceptor and pointed it at 20 different bot detection products. Then we counted every call their JavaScript made.
The result is a per-vendor map of how each one decides whether you are a human or a script. No marketing claims. No vendor disclosure. Just the JavaScript they actually run on your browser.
This post summarizes the findings. The full raw dataset (per-signal call counts for all 20 vendors) is in our internal research repo and available to customers on request.
Method
We built a generic vendor_re_interceptor.js that wraps every window, navigator, document, screen, performance, WebGL, Canvas, Speech, and Permissions API. The wrapper counts every read of every property and every method call.
We injected it into a headless Chrome (Playwright, datacenter IP, Paris) before any vendor script ran. Then we visited a target site protected by each vendor and let the page load fully. Every call the vendor's JavaScript made was logged with the stack trace.
Some vendors do most of their detection in obfuscated WebAssembly or encrypted sensor payloads. We can count what their JS reads and how big the payload is, but we cannot decode the payload itself. Where this matters, we say so.
The Five Detection Philosophies
The 20 vendors cluster into a small number of fundamentally different approaches. Most teams mix them, but each vendor has a dominant style.
1. Timing Flood
Hammer performance.now() and Date.now() 5,000 to 37,000 times during page load. Real browsers have micro-jitter from OS scheduling, VM clock drift, and CPU throttling. Headless browsers and instrumented Chrome have suspiciously smooth timing. Vendors: F5 Shape, Vercara, Akamai, Sucuri, Imperva ABP, DDoS-Guard, Fortinet.
2. Deep Fingerprint
Build the widest possible device profile in few total calls. PerimeterX is the extreme example: 91 unique signals across WebGL (25 parameters), canvas, speech synthesis voices, permissions, screen geometry, and document visibility, with only 276 total calls. Vendors: PerimeterX / HUMAN, DDoS-Guard, Check Point.
3. UA Obsession
Re-read navigator.userAgent hundreds of times per page. Radware tops the chart at 505 reads. Imperva is next at 286. The point is tampering detection: if the UA changes between two reads, the bot has hooked the property and is caught. Vendors: Radware, Kasada, Imperva ABP, GCP Cloud Armor, Sucuri.
4. Event / Interaction Analysis
Watch listener registration for click, keydown, focus, touchstart, scroll. Not the events themselves - whether the page set up the listeners at all. A bare scripted request sets up zero. Lumen registers 1,010 click listeners just on its detection page. Vendors: Lumen, Gcore, Citrix, Check Point.
5. Network-Layer
Almost no JS. The real detection happens at the TLS layer (JA3/JA4 fingerprint), HTTP Client Hints (sec-ch-ua), Accept-Language vs site locale, and IP reputation. DataDome ships 21 total JS calls. Vendors: DataDome, Azure Front Door.
A sixth style exists: challenge-based (Cloudflare, AWS WAF). Both ship a lightweight proof-of-work JavaScript puzzle and lean on IP reputation. Cloudflare's main fingerprinting effort is the managed challenge itself, not deep property probing.
The Heavyweights
Five vendors stand out for the depth and aggression of their detection. The numbers below are from a single page load on the target site.
F5 Shape Security - the timing king
The heaviest fingerprinter we measured. Shape's Date.now() call count alone is 27,173. That is one timer read every microsecond of page load. They use the resulting jitter histogram to detect headless timing artifacts.
They also collect 46 canvas getContext(2d) calls (canvas fingerprint), 15 plugin enumerations (headless Chrome has zero plugins), and ship 9 encrypted sensor payloads back to their endpoint, ~16 KB each. The payloads are binary and obfuscated; we cannot read them without decompiling the loader JS.
Bypass status: single-request recon passes with stealth bundle. Sustained load behind Shape's sensor_data validation is the hardest of any vendor.
Akamai Bot Manager - most-deployed
Akamai's p.js (~130 KB) is the most widely deployed bot detection script on the internet. It floods performance.now() (10,080 calls), watches for touch/mouse/keyboard listener registration, and reads navigator.webdriver twice. It posts a 16,896-byte encrypted sensor payload to the /tl endpoint.
At passive recon rates (we tested 15 requests over 60 seconds), Akamai does not escalate. The bot manager session is cookie-tracked via ak_bmsc and bm_sv.
Bypass status: 42 of 45 Akamai-protected targets in our scan corpus pass with stealth bundle. No escalation observed at recon rates.
PerimeterX / HUMAN - widest surface, one-shot trap
PX builds the most complete device profile of any vendor we measured, but does it in only 276 total calls. They read 25 distinct WebGLRenderingContext.getParameter values (max texture size, viewport dims, shader precision, aliased line widths), three different canvas renderings, speech synthesis voice lists, notification permission state, the new navigator.pdfViewerEnabled, and document.hidden eleven times.
What makes PX dangerous for sustained access is the escalation. The first request comes back 200 with content. The second request from the same IP comes back 403 with a "Press & Hold" challenge. The IP is permanently flagged. New browser contexts from the same address do not help.
Bypass status: single-request recon works. Sustained access requires residential proxy rotation.
Imperva Advanced Bot Protection - ABP one-shot trap
Imperva's signature is the ___utmvc cookie. The detection style combines heavy timing (5,350 performance.now calls) with extreme UA polling: 286 navigator.userAgent reads in a single page load. The window.chrome object gets probed 10 times because it is missing in headless Chrome.
Like PX, ABP runs a one-shot trap. The first visit produces a 200 with the fingerprint payload. The second visit is 403, permanently. Cookies set: ___utmvc (ABP active), reese84 (device fingerprint), visid_incap_*, nlbi_*.
Bypass status: single-request recon passes 5 of 5 ABP targets with stealth bundle (webdriver=false, realistic plugins list, performance.now jitter injection, chrome runtime object). Sustained load not yet tested behind a paid ABP tenant.
DataDome - the network-layer outlier
DataDome ships 21 JS API calls per page load. The 14 KB captcha-delivery.com/c.js file is the CAPTCHA renderer. The real detection happens before any JS runs: JA3/JA4 TLS fingerprint, sec-ch-ua Client Hints, Accept-Language vs site locale, and IP reputation.
Bypass status: passes when the TLS fingerprint and Client Hints match a real browser and the locale matches the target site. Fails on datacenter IP reputation regardless of JS profile.
Full Leaderboard
All 20 vendors, ranked by total JS API calls per page load.
| Rank | Vendor | Signals | Calls | Dominant Style |
|---|---|---|---|---|
| 1 | F5 Shape | 82 | 37,540 | Timing flood + canvas |
| 2 | Vercara (Neustar) | 55 | 26,004 | Timing flood + events |
| 3 | Akamai Bot Manager | 69 | 11,088 | Timing + encrypted sensor |
| 4 | Sucuri | 38 | 11,056 | Timing flood |
| 5 | DDoS-Guard | 83 | 7,128 | Wide fingerprint + timing |
| 6 | Imperva ABP | 54 | 6,599 | Timing + UA obsession |
| 7 | Fortinet (FortiWeb) | 29 | 5,199 | Pure timing (95%) |
| 8 | Kasada | 49 | 4,203 | UA polling + timing |
| 9 | AWS WAF | 44 | 3,939 | Client Hints + events |
| 10 | Radware Bot Manager | 39 | 1,843 | UA obsession + keystrokes |
| 11 | GCP Cloud Armor | 38 | 1,572 | UA + screen dimensions |
| 12 | Lumen (CenturyLink) | 28 | 1,504 | Pure event monitoring |
| 13 | Fastly (Signal Sciences) | 30 | 1,226 | Tab visibility + timing |
| 14 | Check Point CloudGuard | 70 | 1,215 | Wide but shallow |
| 15 | Gcore | 34 | 1,211 | Click pattern analysis |
| 16 | Cloudflare | 38 | 1,140 | JS challenge (not FP) |
| 17 | Citrix (NetScaler) | 37 | 512 | Interaction patterns |
| 18 | PerimeterX / HUMAN | 91 | 276 | Deep device fingerprint |
| 19 | Azure Front Door | 12 | 54 | Network-layer (minimal JS) |
| 20 | DataDome | 8 | 21 | Network-layer (no JS) |
Total calls is not the same as detection quality
PerimeterX detects more than F5 Shape with one hundred and thirty times fewer calls. DataDome detects most automated traffic with no JS fingerprinting at all. Volume measures one philosophy - not the others.
The Escalation Traps
Not every vendor escalates the same way. Two of them spring a trap on the second request from the same IP. Understanding which vendor you are dealing with changes the whole reconnaissance strategy.
| Vendor | Escalation Behavior | Recovery |
|---|---|---|
| F5 Shape | Gradual (sensor_data validation) | Unknown, likely cookie + session |
| Akamai | No escalation at <15 req/min | Cookie-based (ak_bmsc) |
| PerimeterX | One-shot trap - 2nd request = 403 | IP permanently flagged |
| Imperva ABP | One-shot trap - 2nd request = 403 | IP permanently flagged |
| Kasada | Unknown | Unknown |
| Radware | No escalation observed | Cookie-based session |
| Cloudflare | JS challenge, then cf_clearance | Cookie valid ~30 min |
| DataDome | Immediate block if TLS/headers wrong | No recovery without fix |
What This Means If You Are Testing Your Own Stack
If you are running a security assessment against your own properties, the vendor in front of each asset changes what you should test.
Against PX or Imperva ABP - rotate before the second request
Both run a one-shot trap. A test that fires three requests from the same IP will get a 403 on requests two and three regardless of whether the protection actually catches the first one. Always rotate egress IPs between probes, or you are measuring rate limits you cannot bypass instead of bot detection you might.
Against F5 Shape - the sensor_data is the gate
Shape's encrypted sensor payload is the real detection. Passing the JS fingerprint without producing a valid sensor_data POST means the request reaches your origin and reports a "low-confidence" verdict to Shape's cloud. We have seen these requests blocked at the second hop even when the first 200 came back.
Against Cloudflare - the challenge is the test
Cloudflare's bot mitigation is the managed challenge, not the property probing. If your testing harness solves the challenge once and reuses cf_clearance, you are testing CF less than you think. Strip the cookie and re-probe each origin.
Against DataDome - fix the TLS layer first
If your test harness uses requests or aiohttp, you will be blocked at the JA3 layer before any JS runs. Switch to a TLS client that emulates Chrome 12X (we use tls_client; curl_cffi works too). Then verify the sec-ch-ua Client Hints in your requests match the user agent. Then test detection.
What This Means If You Are Building Detection
If you are on the defensive side, the 20-vendor map suggests a few things that consistently work and a few that do not.
Timing analysis is the most common signal - and the easiest to spoof
Seven of twenty vendors lean primarily on timing. The standard bypass is to inject Gaussian noise into performance.now and Date.now before the vendor script reads them. A defender who relies only on timing is solving a problem that has had a known fix for years.
One-shot traps catch sustained attackers, miss the recon
The PX / Imperva pattern catches anything that automates more than one request from the same address. It is excellent against scrapers and credential-stuffers. It is useless against the first request, which is what an offensive recon engineer actually needs to characterize your stack. If the goal is to be unreachable to attacker reconnaissance, a one-shot trap does not get you there.
Network-layer detection is the cheapest win
DataDome and Azure Front Door catch most automated traffic with eight to twelve signals because the TLS layer and HTTP Client Hints are hard to spoof correctly. sec-ch-ua consistency with the User-Agent string is a one-line check that excludes the vast majority of scripted clients without any JS fingerprinting at all.
WebGL parameter diversity catches what timing misses
PerimeterX is the only vendor in our sample that probes 25 distinct WebGL parameters. The combination of GPU vendor string, max texture size, max viewport, and shader precision varies enough across real devices to make spoofing brittle. Most bypass bundles spoof three or four WebGL params and miss the rest.
Vendor selection is an instrumentation choice, not a coverage choice
Every vendor in the top ten can be bypassed in single-request mode by an attacker with budget. The difference between them is what they catch under sustained load and how cleanly the operations team can investigate the alerts. Pick the one whose telemetry your team will actually read.
How We Tested
- Browser: Playwright + headless Chrome 12X.
- Egress: Dedibox datacenter, Paris. Single static IP per session.
- Interceptor:
vendor_re_interceptor.jsinjected viapage.addInitScript()before any vendor JS could run. - Targets: one production site per vendor where the vendor's protection was confirmed via response headers or known cookie signatures.
- Measurement: per-signal call counts captured from a single full page load, exported as JSON, deduplicated by API name.
- Limits: we did not decode encrypted sensor payloads. We did not test sustained load on most vendors. We did not have access to paid vendor tiers (ABP, Bot Manager Premier, AWS WAF BotControl Targeted, CF Business). Where those tiers might change the result, we say so.
The full dataset is internal. If you are a CISO at a company using one of these vendors and want the per-signal breakdown for your stack, send us a note - we are happy to share.
Free External Scan
DDactic maps the bot detection vendor on every public asset you own. Five minutes, no login required.
Get Free Scan