Skip to content

feat: add chrome151 browser fingerprint - #510

Merged
barjin merged 2 commits into
apify:masterfrom
jackc625:feat/chrome-151-fingerprint
Aug 5, 2026
Merged

feat: add chrome151 browser fingerprint#510
barjin merged 2 commits into
apify:masterfrom
jackc625:feat/chrome-151-fingerprint

Conversation

@jackc625

@jackc625 jackc625 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Adds a chrome151 fingerprint. Closes #508.

Relative to chrome142 the only wire-level TLS difference is that Chrome now leads its signature_algorithms list with the three ML-DSA codepoints 0x0904/0x0905/0x0906, which is the entire reason chrome142 produces a different JA4 from current Chrome. Ciphers, extensions, key exchange groups, ALPN, ALPS, ECH and the HTTP/2 settings are unchanged.

Depends on apify/rustls#22 (merged), which added the ML-DSA variants to FingerprintSignatureAlgorithm; the first commit here bumps the rev pin to 23b2c17.

Result

JA4
Real Chrome 151.0.7922.72 t13d1516h2_8daaf6152771_806a8c22fdea
chrome151 (this PR) t13d1516h2_8daaf6152771_806a8c22fdea
chrome142 t13d1516h2_8daaf6152771_d8a2da3f94cd

ja4_r is byte-identical to the browser:

t13d1516h2_002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0012,0017,001b,0023,002b,002d,0033,44cd,fe0d,ff01_0904,0905,0906,0403,0804,0401,0503,0805,0501,0806,0601

All seventeen request headers also match byte-for-byte in wire order, and a real request completes with status 200 while ML-DSA is advertised.

How it was captured

Against https://tls.peet.ws/api/all from consumer Chrome stable 151.0.7922.72 on Windows 11, driven headed via Playwright with a throwaway profile.

Chrome for Testing was used as a cross-check and validated first: CfT 150.0.7871.124 against consumer Chrome stable 150.0.7871.187 on the same host produced identical JA4, JA4_r, ciphers, extensions, groups, signature algorithms and HTTP/2 settings. CfT 151.0.7922.71 then agreed with the consumer 151 capture on everything except sec-ch-ua, which CfT cannot supply because it is unbranded — so that header comes from the consumer build. It is stable across launches (verified over four fresh profiles).

Two things worth knowing about the capture:

  • Chrome randomises TLS extension order per connection, so JA3 varies run to run while JA4 does not. The extension order here follows chrome142 rather than any single capture.
  • A first visit and a repeat visit differ: with a cached session ticket Chrome adds pre_shared_key, giving t13d1517h2_..._a87ad97598a9. This profile targets the cold-connection shape, which is what the issue measured and what chrome142 was compared against.

Headers carry the captured Windows platform

chrome142 advertises macOS. This profile keeps the platform it was actually captured on, so sec-ch-ua-platform and the UA string stay internally consistent. Happy to normalise to macOS if you would rather the Chrome profiles stay uniform, but that would mean constructing a UA string rather than using a captured one.

One deviation from sibling profiles, deliberately

initial_connection_window_size is 15_728_640 where the other Chrome and Firefox profiles use the wire-observed increment directly.

The field is passed to reqwest's http2_initial_connection_window_size, which h2 treats as the target window and from which it derives the WINDOW_UPDATE increment as target - 65535. So 15_663_105 emits 15_597_570, i.e. 65535 short of real Chrome, whereas 15_728_640 (15 MiB) emits exactly the 15_663_105 the capture shows.

This matches safari.rs, which already documents the same arithmetic (// 65_535 (h2 default) + 10_420_225 WINDOW_UPDATE = 10_485_760.), and matches the value #385 originally asked for. The older Chrome/Firefox profiles look like they took the number from that issue's comparison table rather than its recommendation. Left them alone here since changing them would alter existing profiles' output.

Not addressed here

Two pre-existing HTTP/2 gaps show up when diffing against the browser. Both affect every profile equally and need changes to Http2Fingerprint, so they are out of scope — happy to open issues:

Separately, on a resumed connection rustls drops session_ticket when it adds pre_shared_key, where Chrome sends both — so a second request to the same host produces a JA4 no real Chrome emits. That one is in the rustls emulation layer, not here.

jackc625 and others added 2 commits August 5, 2026 10:18
Picks up apify/rustls#22, which adds the ML-DSA variants to
`FingerprintSignatureAlgorithm`. Required by the chrome151 fingerprint,
which lists those three codepoints first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chrome stable is 151; the newest profile was chrome142. The only wire-level
TLS difference between them is that Chrome now leads its signature_algorithms
list with the three ML-DSA codepoints (0x0904/0x0905/0x0906), which accounts
for the entire JA4_c divergence reported in apify#508.

Captured against tls.peet.ws from consumer Chrome stable 151.0.7922.72 on
Windows 11, cross-checked against Chrome for Testing 151.0.7922.71 on the same
host. The two agree on everything except sec-ch-ua, which Chrome for Testing
cannot supply because it is unbranded.

Verified: JA4, JA4_r and all seventeen request headers are byte-identical to
the consumer browser, and a real request completes with ML-DSA advertised.

Requires the matching ML-DSA change in apify/rustls; until that lands and the
rev in Cargo.toml is bumped, this will not build.

Headers carry the captured Windows platform rather than the macOS strings used
by chrome142, so the UA and sec-ch-ua-platform stay internally consistent.

initial_connection_window_size is 15728640 (15 MiB) rather than the 15663105
used by sibling profiles: the field is the window size, not the increment, so
this is what makes the emitted WINDOW_UPDATE equal the 15663105 seen on the
wire.

Closes apify#508

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@barjin barjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thank you @jackc625 !

@barjin
barjin merged commit aaa7eac into apify:master Aug 5, 2026
28 of 52 checks passed
@jackc625
jackc625 deleted the feat/chrome-151-fingerprint branch August 5, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chrome profiles missing ML-DSA signature algorithms — chrome142 ceiling vs Chrome 151 stable

4 participants