Agent context packet

Structured metadata, source alternates, graph links, headings, series position, and diagram inventory for crawlers and agent readers.

Table of contents

  1. Quick Reference
  2. How a JA4 string is built
  3. Replaying a fingerprint
  4. Sources

Entry facts

Kind
article
Maturity
seedling
Confidence
medium
Origin
ai-drafted (AI-drafted, human-reviewed)
Author
Agent
Directed by
krow
Published
Words
1,357 (7 min read)
Tags
tls, fingerprinting, ja4, bot-detection
Full corpus
/llms-full.txt
Readable corpus
/source/full-corpus/

Graph links

Related ja4-fingerprint-t13d1516h2ja4-vs-ja3tls-impersonation-library-comparison

Tagstls, fingerprinting, ja4, bot-detection

Common JA4 TLS Fingerprints, Decoded

A lookup table of JA4 fingerprint hashes for Chrome, Firefox, curl, Go, and Python clients, decoded field by field.

/ directed by / / 7 min read
On this page

A JA4 fingerprint like t13d1516h2_8daaf6152771_<ja4_c> encodes the TLS ClientHello shape; this page decodes the common Chrome, Firefox, Safari, curl, Go, and Python client strings field by field.

Quick Reference

Rows marked live capture 2026-06-13 were observed against https://tls.peet.ws/api/all with the named client/profile. Treat them as version/profile observations, not permanent identities.

Client/profileJA4 fingerprintHTTPSource
FoxIO canonical JA4 examplet13d1516h2_8daaf6152771_e5627efa2ab1h2FoxIO JA4 technical details
Published Chrome-family examplet13d1516h2_8daaf6152771_02713d6af862h2bunny.net JA4 docs; Google Threat Intelligence deep dive; Cloudflare blog
Chrome 131 profile (curl_cffi chrome131)t13d1516h2_8daaf6152771_02713d6af862h2live capture 2026-06-13; curl_cffi target docs
Chrome 136 profile (curl_cffi chrome136)t13d1516h2_8daaf6152771_d8a2da3f94cdh2live capture 2026-06-13; Telegram Desktop issue #30733
Chrome 142 profile (curl_cffi chrome142)t13d1516h2_8daaf6152771_d8a2da3f94cdh2live capture 2026-06-13
Chrome Android 131 profile (curl_cffi chrome131_android)t13d1516h2_8daaf6152771_02713d6af862h2live capture 2026-06-13; curl_cffi target docs
Firefox 133 profile (curl_cffi firefox133)t13d1716h2_5b57614c22b0_eeeea6562960h2live capture 2026-06-13; curl_cffi target docs
Firefox 135/144 profiles (curl_cffi firefox135, firefox144)t13d1717h2_5b57614c22b0_3cbfd9057e0dh2live capture 2026-06-13; curl_cffi target docs
Safari 18.4 profile (curl_cffi safari184)t13d2014h2_a09f3c656075_7f0f34a4126dh2live capture 2026-06-13; curl_cffi target docs
Safari 26.0 profile (curl_cffi safari260)t13d2014h2_a09f3c656075_d0a99439f9b1h2live capture 2026-06-13; curl_cffi target docs
Safari 26.0.1 profile (curl_cffi safari2601)t13d2013h2_a09f3c656075_7f0f34a4126dh2live capture 2026-06-13; curl_cffi installed target list
curl 8.5.0 + OpenSSL 3.0.13 defaultt13d3112h2_e8f1e7e78f70_375ca2c5e164h2live capture 2026-06-13
Go net/http Go 1.22.2 defaultt13d1411h2_cbb2034c60b8_e7c285222651h2live capture 2026-06-13
Python requests defaultt13d1712h1_ab0a1bf427ad_882d495ac381HTTP/1.1live capture 2026-06-13
Python httpx defaultt13d1712h1_ab0a1bf427ad_8e6e362c5eacHTTP/1.1live capture 2026-06-13
OpenSSL s_client -tls1_3 no ALPNt13d410_16476d049b0b_78f1d400d464HTTP/1.1live capture 2026-06-13
OpenSSL s_client -tls1_3 -alpn h2,http/1.1t13d411h2_16476d049b0b_78f1d400d464HTTP/1.1 request after h2 ALPN offerlive capture 2026-06-13
Real Chrome latest desktop[varies by version]variesneeds JA4DB/export or live real-browser capture
Real Firefox latest desktop[varies by version]variesneeds JA4DB/export or live real-browser capture
Real Safari latest desktop[varies by version]variesneeds JA4DB/export or live real-browser capture

These hashes are environment- and version-specific: they identify the ClientHello and ALPN shape observed with a profile, library, OS, and build, not an eternal client name. The useful detector signal is the mismatch. A default Python, Go, or curl client emits its own non-browser JA4 even when the User-Agent claims Chrome, so JA4 should be read beside headers, HTTP/2 settings, IP reputation, and behavior as covered in the bot-detection stack and HTTP/2 fingerprinting.

Use the table as a lookup index, not a universal allowlist. If a log stores only the prefix, t13d1516h2 is enough to say “TLS 1.3, SNI, 15 ciphers, 16 extensions, h2,” but it is not enough to distinguish Chrome 131-style captures from newer Chromium-family captures. If the full a_b_c value is present, compare all three parts. Rows marked [varies by version] are deliberately unpinned because the ref-pack did not contain a verified literal hash for that real-browser/latest claim.

How a JA4 string is built

JA4 has three parts: ja4_a, ja4_b, and ja4_c, joined with underscores. ja4_a is the readable prefix. Its fields are protocol (t for TLS over TCP, q for QUIC, d for DTLS), TLS version, SNI flag (d when a domain/SNI is present, i when it is absent), two-digit cipher count, two-digit extension count, and the first and last character of the first ALPN value. In t13d1516h2, that means TLS over TCP, TLS 1.3, SNI present, 15 ciphers, 16 extensions, and HTTP/2 ALPN. For the deep prefix breakdown, use the t13d1516h2 prefix breakdown.

SegmentValue in t13d1516h2Meaning
protocoltTLS over TCP (q=QUIC, d=DTLS)
TLS version13TLS 1.3
SNIdSNI present (i = absent)
cipher count1515 ciphers after GREASE removal
extension count1616 extensions after GREASE removal
ALPNh2first/last char of first ALPN = HTTP/2
ja4_b_8daaf615277112 hex of SHA-256 over sorted ciphers
ja4_c_02713d6af86212 hex of SHA-256 over sorted extensions + sigalgs

ja4_b is the cipher hash. FoxIO defines it as the first 12 hexadecimal characters of SHA-256 over comma-delimited cipher hex codes sorted in hex order, with GREASE ignored. That sorting is the practical difference discussed in JA4 vs JA3: Chrome/Chromium extension and cipher ordering noise should not create a new identifier every time the same set is shuffled.

ja4_c is the extension plus signature-algorithm hash. It is the first 12 hexadecimal characters of SHA-256 over sorted extension hex codes plus signature algorithms in observed order. SNI (0000) and ALPN (0010) are excluded from the hash input because ja4_a already represents them, but they still count in the extension total. That is why two rows can share t13d1516h2_8daaf6152771 while differing only in the last 12 hex characters: the cipher set and readable shape stayed stable, while extension/signature details changed.

Part A is fast to read, but the full string matters. t13d1516h2_8daaf6152771_02713d6af862 and t13d1516h2_8daaf6152771_d8a2da3f94cd are both Chromium-family shapes in the table, yet they are not the same full fingerprint. A lookup system should key on the full a_b_c value when available, then degrade to the prefix only when the log source truncates it.

JA4 also changes when the wire shape changes. Browser version, platform TLS stack, QUIC versus TCP, ALPN list, PSK/resumption behavior, and library updates can all move a client to a new row. JA4DB is the canonical lookup target, but unauthenticated rows were not harvested for this table; the literal hashes above come from public docs, public examples, or live tls.peet.ws captures.

Replaying a fingerprint

curl_cffi is the Python binding over the active Lexiforest curl-impersonate fork. Its impersonation targets replay browser-like TLS, JA4, JA3, and HTTP/2 profiles with calls such as impersonate="chrome131", impersonate="chrome136", impersonate="firefox135", or impersonate="safari260". Pin target names for reproducible captures. Generic aliases like chrome, firefox, and safari move as the package adds newer profiles.

Replaying is not the same as becoming a browser. A Chrome-like JA4 paired with Python-ish headers, non-Chrome HTTP/2 SETTINGS, wrong pseudo-header order, or mismatched IP reputation is still inconsistent. The safer workflow is to capture the target profile at https://tls.peet.ws/api/all, record tls.ja4, compare the HTTP/2 signal, then use that result in tests. The operational library matrix in the TLS impersonation library comparison and the curl_cffi notes in the curl_cffi TLS fingerprinting notes cover where TLS replay ends and application-layer parity begins.

For debugging blocks, run the same request body through the normal stack and an impersonated stack from the same egress. If both fail the same way, the gate is probably not the ClientHello. If the impersonated path changes the result, inspect JA4, JA3, HTTP/2 SETTINGS, header order, cookies, and origin behavior before assuming the hash alone was decisive.

Sources

Diagram

Drag to pan · scroll or pinch to zoom · Esc to close