Once a TLS connection negotiates HTTP/2, the client opens with a few frames that every implementation fills in slightly differently. A fingerprint built from them was described in Akamai research in 2017, and its common form joins four fields with |:

  1. SETTINGS: which settings the client sends, in what order, with what values.
  2. WINDOW_UPDATE: the connection-level flow-control increment.
  3. PRIORITY frames, if any.
  4. Pseudo-header order: the order of :method, :authority, :scheme and :path, written as letters such as m,a,s,p.

Chrome, Firefox, Safari, Go's net/http and Python's httpx each produce a recognisable value.

Why it matters

Anti-bot systems compare this fingerprint with the TLS fingerprint and the User-Agent. A request claiming to be Chrome whose HTTP/2 settings match a Go client is an easy catch, even from a clean IP. A proxy does not help: HTTPS traffic crosses it inside an encrypted tunnel, so the frames reach the site exactly as your client wrote them.

How to see yours

Echo services print the fingerprint back. Send the same request through your client and through a real browser and compare the akamai_fingerprint field:

curl -s https://tls.peet.ws/api/all

Common confusion

Forcing HTTP/1.1 does not dodge the check. Current browsers use HTTP/2 wherever a site offers it, so a browser User-Agent arriving over HTTP/1.1 is itself unusual. The fix is a client that reproduces a browser's TLS and HTTP/2 behaviour together, such as curl_cffi's impersonation profiles, or a real browser. TLS fingerprinting with curl_cffi shows measured before-and-after values.