Chrome's JA3 changes because Chrome shuffles the order of the extensions in its TLS ClientHello on every new connection, and JA3 hashes those extensions in the order they arrive. Change the order and the hash changes, even though nothing else about the browser did. Chrome does this on purpose. A JA3 that stays fixed for a client claiming to be Chrome is therefore the odd one out: it repeats an ordering real Chrome almost never sends twice.

What JA3 actually hashes

JA3 takes five fields from the ClientHello, the first message a browser sends when it opens a TLS connection: the TLS version, the cipher suites, the extensions, the elliptic curves and the point formats. It writes each list out in the order it was sent, joins the five with commas, and takes an MD5 of the string.

That order is the weak point. When JA3 was designed, a given TLS library always sent its extensions in the same sequence, so the sequence was a stable trait of the client. Hashing it in order made sense. Nobody had a reason to shuffle.

Why does Chrome's JA3 change? It shuffles on purpose

Chrome randomises its extension order to stop servers and middleboxes depending on it. When every client sends one exact shape, equipment on the network starts assuming that shape, and the protocol can no longer change without breaking somebody. The word for that is ossification. A browser that varies the parts that are allowed to vary keeps the rest of the internet from hard-coding them.

Chrome also sends GREASE values, deliberately meaningless entries in several lists, for the same reason. Between the two, a fixed JA3 was never something Chrome produced to begin with.

Every profile is drawn from one real computer, not from separate listsIn Mosaic: Machines that exist. GPU, screen, CPU and fonts from one real device. Free holds 3 profiles. Pro is $49 a month for any number.

How it works: Machines that exist

What we measured

We did not take this on faith, because our own engine depends on it. Tesseract Chrome is Chromium, so it should emit exactly Chrome's handshake. We ran one profile against Google's own Chrome for Testing 153.0.8010.36, on the same machine in the same minute, through our detector runner's tls-ja3 row with a stock control:

ours     JA4 t13d1518h2_8daaf6152771_4980c97edce0
stock    JA4 t13d1518h2_8daaf6152771_4980c97edce0

Byte-identical: TLS 1.3, 15 cipher suites, 18 extensions, ALPN h2, and the same hashes of the sorted cipher list and extension set. The JA3 values were 995f48479d09 for ours and 624b4feda192 for stock. That gap is not a finding. Each connection draws a new ordering, so two connections from one binary disagree on JA3 as readily as two binaries do.

JA4 survives because it sorts the ciphers and extensions before hashing them, and leaves GREASE out. The shuffle changes the order and nothing else, so a sorted list hashes the same every time. The readable prefix, t13d1518h2, says TCP, TLS 1.3, a domain name in SNI, 15 ciphers, 18 extensions and HTTP/2.

The version number moves it, not the shuffle

There was one number that did change, and it came from the wrong control. Google Chrome 152 on the same machine read t13d1517h2: seventeen extensions where 153 sends eighteen. That is a change in Chrome's own TLS stack between major versions.

So the honest comparison is always against a Chrome of the same major. Against a different one, a real difference in Chrome itself looks like a fault in yours. Our stock-comparison check refuses to compare across majors for this reason.

Why our engine has no TLS fingerprint switch

Some anti-detect browsers sell control over the TLS fingerprint as a feature. We left it out deliberately. Every real Chrome of a given version sends the same ClientHello shape, so varying it per profile does not separate two profiles from each other; it makes one of them the only browser on the internet with that handshake.

A handshake that disagrees with the User-Agent is also the earliest contradiction a site can read, before a single line of JavaScript runs. A profile that claims Chrome and opens its connection like something else has failed before the page loads. Ours inherits Chrome's permutation and GREASE untouched, and the same holds for the HTTP/2 settings Chrome sends, because both come from the Chromium code we build.

How to read your own

Look at the JA4, not the JA3, and compare it with a real Chrome of the same major on the same machine. Our TLS fingerprint page explains each field of both hashes, and the fingerprint checker shows what a page reads once the connection is open. If you are weighing products that promise a "custom JA3", what an anti-detect browser is covers which values a browser can change and which it should leave alone, and our launch post explains why we build the engine from stock Chromium source.