TLS and JA4 fingerprinting: how you're tracked below the browser
Before your browser sends a single cookie or runs a line of JavaScript, it has already told the server a great deal about itself. The very first message of every HTTPS connection, the TLS ClientHello, carries a structured list of capabilities that varies from one client to another. This article explains how that message becomes a stable identifier through JA3 and JA4 fingerprinting, who uses it, and why it is one of the hardest signals for an ordinary user to change.
What happens before encryption begins
When you open a connection to an HTTPS site, the client and server first negotiate how they will encrypt the rest of the conversation. The client opens with a ClientHello: a plaintext message that advertises everything the client supports. The contents are not secret, because encryption has not started yet, which means any server, proxy, or middlebox on the path can read them in full.
The ClientHello includes the TLS version, the list of cipher suites the client will accept, a set of extensions (such as server name indication, application-layer protocol negotiation, and signature algorithms), the elliptic-curve groups it supports, and the point formats for those curves. None of this identifies you by name. The fingerprinting power comes from a subtler property: the exact set of values, and the order in which they appear, is determined by the software that built the message, not by you.
From handshake to fingerprint: JA3 and JA4
JA3, published by Salesforce engineers in 2017, was the first widely adopted way to summarise a ClientHello. It concatenates five fields from the handshake (TLS version, cipher suites, extensions, supported groups, and elliptic-curve point formats), joins their numeric codes with separators, and takes an MD5 hash of the result. The output is a 32-character hexadecimal string such as e7d705a3286e19ea42f587b344ee6865. Two clients producing the same byte layout produce the same JA3 hash.
JA3 had a known weakness: the order of TLS extensions. Some clients, notably Chrome from 2021 onward, deliberately shuffle their extension order on every connection (a technique called GREASE-driven randomisation). That alone changes the JA3 hash each time, which broke JA3 for tracking Chrome specifically.
JA4, released by FoxIO in 2023, was designed to survive this. It is part of a family (JA4, JA4S for the server response, JA4H for HTTP, and others) and produces a human-readable, segmented string rather than a single opaque hash. A JA4 fingerprint looks like t13d1516h2_8daaf6152771_b186095e22b6. The first segment encodes the protocol, TLS version, number of cipher suites, number of extensions, and ALPN value. Crucially, JA4 sorts the cipher suites and extensions before hashing them, so randomising their order no longer changes the result. The randomisation defence that defeated JA3 does nothing against JA4.
Why this fingerprint is so revealing
The reason network-layer fingerprinting works is that the ClientHello is a faithful signature of the underlying networking stack. Different stacks produce reliably different handshakes:
- Browser engine. Chromium, Gecko (Firefox), and WebKit (Safari) each assemble their ClientHello differently. A JA4 fingerprint usually reveals the engine and often the major version.
- Operating system. The same browser version can fingerprint slightly differently across platforms because of how the OS provides TLS primitives, especially on Safari and on clients that use the system TLS library.
- Custom clients. Tools built on Python's requests, Go's net/http, curl, or Node all have distinctive handshakes that look nothing like a mainstream browser. This is exactly why a scraper that perfectly imitates a browser's HTTP headers still gets blocked: the headers say Chrome, but the handshake says Python.
The fingerprint identifies a class of client rather than a unique person. On its own a JA4 value might be shared by tens of millions of people running the same Chrome build on Windows. Its real power is in combination. Joined with your IP address, your HTTP header order, and a browser-layer fingerprint, the network signature narrows the field considerably and is far harder to forge than any of the others.
Who collects it, and why
TLS fingerprinting started as a defensive tool and is now mainstream infrastructure. The main users are:
- CDNs and anti-bot vendors. Cloudflare, Akamai, and similar providers compute a TLS fingerprint on every connection. If your handshake claims to be Chrome but matches a known automation library, the request is challenged or blocked. This is the most common reason a legitimate script using spoofed headers fails while a real browser succeeds.
- Fraud and security teams. Banks and payment processors use the handshake as one input to detect credential-stuffing and account-takeover tools, which usually run on automation stacks with telltale fingerprints.
- Trackers and analytics. Because the value is computed server-side and needs no JavaScript or cookies, it works against clients that block scripts and clear storage. It is a useful supplementary signal for linking sessions when browser-layer signals are unavailable.
Why you can't easily change it
Most privacy advice targets things you can toggle: clear cookies, block scripts, spoof a header. The TLS fingerprint resists all of that, for a structural reason. The ClientHello is produced deep inside your TLS library, below the layer any browser setting or extension can reach. A content blocker can stop a tracking script from loading, but it cannot rewrite the handshake your operating system already sent. There is no checkbox in any mainstream browser to alter your cipher-suite list or extension set.
This is also why naive spoofing backfires. If you force an unusual TLS configuration, you do not blend in; you produce a rare fingerprint that few other people share, which makes you more distinguishable, not less. A handshake that does not match any known browser is itself a strong anti-bot signal.
What actually helps
The realistic goal is not to be invisible at the TLS layer but to share a handshake with the largest possible crowd. Concrete steps:
- Use a mainstream browser's native stack, unmodified. A current release of Chrome, Firefox, or Safari produces a handshake shared by an enormous population. That common fingerprint is the best camouflage available, because it is indistinguishable from millions of others.
- Keep the browser updated. Each version has a characteristic handshake. A wildly out-of-date build narrows the crowd you blend into and stands out.
- Avoid handshake-altering tools you don't fully understand. Some security suites, corporate TLS-inspection proxies, and aggressive VPN clients intercept and re-emit your TLS connections. This replaces your browser's handshake with the product's own, often rarer, fingerprint. If a proxy terminates TLS, the server sees the proxy's handshake, not yours.
- For automation and tooling, use uTLS-style libraries. If you write scripts, libraries such as Go's uTLS let you mimic a real browser's ClientHello byte-for-byte, including GREASE values and extension ordering, so the handshake matches the browser you claim to be. This is the legitimate way to make a client present a coherent, browser-consistent fingerprint, rather than a default library handshake that screams automation.
- Understand that VPNs and Tor do not change it. A VPN changes your apparent IP address but tunnels your real browser's TLS handshake unchanged, so your JA4 value is identical with the VPN on or off. Tor Browser helps mainly because it ships a single, standardised configuration that every Tor user shares, which is the crowd-blending principle taken to its logical end.
How it fits the bigger picture
TLS fingerprinting is one layer in a stack of identifiers. Above it sit HTTP header order, then browser-API fingerprints, then cookies and storage. Defences that only address the upper layers leave the network signature intact, and a coherent tracker correlates across all of them. The practical takeaway is consistency: every layer of your client should tell the same story. A VPN exit in one country, an en-US browser, and a Chrome handshake on a Linux user agent that no Chrome build ships on is a contradictory profile, and contradictions are themselves a signal.
The privacyscore.dev test focuses on the browser-layer signals you can observe and influence directly, but it is worth knowing that a quiet, unchangeable identifier was sent before any of those measurements were even possible. Recognising that the handshake exists, and that blending in beats standing out, is the right mental model. The most private clients are not the most exotic ones; they are the ones that look exactly like everyone else.