Skip to content
Glossary

JA3 fingerprint

A JA3 fingerprint is a hash computed from selected fields of the TLS ClientHello, taken in the order the client sent them.

A JA3 fingerprint is a hash computed from selected fields of the TLS ClientHello, taken in the order the client sent them. It turns a handshake into one short string that a server can match against a list, without decrypting anything or waiting for a request.

#What goes into the hash

The fields are the TLS version, the offered cipher suites, the extension identifiers, the supported elliptic curves and the curve point formats. Order is part of the input, not an accident of it, which is why two clients that support identical features can still hash differently.

All of this arrives in the first flight of the connection, in the clear. That is the point: classification finishes before your user agent or any other header is read.

#Why the same client can hash differently

RFC 8701 defines GREASE, a set of reserved values that a client may insert into its cipher suite, extension and named-group lists to keep servers tolerant of unknown values. Those values are chosen from a reserved set and may vary between connections. An implementation that hashes them along with everything else produces a different fingerprint each time, which looks like rotation and is not.

Implementations therefore strip GREASE values before hashing. Whether a given detector does so is not something you can read from the outside; you can only observe whether your hash is stable across connections.

#The family, not the one hash

Name Computed from
JA3 The client’s ClientHello
JA3S The server’s ServerHello, so a pair can be matched
Later successors Sorted inputs and additional fields, to resist GREASE and reordering

Newer schemes exist precisely because JA3 proved brittle. Treat the name as shorthand for the technique rather than as the specific hash in use anywhere.

#Commonly confused with

TLS fingerprinting is the technique; JA3 is one encoding of it. An HTTP/2 fingerprint is derived after the handshake, from frames rather than from the ClientHello, and the two are frequently checked together by an anti-bot system.

Frequently asked questions

Why does my JA3 hash change on every connection?
Most likely GREASE. RFC 8701 lets a client insert reserved values into the cipher, extension and named-group lists, and those values can differ per connection. A fingerprinting implementation that does not strip them produces a fresh hash each time. Stability returns once the reserved values are removed before hashing.
Can I change my JA3 fingerprint through configuration?
Only where the configuration reaches the TLS library, since the hash is computed from what that library offers and in what order. Headers, proxies and address rotation do not touch it. Changing it means using a stack that produces a browser's handshake, or driving a real browser.
Is a matching JA3 hash enough to pass as a browser?
No. It says your handshake resembles that browser's. HTTP/2 settings, header order, JavaScript-level properties and behaviour are all checked as well, and a browser hash arriving alongside a scripting client's frame pattern is a contradiction that is easy to spot.

Sources

  1. RFC 8446: TLS 1.3, the ClientHello fields the hash is built from
  2. RFC 8701: GREASE, the reserved values that destabilise naive hashing

Related terms