TCP fingerprinting identifies a client from the very first packet it sends — the SYN packet's window size, TCP options and their order, maximum segment size (MSS), and time-to-live (TTL) — hashed into the JA4T format, the transport-layer companion to JA4's TLS fingerprint and JA4H's HTTP/2 fingerprint, revealing the operating system before a single byte of encrypted traffic is exchanged.
The TCP handshake happens before any encryption, making it the earliest fingerprintable signal in the whole connection. Every operating system's networking stack picks its own defaults for the SYN packet's window size, which TCP options it sets and in what order, its MSS, and initial TTL — Windows defaults to a TTL of 128 and skips the TIMESTAMP option that Linux and macOS both send, while Linux and macOS share TTL 64 but differ in the ordering of their own options. JA4T packs Window_Size, Options, MSS, and TTL into one comparable string, the same modular approach JA4 (TLS) and JA4H (HTTP/2) use one and two layers up.
This matters for scraping because a client's OS-level TCP fingerprint doesn't change just because its HTTP library spoofs a Chrome User-Agent header or matches Chrome's TLS ClientHello — the packet that opened the connection already committed to whatever operating system the underlying network stack actually is. A request claiming to be Chrome on macOS but opening with a Linux server's TCP defaults is inconsistent before the application layer even begins.
Fixing a TLS or HTTP/2 fingerprint means matching values a library exposes through its own configuration — curl_cffi ships pre-built TLS fingerprints, and an HTTP/2 client can be told to reorder its pseudo-headers. TCP-layer defaults are set by the operating system's kernel network stack, several layers below anything a Python or Node.js library controls, so replicating a specific browser-and-OS combination's SYN packet generally means running the traffic from a matching OS and kernel rather than something a request library can patch at runtime.
That's why anti-bot vendors treat a JA4T mismatch as a particularly strong signal: it's the layer least practical for a scraper to spoof through library-level configuration alone, and it catches a common blind spot since most scraping infrastructure runs on Linux datacenter servers regardless of what browser identity the request layer claims above it.
How Crawlora handles this
Crawlora runs its browser-rendering and proxy traffic from infrastructure whose TCP-layer fingerprint is kept consistent with the browser identity a request presents, so the JA4T check doesn't catch the OS-mismatch gap a Linux-hosted scraper claiming to be a Windows or macOS browser would otherwise leave behind.
FAQ
No — they're companion signals in the same JA4 family, read at different layers. JA3/JA4 reads the TLS handshake, JA4H reads the HTTP/2 SETTINGS frame and header order, and JA4T reads the TCP SYN packet that opens the connection before either of those even happens.
Yes — matching a browser's TLS ClientHello doesn't change the underlying operating system's TCP stack defaults. A request presenting a perfect Chrome-on-macOS TLS fingerprint from a Linux server still opens with Linux's TCP options and TTL, which JA4T flags as inconsistent.
TLS and HTTP/2 fingerprints are set by libraries a script controls directly. TCP defaults come from the operating system's kernel network stack, several layers below anything a request library configures — closing the gap generally means running traffic from infrastructure whose OS actually matches the claimed browser identity.
Beyond TCP Fingerprinting (JA4T), Crawlora's own docs cover the rest of the stack — browse the APIs, test a request in Playground, and move from scraping infrastructure work to production data workflows.