node-tls-clientLatest version on npm

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 won

res.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,
});
OptionSets
h3SettingsThe HTTP/3 SETTINGS frame, by name (see H3Settings).
h3SettingsOrderThe order of those settings.
h3PseudoHeaderOrderPseudo-header order on HTTP/3 requests.
h3PriorityParamThe HTTP/3 priority parameter.
h3SendGreaseFramesWhether 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.

On this page