"TLS Fingerprinting: The Layer Harder to Fake Than Browser Fingerprinting"
JA3/JA4 fingerprints hide in TLS handshake messages — JavaScript cannot reach them and anti-detect browsers cannot change them. The principles, the algorithms, and what they mean in practice, with a free online check.
When people hear "fingerprint detection", most think of Canvas, WebGL, fonts — browser traits that all live within JavaScript's jurisdiction, where disguise tools can reach them. But one layer of the fingerprint system hides deeper — the TLS handshake fingerprint. It sits in the very first message of an HTTPS connection and reveals "what software you are" before any page content loads and any script executes.
ClientHello: The First Sentence That Gives You Away
The first step when a browser establishes an HTTPS connection is sending a plaintext message called ClientHello, which contains:
- Supported TLS protocol versions (1.0 / 1.1 / 1.2 / 1.3)
- The supported cipher suite list — and its order
- The elliptic curves (supported_groups) and signature algorithm lists
- The extension list — and its order (SNI, ALPN, key_share…)
Different software hard-codes entirely different lists — Chrome's combination and ordering are its own, Safari's is another, and Python's requests, Go's net/http, and curl all differ. These lists are hard-coded in each program's TLS library and cannot be modified by the user or by web scripts.
JA3 and JA4: Turning the First Sentence into a Fingerprint
JA3 (2017, Salesforce) works in a blunt way — concatenate the five fields above into a string in a fixed format and take the MD5. A typical curl client's JA3 string looks like:
769,4867-4866-4865-...,43-51-11-10-13-16,29-23-24-25,0
A server obtains this fingerprint after a single handshake and can compare it against its database.
JA4 (2023, FoxIO) upgrades JA3's weak spots — JA3 is sensitive to extension order, so a modern client that deliberately shuffles its order breaks the JA3 match. JA4 splits the fingerprint into three parts:
- Part A (human-readable) —
t13d1516h2= TLS 1.3 + SNI present + 15 cipher suites + 16 extensions + HTTP/2 — the client's outline readable at a glance - Part B — hash of the cipher suites after sorting — resistant to order shuffling
- Part C — combined hash of extensions, signature algorithms, and ALPN
Mainstream risk engines today run both — JA3 for hits against historical databases, JA4 for stronger identity classification.
Why This Layer Is Hard to Fake
A browser exposes three trait layers with very different spoofing difficulty:
| Layer | Representative traits | Spoofing difficulty |
|---|---|---|
| JS layer | Canvas, WebGL, fonts, UA | Low — anti-detect browsers change them freely |
| HTTP layer | Header order, H2 settings frame | Medium — requires deep client modification |
| TLS layer | ClientHello lists and order | High — changing it means rewriting the TLS stack |
The risk-engine logic is therefore simple — if the claimed identity and the TLS fingerprint disagree, it is a disguise. A session claiming to be Chrome whose TLS handshake shows Python traits can be blocked with zero human judgment. A great many "I changed everything and still got banned" cases are rooted in this layer — the proxy chain passed the client's original TLS handshake straight through.
In Practice: How to Check and Fix
Checking is simple — open the TLS fingerprint tool; the server reads the ClientHello from your handshake directly and returns JA3, JA4, protocol version, and ALPN within seconds.
How to interpret the results:
- Direct check from your everyday browser — JA4 should show normal browser traits (t13d…h2/h1). If it does, your browser itself looks normal
- Test again through your proxy — if JA4 turns into curl / Go / Python traits, this link is running bare at the TLS layer, instantly recognizable to risk engines
- Fix — switch to a client that supports TLS impersonation (uTLS-based solutions can shape the handshake to mimic a chosen browser), and keep it consistent with the HTTP/2 fingerprint, timezone, language, and other dimensions — see what the disguise score really measures
The other side is worth noting too — a stable TLS fingerprint is not a sin in itself. On the same machine it barely changes over time, which is exactly why risk engines treat it as an "environment anchor" — cross-checked against IP information (see the IP geolocation lookup), it can identify scripts without hurting real users.
A Common Misconception
"I use an anti-detect browser that changes every parameter — the TLS fingerprint changes too, right?" No. Most anti-detect browsers modify only JS-visible traits; at the TLS layer they either pass the handshake through unchanged (exposing the real software) or apply a wholesale browser template. A template mismatched with the rest of the environment — TLS looks like Chrome 120 while Canvas matches a different version — manufactures new contradictory signals. That is why we keep stressing that consistency matters more than single-point disguise.
Summary
The TLS fingerprint is the layer of the risk-control stack closest to your identity and furthest from what disguise can reach. Understanding it explains why "changing the UA is useless" and why some proxies "get identified no matter how they are used". Spending thirty seconds on the TLS fingerprint check to see your own handshake traits is the best starting point for understanding this whole system.
Check your own network: run a full disguise check on the homepage, or try the fingerprint test.