HTTP/3
Protocol racing, turning QUIC off, and the known issues in native 1.16.0.
By default a session speaks HTTP/1.1 or HTTP/2, whichever the server negotiates over TLS. Browsers also try HTTP/3 (QUIC over UDP) and use whichever protocol answers first. withProtocolRacing: true does the same:
// Race HTTP/2 and HTTP/3 like a browser does; the faster one wins.
const racing = new Session({
clientIdentifier: ClientIdentifier.chrome_144, // carries real HTTP/3 settings
withProtocolRacing: true,
});
const res = await racing.get("https://cloudflare.com/cdn-cgi/trace");
console.log(res.usedProtocol); // "HTTP/2.0" or "HTTP/3.0", whichever wonres.usedProtocol tells you which protocol won. Many servers, Cloudflare included, still answer over HTTP/2 most of the time.
Turning QUIC off
disableHttp3: true keeps a session on TCP regardless of other settings:
// Never use QUIC, e.g. for high request volume (see Known issues).
const tcpOnly = new Session({ disableHttp3: true });Known issues (native 1.16.0)
These only affect sessions that actually use HTTP/3, i.e. ones with withProtocolRacing. Sessions without it are unaffected.
Most profiles have no real HTTP/3 fingerprint
Only chrome_144, chrome_144_psk, firefox_147, firefox_147_psk and
firefox_148 carry HTTP/3 settings. Every other profile sends a minimal
HTTP/3 SETTINGS frame that doesn't match the browser it imitates. Its TLS and
HTTP/2 fingerprints are unaffected. If the HTTP/3 fingerprint matters, use one
of those five profiles or set disableHttp3: true.
Racing under heavy concurrency can crash the process
With many racing requests in flight at the same time, native 1.16.0 can crash
the process. Use disableHttp3: true for high request volume.
- Proxies: racing needs a SOCKS5 proxy or none. With an HTTP proxy every request fails with
status: 0, because HTTP proxies can't tunnel UDP. See Proxies.
Custom HTTP/3 fingerprints
On the custom fingerprint path (ja3string, no clientIdentifier), these options describe the HTTP/3 connection:
// On the ja3string path, the HTTP/3 SETTINGS frame is configurable too.
// (Shape only: with this JA3 string native 1.16.0 times out over QUIC.)
const custom = new Session({
ja3string:
"771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
withProtocolRacing: true,
h3Settings: {
QPACK_MAX_TABLE_CAPACITY: 65536,
MAX_FIELD_SECTION_SIZE: 262144,
QPACK_BLOCKED_STREAMS: 100,
},
h3SettingsOrder: [
"QPACK_MAX_TABLE_CAPACITY",
"MAX_FIELD_SECTION_SIZE",
"QPACK_BLOCKED_STREAMS",
],
h3PseudoHeaderOrder: [":method", ":authority", ":scheme", ":path"],
h3SendGreaseFrames: true,
});| Option | Sets |
|---|---|
h3Settings | The HTTP/3 SETTINGS frame, by name (see H3Settings). |
h3SettingsOrder | The order of those settings. |
h3PseudoHeaderOrder | Pseudo-header order on HTTP/3 requests. |
h3PriorityParam | The HTTP/3 priority parameter. |
h3SendGreaseFrames | Whether to send GREASE frames, as Chrome does. |
A working custom HTTP/3 fingerprint also needs a ClientHello that QUIC accepts. With the JA3 string above, native 1.16.0 timed out over QUIC (HTTP/3 request failed: timeout: no recent network activity). Prefer one of the profiles listed under the first known issue when you need HTTP/3.