Skip to content
← Back to glossary Anti-Bot

TLS Fingerprinting (JA3 / JA4)

What Is TLS Fingerprinting?

TLS fingerprinting identifies a client by the details of its TLS ClientHello message (cipher suites, extensions, elliptic curves, and their order) before any HTTP request is ever sent. This is why rotating IP addresses or changing User-Agent strings does nothing to prevent detection, the block happens at the TLS handshake layer, which sits below HTTP entirely.

Every time a client opens a TLS connection, it sends a ClientHello packet listing which TLS version, cipher suites, extensions, and elliptic curves it supports, and in what order. Real browsers (Chrome, Firefox, Safari) each produce a distinct, consistent pattern in this handshake. Most HTTP libraries (Python's requests, Node's default https module, plain curl) produce a different, easily recognizable pattern.

Anti-bot systems capture this pattern and hash it into a fingerprint. If that fingerprint doesn't match a real browser's, the request can be flagged or blocked, regardless of the IP address or headers sent afterward.

JA3 vs JA4

  • JA3: the original fingerprinting method, released by Salesforce in 2017. It hashes the TLS version, cipher suites, extensions, elliptic curves, and elliptic curve point formats from the ClientHello into a single MD5 hash.
  • JA4: a newer, more detailed fingerprinting standard. It improves on JA3 by including ALPN values, ordering ciphers/extensions more precisely, and producing a fingerprint that's harder to spoof accidentally and easier to reason about across TLS versions (including TLS 1.3).

Both work the same way at a conceptual level. They turn "how a client negotiates TLS" into a short, comparable signature.

Why Rotating IPs Doesn't Help

TLS fingerprinting happens during the handshake, which is a layer below the HTTP request. Because of this:

  • Changing your IP address doesn't change your TLS fingerprint.
  • Changing your User-Agent header doesn't change it either; the User-Agent is sent after the TLS handshake completes, inside the HTTP request.
  • Standard HTTP client libraries (like Python requests) have a fixed, non-browser-like TLS signature by default, so every request from them looks identical to an anti-bot system no matter what other values are randomized.

This is a common source of confusion: a scraper can have clean residential IPs, randomized headers, and realistic User-Agent strings, and still get blocked immediately, because the TLS layer gave it away before any of that mattered.

Common Bypass Approaches

  • curl_cffi: a Python library that impersonates the TLS/JA3 fingerprints of real browsers (Chrome, Safari, etc.) at the TLS layer, rather than just spoofing headers.
  • Browser automation: using an actual browser engine so the TLS handshake is generated by real browser code, not a scripting library.
  • TLS fingerprint impersonation libraries: tools that reimplement a specific browser's cipher suite order and extension list so outgoing requests match a known-good signature.

Related terms

Web Unblocker

Extract data automatically, browse undetected, and beat anti-bot systems — all in one powerful tool.

Get started free

Community

Head over to our community where you can engage with us and our community directly.

Questions? Ask our team via live chat, join us on our official Slack community. We're always happy to help.

Join our Slack Community