← All articles
Detection·8 min read

JA3 and JA4 TLS fingerprinting, explained for marketers

A user-agent string is a claim the client makes about itself, and it can say anything. Changing it is one line of code. This is why detection built on user-agents is trivially defeated, and why the more interesting question is whether there is anything a client cannot easily lie about.

What happens before any of your code runs

Every HTTPS connection opens with a TLS handshake. The client sends a ClientHello announcing which TLS versions it supports, which cipher suites it offers and in what order, which extensions it understands, and which elliptic curves it can use. All of this is sent before a single byte of your page, your tag or your headers.

That combination is not arbitrary. It is determined by the TLS library the client was built against. Chrome's ClientHello looks like Chrome. Python's requests library looks like OpenSSL as Python configures it. Go's net/http looks like Go. They are different in ways the person writing the script usually does not know about and cannot casually change.

From handshake to fingerprint

JA3 hashes those handshake fields into a single short string. JA4 is the newer scheme and is more robust: it is partly human-readable, and it is deliberately resistant to the cipher-order shuffling that was used to evade JA3.

A real browser and a scripted client, same user-agent:

  Client A  UA: Chrome/120 ...   JA4: t13d1516h2_8daaf6152771_b186095e22b6
  Client B  UA: Chrome/120 ...   JA4: t13d401h2_8daaf6152771_f9b5f5a5a4d1

The user-agent is identical. The handshakes are not: Client B
is a script claiming to be Chrome.

Why this is hard to defeat

Faking a user-agent is a string edit. Faking a TLS fingerprint means making your TLS stack behave like a different TLS stack, at the protocol level. It is possible — there are libraries for it — but it is a different order of effort, and the overwhelming majority of automation does not bother.

The honest limits

Three of them, and anyone selling this as a complete answer is overselling it:

  • A fingerprint identifies the client software, not the intent. Googlebot has a fingerprint too, and you want Googlebot.
  • Thousands of real people share one fingerprint, because they all run the same Chrome build. A fingerprint on its own can never be grounds for a block.
  • Headless Chrome driving a real browser engine produces a fingerprint close to real Chrome. TLS alone will not catch it; that needs behavioural signals.

Where it fits

TLS fingerprinting is one signal among several, and its value is that it is orthogonal to the others. An operation can rotate IPs cheaply and spoof user-agents for free, but its TLS stack stays put. When a bot farm cycles through a thousand residential addresses, the handshake is often the only thing that stays constant — and that constancy is what makes it recognisable across every site on a shared network at once.

See this on your own site

The free exposure check reads only publicly visible information and takes about ten seconds. No signup.