JA4 Fingerprint Format & Decoder
A JA4 fingerprint identifies the TLS library behind a connection from its ClientHello: the cipher suites, extensions, ALPN and signature algorithms it offers. This page documents what every character means, how the two hashes are built, and how to read one without a lookup table.
The format
t13d1516h2_8daaf6152771_e5627efa2ab1
└─ readable ─┘ └─ ciphers ─┘ └ extensions ┘
10 chars 12 hex chars 12 hex charsDecode a JA4 fingerprint
Paste a JA4 string to expand its readable prefix. This runs entirely in your browser: nothing is uploaded and nothing is logged. Sections 2 and 3 are one-way hashes, so the decoder reports them but cannot name the client behind them.
Section 1: the readable prefix
Ten characters, no hashing. This is the part you can read at a glance, and it is often enough on its own to spot a scripted client claiming to be a browser.
| Position | Field | Example | Meaning |
|---|---|---|---|
| 1 | Protocol | t | “t” = TLS over TCP, “q” = QUIC, “d” = DTLS |
| 2–3 | TLS version | 13 | Highest version offered. 13 = TLS 1.3, 12 = TLS 1.2, 11 = 1.1, 10 = 1.0, s3 = SSL 3.0. DTLS uses d1/d2/d3. |
| 4 | SNI | d | “d” = an SNI extension is present (connecting to a domain), “i” = absent (connecting to an IP) |
| 5–6 | Cipher count | 15 | Number of cipher suites offered, GREASE excluded, zero-padded, capped at 99 |
| 7–8 | Extension count | 16 | Number of extensions present, GREASE excluded, zero-padded, capped at 99 |
| 9–10 | ALPN | h2 | First and last alphanumeric character of the first ALPN value: “h2” for HTTP/2, “h1” for http/1.1, “00” if no ALPN |
Sections 2 and 3: the hashes
Both are SHA-256 digests truncated to their first 12 hex characters. Both are one-way: you cannot recover the cipher list from the hash, only match it against fingerprints you have already seen.
8daaf6152771
Section 2: cipher suites
Truncated SHA-256 of the cipher suite hex codes, sorted in hex order. Sorting is what makes JA4 resistant to clients that shuffle their cipher list between connections. GREASE values are removed first.
e5627efa2ab1
Section 3: extensions + signature algorithms
Truncated SHA-256 of the sorted extension hex codes, joined by an underscore to the signature algorithm list. Signature algorithms are not sorted, because their order is itself a signal.
Rules that trip people up
- GREASE is ignored everywhere, excluded from the counts in section 1 and from both hashes. Non-GREASE values such as SCSV are kept.
- SNI (
0x0000) and ALPN (0x0010) are excluded from the section 3 hash, because both are already represented in the readable prefix. They still count toward the extension count. - An empty list hashes to
000000000000rather than to the SHA-256 of an empty string. - Counts cap at 99. A client offering 120 extensions still reports
99. - A raw variant (
JA4_r) exists that lists the cipher and extension values in full instead of hashing them. It is far easier to debug against, and worth logging alongside the hashed form while you build a corpus.
Worked example
Decoding t13d1516h2_8daaf6152771_e5627efa2ab1 field by field.
t → TLS over TCP (not QUIC, not DTLS)
13 → TLS 1.3 offered
d → SNI present (connecting to a hostname, not a bare IP)
15 → 15 cipher suites (GREASE already removed)
16 → 16 extensions
h2 → first ALPN value is HTTP/2
8daaf6152771 → hash of the sorted cipher list
e5627efa2ab1 → hash of sorted extensions + signature algorithms
// The prefix says: a modern client speaking TLS 1.3 and
// negotiating HTTP/2, consistent with a real browser.
// Which browser or tool requires a corpus lookup.On attributing a hash to a tool. You will find blog posts confidently naming the exact browser or automation framework behind a given hash. Treat those with care: the hashes are one-way, so any attribution is a lookup against someone’s corpus, and corpora disagree. Check a fingerprint against the community JA4+ database Opens in a new tab or against traffic you have observed yourself, and record which source you used.
The JA4+ suite
JA4 is one member of a family, each fingerprinting a different layer. Created by FoxIO as the successor to JA3.
| Fingerprint | Fingerprints | Notes |
|---|---|---|
| JA4 | TLS ClientHello | The client fingerprint. What this page documents. |
| JA4S | TLS ServerHello | How the server responded. Pairs with JA4 to fingerprint a session. |
| JA4H | HTTP request headers | Header names, order, cookies, and language. Application-layer counterpart. |
| JA4L | Latency / hop count | Approximate distance to the client, useful against proxies. |
| JA4X | X.509 certificate | Fingerprints the certificate itself, for infrastructure attribution. |
| JA4T | TCP parameters | Window size and options. Identifies the OS network stack. |
| JA4SSH | SSH handshake | Applies the same idea to SSH sessions. |
Licensing. JA4 itself is published under the FoxIO License 1.1, which allows internal and non-commercial use but sets conditions on commercial redistribution. The rest of the family is BSD 3-Clause. Read the current licence before shipping an implementation commercially.
Reading JA4 in Cloudflare
Cloudflare exposes the client fingerprint as cf.bot_management.ja4 in the Ruleset Engine, usable in WAF custom rules and available in Logpush.
Requires Bot Management
JA3/JA4 fingerprints ship with Bot Management for Enterprise, alongside the full 1–99 bot score, detection IDs and JS Detections. Without that subscription the field is simply not populated, so a rule referencing it never matches, which looks identical to a rule that matches nothing.
- Find the fingerprints actually hitting your zone in Bot Analytics, then build rules from what you see rather than from a list you found online.
- Combine JA4 with path, ASN, country or method. A bare fingerprint match is the rule most likely to catch real users.
- On plans without Bot Management,
cf.verified_bot_categoryis a different signal that is available everywhere.
# Scoped, not a bare fingerprint match
(
cf.bot_management.ja4 == "t13d1516h2_8daaf6152771_e5627efa2ab1"
and http.request.uri.path contains "/api/"
and ip.src.asnum in { 16509 14618 }
)
# Action: Managed Challenge, not Block.
# Many real users share one fingerprint.JA3 vs JA4
| JA3 | JA4 | |
|---|---|---|
| Output | A single opaque MD5 hash | Three readable sections; version, ALPN and counts visible without a lookup |
| GREASE | Included, so random padding changes the hash | Stripped everywhere before counting or hashing |
| Ordering | Order-sensitive, so shuffling ciphers changes the hash | Ciphers and extensions sorted before hashing |
| Signature algorithms | Not included | Included in the third section |
| Transport | TCP only | TCP, QUIC and DTLS |
One fingerprint is a population, not a person
This is the single most important thing to understand before writing a rule. Every copy of the same browser build on the same platform produces an identical JA4. The fingerprint tells you what software is connecting, never who.
So a bare ja4 == … block rule against a browser-family fingerprint blocks every real visitor running that browser. Fingerprints are excellent as a correlation key (they persist while an actor rotates IPs) and as one input to a scoped rule. They are a poor standalone verdict.
WebDecoy uses JA4 as a correlation key inside a persistent actor identity, and only ever enforces on composite signatures that combine the fingerprint with network and path scope. Browser traffic is gated by session clearance instead, which avoids shared-fingerprint collateral entirely.
Further reading
JA4 Fingerprinting for AI Scrapers
The detection playbook: real fingerprints from scraping tools, collection at nginx, and rule building.
JA4 Fingerprint: definition
The short version: what it is, what it is used for, and the limitation that matters.
Blocking by JA4 at the WAF
Using fingerprints against IP rotation without taking out real users.
Specification source: FoxIO-LLC/ja4 Opens in a new tab · Fingerprint lookups: ja4db.com Opens in a new tab · Cloudflare field: cf.bot_management.ja4 Opens in a new tab
Frequently asked questions
How do I decode a JA4 fingerprint?
Split it on the two underscores. The first ten characters decode without any lookup: character 1 is the transport (t for TLS over TCP, q for QUIC, d for DTLS), characters 2–3 are the TLS version, character 4 says whether SNI was present, characters 5–6 and 7–8 are the cipher and extension counts with GREASE removed, and characters 9–10 are the first ALPN value. The decoder on this page does this in your browser; nothing is uploaded. The two hashes that follow are truncated SHA-256 digests and cannot be reversed, so naming the client behind them requires matching against a corpus such as the community JA4+ database.
What does each part of a JA4 fingerprint mean?
A JA4 has three underscore-separated sections. The first is ten readable characters describing the connection: transport protocol, TLS version, whether SNI is present, the cipher count, the extension count, and the first ALPN value. The second is a 12-character truncated SHA-256 of the cipher suite list, sorted in hex order. The third is a 12-character truncated SHA-256 of the sorted extension list combined with the signature algorithms.
Which Cloudflare plan is needed for cf.bot_management.ja4?
JA4 fingerprints require a Bot Management subscription. Cloudflare exposes JA3/JA4 fingerprints as part of Bot Management for Enterprise, alongside the full 1–99 bot score, detection IDs and JS Detections. On plans without Bot Management the field is not populated, so a rule referencing it will not match. Cloudflare also exposes a verified-bot category on every plan, which is a different and more widely available signal.
Can I identify a specific browser from a JA4 hash?
Not from the hash alone: the two hashed sections are one-way. You identify a fingerprint by looking it up against a corpus of known fingerprints, such as the community JA4+ database, or by building your own from observed traffic. The readable first section does tell you the TLS version, transport and ALPN without any lookup, which is often enough to spot a plain HTTP client pretending to be a browser.
Do two different clients ever share a JA4 fingerprint?
Constantly. Every copy of the same browser build on the same platform produces the same JA4. A fingerprint identifies a population of clients, not an individual, which is why it works well as a correlation key or a rate-limit dimension but is dangerous as a standalone block rule: blocking one blocks every real user who shares it.
Can a bot spoof its JA4 fingerprint?
It is possible but far costlier than spoofing a user agent. The fingerprint is a by-product of how the client TLS library actually negotiates the connection, so changing it means changing or carefully impersonating the underlying stack. Libraries that mimic browser handshakes exist, which is why JA4 is best used as one input among several rather than as a sole verdict.
Is JA4 open source?
The suite is split. JA4 itself is published under the FoxIO License 1.1, which permits internal and non-commercial use but places conditions on commercial redistribution. The other members of the family (JA4S, JA4H, JA4L, JA4X and JA4SSH) are BSD 3-Clause. Check the current licence text before shipping an implementation in a commercial product.
Fingerprints identify software. Actors identify attackers.
See how WebDecoy resolves JA4 into a persistent actor identity that survives IP rotation.
Explore Bot Scanner