← The blog
Technical

TLS fingerprinting (JA3/JA4): why a scraper gets flagged

08/28/2026 · 8 min read · by WyndPath
TLS fingerprinting (JA3/JA4): why a scraper gets flagged

You polished your scraper. The User-Agent of a real Chrome, perfect headers, a nice residential IP. And yet the server answers 403 before it even serves a single line of HTML. What gave you away happens one layer below everything you usually control: in the TLS handshake, the very first thing a client sends over HTTPS.

What happens before HTTP

When a client opens a secure connection, it starts with a message called the ClientHello. This message goes out in the clear, before any full encryption, and before a single HTTP header. It announces the client's technical capabilities:

The key point: this list and its order vary depending on the software library that establishes the connection. The Chrome on your machine, Firefox, Python's requests library or curl don't negotiate TLS the same way. Each has its own way of introducing itself.

From signature to hash: JA3

In 2017, engineers at Salesforce had a simple idea. Since the ClientHello is stable and characteristic, why not turn it into a fingerprint. The method, named JA3, takes five fields from the message, strings them together, and computes a hash. The result is a short string that identifies the way TLS is negotiated, and therefore the real software behind the connection.

The server doesn't take your word for it. It computes your TLS fingerprint and compares it to the ones it knows.

Python's requests library produces a fingerprint that is immediately recognizable as non-browser. It doesn't matter that your User-Agent proudly displays "Chrome": if the TLS fingerprint says "Python", the server sees the contradiction and raises its suspicion score.

What the server compares
The identity announced in the headers, against the real way TLS is negotiated.
Real browser Announced header: "Chrome" Real TLS fingerprint: Chrome consistent ✓ Naive scraper Announced header: "Chrome" Real TLS fingerprint: python-requests contradiction ✗

Why JA3 gave way to JA4

In 2023, Chrome introduced a change: the order of the extensions in the ClientHello is now randomized on every connection. Good practice from a security standpoint, but with an immediate side effect: a real Chrome's JA3 fingerprint became different on every session, making the signal unusable.

The answer was JA4, a new method that sorts the elements before hashing them. The fingerprint becomes stable again, despite the randomization. In 2026, the switch from JA3 to JA4 is nearly complete across all the major protection vendors.

A detail that changes everything. The TLS fingerprint stays the same even when you change IP address. Spinning up a thousand proxies is therefore pointless if the thousand connections present the same script fingerprint. You're correlated and blocked despite the rotation.

And it doesn't stop at TLS

Once the encrypted connection is established, another layer takes over: the HTTP/2 protocol. Here too, the way the dialogue opens is characteristic, notably the order of the pseudo-headers and certain technical parameters. A strictly alphabetical header order, for example, is a classic signature of an automated client that no real browser produces.

The lesson for anyone collecting data

The conclusion is a little counterintuitive. People often think that scraping cleanly is a matter of proxies and well-copied headers. In reality, the real issue is end-to-end consistency. Everything has to tell the same story:

Reproducing this consistency by hand is endless work, because the reference fingerprints change with every browser version. That's the whole point of a service like WyndPath: to present, on every request, a complete and consistent signature, without you having to chase the latest version of Chrome. You request a URL, you receive the page, within the rules published by the site.

Sources · Scrapfly, JA3/JA4 guide and HTTP/2-HTTP/3 fingerprinting (2024-2026) · Salesforce, JA3 specification (2017) · Documentation on extension randomization in Chrome (2023) · Evomi, HTTP/2 and HTTP/3 fingerprinting.

Collect this data without getting blocked

WyndPath handles proxies, JavaScript rendering and anti-bot bypass in a single API call. Pay-per-success.

Start for free →
Read also · Data
What share of web traffic is generated by bots?
Read also · Technical
How anti-bot systems work