Every HTTPS connection starts with the client saying hello. Before a single byte of a page moves, the browser sends a TLS ClientHello listing which protocol versions, ciphers and extensions it supports. Different TLS libraries send different lists, so the hello says what kind of software is connecting. JA3 turns that hello into one short string a firewall can match.
How a JA3 fingerprint is made
JA3 was invented at Salesforce in 2017. Its repository gives the recipe. Take five fields from the ClientHello, as decimal values:
SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat
Join the values inside a field with -, join the fields with ,, keep the order the client sent them in, and hash the result with MD5. The output is a 32-character fingerprint. The same recipe applied to the server's reply is JA3S.
A script built on an HTTP library and a browser build their hellos from different TLS stacks, so each gets a different JA3. That is the whole use: a network team can block a known piece of malware by its hash, and a bot rule can notice a client that says Chrome in its User-Agent and hellos like a Python library.
The fingerprint is changed inside the engine, not painted on topIn Mosaic: Its own Chromium. Tesseract Chrome: values changed in C++, not JavaScript. Free holds 3 profiles. Pro is $49 a month for any number.
Mosaic is a desktop app
Email yourself the link and open it on your computer.
How it works: Its own Chromium
Why Chrome broke it
JA3 keeps the order of the extensions, and since Chrome 110 Chrome shuffles that order on every connection (Chrome Platform Status, read 2 November 2026). The stated reason is "to reduce potential ecosystem brittleness": servers had started building logic around one fixed Chrome hello. The side effect is that one copy of Chrome produces a different JA3 on almost every connection.
We saw this in our own measurements. Our engine and Google's Chrome for Testing 153, on the same Mac, in the same minute, gave different JA3 hashes, and because of the shuffle two connections from one binary disagree as well. Their JA4 values were byte-identical. So a different JA3 between two Chrome connections says nothing, and a JA3 that never changes across connections says a lot, because it is not what a current Chrome does.
The same creator now maintains JA4, which sorts the cipher and extension lists before hashing, so the shuffle no longer moves the result. Salesforce's repository says JA3 is no longer actively maintained there.
What a site can read with it
A JA3 or JA4 hash tells a server which TLS library made the connection. On its own that does not separate two Chrome users, because every Chrome of a version uses the same library. What it catches is disagreement: a handshake from one client paired with headers from another. That is the trap tools fall into when they put a browser's User-Agent on an HTTP library, and it is read before any JavaScript runs. The wider family of handshake checks is in TLS fingerprinting, and how detection services combine it with the page-level checks is in how sites detect anti-detect browsers.

How Mosaic handles it
Mosaic does not change the TLS handshake, on purpose. Tesseract Chrome is Chromium, so it sends Chrome's own ClientHello, with Chrome's per-connection shuffle and GREASE values left as they are. There is no setting for a TLS persona, because a profile with a handshake no Chrome sends would be the only browser on the internet with it. A proxy does not change it either: with HTTPS, the proxy carries the browser's own handshake through a tunnel. Mosaic's detection tests include a JA3/JA4 echo page, so you can read a profile's handshake yourself; the engine page covers what we do change.
Sources
- Salesforce: JA3, a method for profiling SSL/TLS clients, read November 2, 2026
- Chrome Platform Status: TLS ClientHello extension permutation, read November 2, 2026
- FoxIO: JA4+ network fingerprinting, read November 2, 2026





