Learn how HTTP/2 fingerprinting works: SETTINGS frames, pseudo-header order, and how the Akamai fingerprint complements JA3/JA4 to detect bots.
Every HTTPS connection is preceded by a TCP handshake and a TLS negotiation, but neither of those is where HTTP/2 fingerprinting lives. HTTP/2 fingerprinting captures signatures from the frames a client sends after TLS is established — in the first milliseconds of the HTTP/2 session — before any request has been made. The exact combination of settings frames, flow-control increments, and pseudo-header ordering a client sends is determined by its HTTP/2 implementation, not its user, and is consistent across requests. That consistency is what makes it a fingerprint.
Key Takeaways
- HTTP/2 clients announce themselves before the first request. The initial SETTINGS frame, WINDOW_UPDATE increment, and PRIORITY frames are dictated by the HTTP/2 library — not the user — producing signatures that differ between Chrome, Firefox, Safari, and automation tools.
- The Akamai fingerprint encodes four signals — SETTINGS values, window increment, PRIORITY frames, and pseudo-header order — into a compact string that identifies the underlying HTTP client.
- It catches bots that pass TLS and User-Agent checks. A script that spoofs Chrome's TLS handshake (via
curl-impersonate) still typically fails the HTTP/2 layer unless it also mimics Chrome's exact frame sequence and pseudo-header order. - Paired with JA3/JA4, the two fingerprints cover complementary layers: TLS identifies the cryptographic library; HTTP/2 fingerprinting identifies the HTTP implementation. A mismatch between them is a strong bot signal.
- PRIORITY frames — historically the most distinctive part of the HTTP/2 fingerprint — were deprecated in RFC 9113, so modern fingerprinting leans more heavily on SETTINGS values and pseudo-header order.
What Is HTTP/2 and Why Does It Fingerprint?
HTTP/2 (RFC 7540, updated by RFC 9113) replaced HTTP/1.1's plain-text, one-request-at-a-time model with a binary framing layer. All communication flows over a single TCP connection through numbered streams, carried by binary frames — each frame typed as DATA, HEADERS, SETTINGS, WINDOW_UPDATE, PRIORITY, and so on.
When a client opens an HTTP/2 connection, it follows a prescribed startup sequence before it can issue any request:
- Send the HTTP/2 connection preface — a fixed 24-byte magic string.
- Send a SETTINGS frame declaring the client's parameter choices for this connection.
- Optionally send a WINDOW_UPDATE frame to increase the initial flow-control window.
- Optionally send PRIORITY frames to prime the stream dependency tree.
- Send the first HEADERS frame containing the actual HTTP request.
Steps 2–4 happen before the server has responded and before any user-authored code runs. They are entirely determined by the HTTP/2 library — and they differ between implementations in ways that are stable across sessions, URLs, and IP addresses.
The Four Signals the Akamai Fingerprint Captures
Researchers at Akamai Technologies observed that these startup signals are consistent enough per client to be used as a fingerprint. The Akamai fingerprint encodes four signals into a single pipe-delimited string. A representative fingerprint looks like:
1:65536;3:1000;4:6291456;6:262144|15663105|0|m,a,s,p
1. SETTINGS Frame Values
The SETTINGS frame is a list of parameter_id:value pairs. HTTP/2 defines six standard parameters: HEADER_TABLE_SIZE (ID 1), ENABLE_PUSH (2), MAX_CONCURRENT_STREAMS (3), INITIAL_WINDOW_SIZE (4), MAX_FRAME_SIZE (5), and MAX_HEADER_LIST_SIZE (6). A client sends only the parameters it wants to override from the protocol defaults.
The combination of which parameters appear, their values, and their order is determined by the HTTP/2 library. Chrome's BoringSSL-backed HTTP stack chooses different values and a different ordering than Firefox's Necko, Safari's CFNetwork, or Python's httpx. Even minor version updates can shift which parameters are included or what values they carry. The first segment of the Akamai fingerprint string — 1:65536;3:1000;4:6291456;6:262144 in the example above — encodes these pairs.
2. WINDOW_UPDATE Increment
HTTP/2's flow-control system starts with a default connection-level window of 65,535 bytes. Most clients immediately send a WINDOW_UPDATE frame to increase this to a larger working size, and the specific increment they choose is characteristic of the client. A missing WINDOW_UPDATE or an unusual increment value is itself a signal — many minimal HTTP libraries omit this frame entirely, while major browsers send a large, library-specific increment. The second segment of the fingerprint encodes this value.
3. PRIORITY Frame Sequence
HTTP/2 originally allowed clients to declare stream priority with PRIORITY frames, establishing a dependency tree so the server could send the most important responses first. Browsers sent distinctive startup patterns: Chrome's historical pattern, for instance, included a specific sequence of PRIORITY frames for streams 3, 5, 7, 1, and 11 at defined weights. These patterns were highly stable and immediately distinguishable from non-browser HTTP clients that typically omit PRIORITY frames entirely.
RFC 9113 (2022) deprecated the HTTP/2 stream priority mechanism because it proved complex to implement and rarely improved performance in practice. Modern clients increasingly omit PRIORITY frames altogether. The third segment of the Akamai fingerprint captures this pattern (or its absence), which still distinguishes older browser builds from one another and from headless or scripted HTTP clients.
4. Pseudo-Header Order
HTTP/2 requests encode the method, path, scheme, and host as pseudo-headers — :method, :path, :scheme, and :authority — that must precede ordinary headers in the HEADERS frame. The protocol requires that all four appear before regular headers, but the order among themselves is left to the implementation.
Browsers consistently use a particular ordering. Chrome typically sends :method, :authority, :scheme, :path — encoded in the fingerprint as m,a,s,p. HTTP libraries in Go, Python, and Node.js often emit these in a different sequence, or the sequence may vary by version. The fourth segment captures this ordering, and combined with the SETTINGS signal it is one of the most stable discriminators between real browser clients and automation libraries.
How HTTP/2 Fingerprinting Complements TLS Fingerprinting
TLS fingerprinting (JA3/JA4) extracts a signature from the ClientHello message — sent in plaintext before the TLS session is encrypted. HTTP/2 fingerprinting extracts a signature from the binary frames sent immediately after TLS is established. The two operate at adjacent layers with no overlap:
| Layer | Technique | What is captured |
|---|---|---|
| TLS | JA3 / JA4 | Cipher suites, extensions, elliptic curves in the ClientHello |
| HTTP/2 | Akamai fingerprint | SETTINGS values, window increment, PRIORITY sequence, pseudo-header order |
A bot that successfully clones Chrome's TLS handshake using a tool like curl-impersonate still sends HTTP/2 frames from its underlying HTTP library — a different SETTINGS set and pseudo-header order that any fingerprint-aware server can distinguish from a real browser. Conversely, a bot that clones Chrome's HTTP/2 frames but leaves the TLS handshake unchanged fails the JA3/JA4 check. Layering both fingerprints creates a substantially harder-to-evade test than either one alone.
This is the same compound-layer principle described in the bot detection techniques guide: inconsistency between observable protocol layers is stronger evidence of spoofing than any single anomaly.
HTTP Header Order: A Related Signal
Beyond the binary-framing signals, the order of ordinary HTTP headers within the HEADERS frame also carries information. Chrome, Firefox, and Safari each emit headers — Accept, Accept-Language, Accept-Encoding, User-Agent, Upgrade-Insecure-Requests — in a consistent order determined by the browser's request-preparation logic, not by the page or the user. Automation libraries emit headers in a different default order, often alphabetically or in the order they were appended in code.
A request whose header order matches Python's requests or Go's net/http rather than Chrome's standard sequence is likely not a real browser, regardless of what the User-Agent field claims. Header-order fingerprinting works across both HTTP/1.1 and HTTP/2, and is commonly used alongside the binary-framing signals for a richer combined score.
Practical Testing
Unlike browser fingerprinting signals such as Canvas or WebGL — which are readable from JavaScript inside the page — HTTP/2 fingerprinting is inherently server-side. The SETTINGS and WINDOW_UPDATE frames are binary framing that never reach the page's JavaScript context, so testing requires a server that reads and interprets those raw frames before handing the connection to the application layer.
BrowserLeaks' /http2 endpoint shows your live Akamai fingerprint string — the four-segment value your current client is sending. BrowserInsight's bot detection tool covers the complementary client-side signals (automation artifacts, headless leaks, fingerprint consistency). The TLS layer is surfaced separately via the network diagnostics page.
Frequently Asked Questions
Does HTTP/3 have a similar fingerprint?
Yes, though the signals differ. HTTP/3 runs over QUIC rather than TCP+TLS, and QUIC carries its own connection parameters — QUIC transport parameters embedded in the Initial packet — that vary by implementation. HTTP/3 SETTINGS frames, carried in the QPACK control stream, provide a signal analogous to HTTP/2 SETTINGS. Active research is extending HTTP/2-style fingerprinting to HTTP/3 as the protocol becomes more prevalent.
Can a bot defeat HTTP/2 fingerprinting by forging its User-Agent?
No. The User-Agent header is set in the HEADERS frame by application code, but the SETTINGS frame, WINDOW_UPDATE, and PRIORITY frames are emitted by the HTTP/2 library before any application code runs. A bot that forges a Chrome User-Agent while using Go's net/http or Python's httpx still sends that library's SETTINGS values and pseudo-header ordering, not Chrome's.
Is HTTP/2 fingerprinting used in production today?
Yes. Major CDNs, bot management vendors, and large web properties use it alongside TLS fingerprinting and behavioral signals as part of multi-layer bot scoring. Because it requires no JavaScript execution and captures frames before the server sends any response, it is particularly difficult to evade without accurate per-library emulation.
Why was PRIORITY deprecated if it was so useful for fingerprinting?
PRIORITY was removed from HTTP/2 in RFC 9113 for reasons entirely unrelated to fingerprinting — implementations found it complex to support correctly and it delivered little measurable latency benefit in practice. The deprecation reduces one dimension of the fingerprint for modern clients but also means that any client still sending the old PRIORITY pattern is likely running an older browser build, which is itself a useful classification signal.


