Network signals (the first filter)
Before any JavaScript runs, the site already knows a lot from your IP address alone: its ASN (the network it belongs to — e.g. Amazon vs. a home ISP), its past reputation, and whether its location makes sense. Datacenter IPs (AWS, GCP, DigitalOcean) get almost no trust by default, because real users rarely browse from a server farm. Residential and mobile IPs start out neutral. IPs caught misbehaving before get blacklisted right at the edge. This one filter handles about 70% of low-effort scraping traffic before any fingerprinting is even needed.
Transport signals (TLS and HTTP/2)
Every https connection starts with a TLS handshake — the step where client and server agree on encryption. That handshake exposes a JA3/JA4 fingerprint: the list of cipher suites, extensions, and elliptic curves your client offers, in the exact order it offers them. Python's requests library has a JA3 that instantly says "not a browser." HTTP/2 adds more tells, like the order of frame priorities and headers. Real Chrome sends headers in a particular order; curl sends them differently. Anti-bot vendors keep catalogs of known automation-tool fingerprints and block anything that matches.
Browser signals (JS-collected)
If you make it past the network and transport filters, the page runs JavaScript that quietly inspects your browser. It checks things like the canvas rendering hash (the exact pixels your machine draws), the WebGL renderer string (your graphics hardware), an audio fingerprint, installed fonts, screen size, timezone, languages, the navigator.webdriver flag, and dozens more. Faking any one of these is easy; the hard part is making them all agree with each other. A spoofed canvas paired with a real WebGL value is actually a stronger bot signal than either one alone, because the mismatch gives you away.
Behavioral signals (the last layer)
Once the page loads, the site watches how you act: mouse movement, scrolling, how long you wait before clicking, and how fast you fill in forms. Real people move the mouse in jittery, curved paths, scroll in bursts, and pause at random. Scrapers either skip all of this (no mouse event ever fires) or fake it in patterns that machine-learning models recognize with high confidence. This is the layer that catches headless browsers — automated browsers with no visible window — that pass every static fingerprint check.
A worked example — what a single request reveals
Take one GET request to an Akamai-protected site from a plain Python requests script. Here is what each layer sees:
| Layer | What's observed | Verdict |
|---|---|---|
| Network | JA4 hash matches Python urllib3, not Chrome | Bot |
| Transport | No HTTP/2 — connection negotiates HTTP/1.1 | Bot |
| Headers | Accept-Encoding: gzip, no Accept-Language, User-Agent claims Chrome | Incoherent — bot |
| IP | AWS us-east-1 datacenter ASN | Bot |
| JavaScript | No script execution — sensor.js never ran | Bot or non-browser |
Every layer independently flags this as a bot. Akamai returns a 412 status with the Pardon Our Interruption page, the _abck cookie stays stuck at ~-1~ (its "not verified" state), and any protected XHR endpoints refuse to work because of that cookie. The bot was already caught at the TLS handshake — every layer after that just confirmed it.
Now run the same request with curl_cffi + Chrome impersonation + an ISP residential proxy: the JA4 matches a real Chrome, HTTP/2 works, the headers line up, and the IP looks residential. The same endpoint now returns 200. Nothing changed except the network-layer fingerprint.
How this is shifting in 2026
Three trends are reshaping how detection works:
- JA4 has fully replaced JA3 across major vendors. Matching only an old JA3 profile now produces a "wrong-shape Chrome" signal, because vendors check both.
curl_cffi,utls, andtls-clientall support JA4 — there is no reason to be stuck on JA3 in 2026. - WASM challenges are now standard at the enterprise tier. WASM is compiled code that runs in the browser, harder to inspect or fake than plain JavaScript. DataDome's
boring_challengeshipped in 2023; Akamai and PerimeterX added WASM probes through 2024. These can no longer be addressed at the JavaScript layer (see the WASM fingerprinting entry); handling them has moved down into the browser engine itself (Camoufox, CloakBrowser). - Behavioural signals are tracked per-session, not per-request. Vendors now collect clicks, scrolls, and timing across a whole session and score the overall pattern. A single request with a flawless fingerprint can still get flagged by your behavior on request 50. The fix is realistic pacing and warm-up over time, not a perfect one-off fingerprint.
What hasn't changed: the cost ranking of fixes. Network-layer fixes are still the cheapest, behavioural fixes still the most expensive. Move up the layers only as the one below stops working.
