TLS fingerprint
How WireLens sends each server your app's own TLS and HTTP/2 fingerprint, and how to read the Fingerprint section of a connection.
When WireLens decrypts a connection, there are two connections: your app talks to WireLens, and WireLens talks to the server. The server only ever sees the second one.
The first message of a TLS connection, the ClientHello, lists the cipher suites, extensions and other options the client supports. That list differs between Chrome, Safari, Firefox, curl and every other TLS library, and it identifies the client. Bot-detection services hash it (the hash is called JA4, or the older JA3) and compare it with the User-Agent. HTTP/2 gives a second fingerprint: the order and values of the first settings a client sends, and the order of the :method, :authority, :scheme and :path headers.
If the server sees a Chrome User-Agent arriving with a different TLS fingerprint, it may answer with a challenge or a 403, and only while WireLens is running.
On the Mac: match the client's fingerprint#
On the Mac, WireLens builds each connection to the server from your app's own ClientHello and HTTP/2 settings. The server sees the fingerprint it would see without WireLens.
It is on by default. The switch is Match the client's TLS fingerprint in Tools ▸ SSL Proxying ▸ Decryption. Turn it off to send WireLens's own fingerprint instead.
What is copied:
- Cipher suites, supported groups, signature algorithms and TLS versions, in your app's order.
- The extensions your app sends, including GREASE, certificate compression, ALPS and encrypted ClientHello. Chrome shuffles its extensions on every connection, and WireLens does too when the app is Chrome-based.
- The HTTP/2 settings frame, the first window update, and the order of the request's pseudo-headers and its priority.
- The order of the request headers, on HTTP/1.1 and HTTP/2.
WireLens can only offer what its TLS library supports. Chrome 152 also offers ML-DSA signature algorithms, which WireLens cannot offer yet, and for Chrome 152 the JA4 differs in that one part. Older cipher suites that some libraries still list, such as DHE and Camellia from curl or OpenSSL, are left out the same way. The Fingerprint section names everything that could not be copied.
If a server refuses a copied handshake, WireLens connects again with its own, and the request still goes through. It remembers that server for ten minutes, and the connection shows Fell back to WireLens's own handshake with the reason.
WebSocket connections are covered too. Connections sent through an upstream proxy (see SOCKS, upstream and reverse proxy) keep WireLens's own fingerprint, because the proxy makes its own connection to the server.
The Fingerprint section#
Select a decrypted flow and open Summary. The Fingerprint section compares the two connections:
| Row | What it shows |
|---|---|
| Upstream | Whether the server saw your app's fingerprint, such as Matches the client (JA4 and HTTP/2) in green, or Differs from the client in orange. |
| Reason | Why, when the verdict needs explaining. |
| Client JA4 / Upstream JA4 | The JA4 of your app's ClientHello, and of the one WireLens sent to the server. |
| Client HTTP/2 / Upstream HTTP/2 | The HTTP/2 fingerprint of each side, in the settings| form fingerprinting services print. |
| Differences | Each thing that was not copied, by name. |
| Client JA3 / Upstream JA3 | The older JA3 hash. Chrome's changes on every connection, and two JA3 values that disagree mean little on their own. |
| Client JA4_r | Your app's JA4 in its raw, readable form. |
The upstream values are read from what was actually sent, not from the settings WireLens chose.
On iPhone and iPad#
iOS builds the connection to the server itself. WireLens can neither change nor read the TLS fingerprint the server sees.
On a decrypted request's Overview tab, tap Connection to see its Fingerprint section: Client JA4, Client H2 (your app's HTTP/2 fingerprint), Origin H2 (the HTTP/2 settings sent to the server), Client JA3, and a verdict at the top. A server that blocks on TLS fingerprints may treat traffic differently while WireLens for iPhone captures it.
From MCP#
The same information is in get_flow over MCP, under connection.. An agent can set the Mac switch with set_setting and the name tlsFingerprintPassthrough.
Something here is unclear, or wrong for your setup? Contact support or write to support@wirelens.app.