Back to Blog
Blog23 min read

The First 100 Milliseconds: What Servers Know Before the Page Loads

W
WHOX Research
February 13, 2026
The First 100 Milliseconds: What Servers Know Before the Page Loads

Walk into a store you've never visited. Don't say a word. Don't touch a thing. Just stand in the doorway.

Staff already clocked your shoe brand. Already know whether you drove or cabbed it. Already spotted bags from a competitor. Greet warmly, watch on camera, or page security > that call was made before you opened your mouth.

Same energy on the web. Every time you load a site, the server harvests a frankly unnerving volume of data about you before rendering a single pixel. Operating system. Browser. VPN. Mobile carrier. Country. All ripped from the raw mechanics of how your machine says hello.

Roughly 100 milliseconds. A tenth of a second. Blink and you've missed three full cycles.

None of this requires exotic government gear. Standard infrastructure. Every major CDN runs it. Every bot-detection service runs it. Baked right into how the internet works at the protocol layer, and it's been that way for years.

In brief: Servers identify your OS, VPN, and browser within 100ms through TCP, TLS, and HTTP/2 protocol fingerprints > before any JavaScript runs or cookies are set.


Act 1: The Knock

29200_2-4-8-1-3_1424_7.

One string. Hundreds of scanning machines unmasked. Stick around.

Before your browser can fetch a webpage, it opens a TCP connection. Your machine fires off a SYN packet. Server responds. Your machine confirms. Connection open. Ten to thirty milliseconds. Boring protocol plumbing nobody thinks twice about.

Except that very first SYN packet is straight up leaking your identity.

Every OS implements TCP a little differently. Not in what it does > in how. Engineers who wrote your networking stack made specific calls about window sizes, TCP options, and the order those options show up. Windows skips the timestamp option entirely. Every Unix-based system includes it. iOS slaps on an extra End of List padding that no other OS uses. Decisions made years ago by individual kernel developers, now fossilized into billions of devices as permanent fingerprints.

John Althouse at FoxIO laid all of this bare when he dropped JA4T, the TCP fingerprinting piece of the JA4+ suite, in April 2024. Working with GreyNoise, an internet intelligence outfit, he proved how devastating the technique is. Remember that string from above? 29200_2-4-8-1-3_1424_7 kept showing up across hundreds of source IPs. Options pattern 2-4-8-1-3 screamed Unix. MSS of 1424 pointed to 36 bytes of tunnel overhead > likely an unencrypted tunnel or proxy, since 36 bytes isn't enough for VPN encryption. All those IPs traced back to Tencent ranges. Hundreds of scanning machines identified from one packet field.

Maximum Segment Size is the most loquacious detail in the handshake. Standard Ethernet yields an MSS of 1460. VPN encryption adds overhead that shrinks that number. WireGuard yields one value. OpenVPN yields another. IPsec a third. From your very first packet, the server can tell whether you're behind a VPN and roughly what flavor. Mobile carriers stamp their own MSS too. Althouse showed JA4T can sometimes distinguish T-Mobile from Verizon just from the SYN packet.

WHOX check A06 measures exactly this: MTU and TTL patterns of your connection, sniffing out VPN tunnels and mapping your network path. Check C09 folds TTL, MTU, and round-trip time into a composite anomaly score. Server-side, that analysis wraps up before your browser sends its first byte of actual content.

Each OS leaves a telltale TCP signature. JA4T format encodes window size, TCP options, MSS, and window scale factor into a single string. Typical signatures:

OS Window Options MSS Scale JA4T
Windows 10/11 65535 2-4-8-1-3 1460 8 65535_2-4-8-1-3_1460_8
Linux 5.x+ 29200 2-4-8-1-3 1460 7 29200_2-4-8-1-3_1460_7
macOS 65535 2-4-8-1-3 1460 6 65535_2-4-8-1-3_1460_6
iOS 65535 2-4-8-1-3-0 1460 6 65535_2-4-8-1-3-0_1460_6
Android 65535 2-4-8-1-3 1460 9 65535_2-4-8-1-3_1460_9

iOS tacks on that extra End of List option nobody else uses. Android's scale factor of 9 runs higher than any desktop OS. Manufacturing-era fingerprints baked into kernel code you'll never touch.

Zero-Overhead Fingerprinting

LLM scraping pushed a developer over the edge.

In 2025, Alberto Ventafridda published an open-source Go webserver using eBPF to fingerprint TCP connections at the kernel level. His words: the rising need to scrape the internet for human content to feed LLMs made TCP fingerprinting a hot topic. So he built a tool that intercepts packets at the network interface via eBPF's XDP hook > before they even reach the kernel's TCP stack. Fingerprint captured with essentially zero overhead, stashed in a kernel-space hashmap, ready by the time the webserver accepts the connection. No extra threads. No packet copying. No added latency.

Bouncer reading your driver's license through the envelope before you hand it over.

The p0f Legacy

None of this started in 2024. Rewind to June 10, 2000.

Security researcher Michal Zalewski dropped a tool called p0f on the Bugtraq mailing list. Passive OS fingerprinting. Watch TCP traffic flow by without sending a single probe packet, and identify the operating system at the other end purely from how it built its SYN packets.

p0f read initial TTL from the IP header, TCP window size, maximum segment size, the don't-fragment bit, ordering of TCP options like window scaling and selective acknowledgment. Each OS made slightly different calls. Windows set a TTL of 128. Linux set 64. OpenBSD used a particular window size nobody else touched. Match combinations against a signature database, and you've got the remote OS without ever being detected. Unlike nmap, which fires crafted probe packets firewalls can spot, p0f just listened. Pure eavesdropping.

Adoption was ferocious. OpenBSD integrated p0f's logic into its PF packet filter in 2003, letting admins write firewall rules keyed to the connecting machine's OS. Ettercap, Prads, Satori, pfsense, amavisd > all ran p0f under the hood. Version 3, released in 2012, bolted on application-level payload analysis, IDing HTTP clients by their header ordering.

p0f proved the concept a quarter century ago: passive observation of standard protocol behavior is enough to finger who you are. JA4T extends that insight to the modern internet with structured hashing, VPN overhead detection, and carrier identification Zalewski never attempted. Lineage is direct. Capability has grown by orders of magnitude.

You haven't sent a single byte of content. Server already knows your OS, your network path, and whether you're hiding behind a tunnel.


Act 2: Twenty Trillion Permutations, One Sort Function

TCP wraps up. Now your browser sets up encryption through the TLS handshake, kicking off with the Client Hello > sent in the clear, because you've got to negotiate encryption before you can encrypt anything.

Spoiler: that Client Hello is a detailed dossier of your software stack, unencrypted, readable by every network device sitting between you and the server.

Supported TLS versions, cipher suites, extensions, elliptic curves, Alpn preferences > all in there. A Chrome Client Hello looks nothing like Firefox. A Python script looks nothing like either. Even different versions of the same browser spit out distinct fingerprints.

2017, Salesforce researchers John Althouse, Jeff Atkinson, and Josh Atkins published JA3: grab five fields from the Client Hello, concatenate them, hash with MD5. Simple. Elegant. Wildly effective. Cloudflare adopted it. Every major security tool integrated it. For six years JA3 was gospel for identifying what's hitting your server.

Then Google torched the whole thing.

Early 2023, Chrome started randomizing the order of TLS extensions in every Client Hello. Stated reason: force servers to quit relying on a specific extension order and actually respect RFC 8446. Effect on fingerprinting? Total annihilation. Stamus Networks ran the math. A single Chrome installation with 16 TLS extensions now generates 16 factorial possible orderings. That's 20,922,789,888,000 different JA3 hashes. Twenty point nine trillion. One browser. One machine. One user. For scale, the Milky Way holds 100 to 400 billion stars. One Chrome install generates more JA3 variations than stars in our galaxy.

Overnight, JA3 went from reliable identifier to static noise. Stamus Networks wrote it flat out: JA3 has been rendered useless for identifying clients and user agents.

Chrome holds roughly two thirds of the browser market. Useless for Chrome means useless for most of the internet. Full stop.

Here's where it gets wild. John Althouse, same researcher who created JA3, had moved to FoxIO. When Chrome dropped the randomization bomb, he was already locked and loaded with JA4.

Fix: sort the extension list before hashing.

Chrome shuffled the deck. JA4 sorts it back into order before looking at the cards. Redesign added a human-readable format, QUIC support, and a modular a_b_c structure. Core insight that neutralized twenty trillion permutations? A single sort function. Fight me on this being the most elegant countermove in fingerprinting history.

WHOX check C12 runs that comparison on every visitor: JA4 fingerprint of the TLS handshake versus the browser claimed in the User-Agent. Mismatch means the software talking to the server isn't what it says it is.

Most sophisticated randomization defense in browser history, defeated by alphabetical sorting. Protocol layer doesn't forget, no matter how hard you shuffle.


Act 3: The Hardcoded Confession

TCP done. TLS negotiated. Now your browser speaks HTTP/2 to request the actual page. And in doing so, hands over another fingerprint most people have never heard of.

Even after encryption locks down, the values your browser fires inside the encrypted tunnel identify you perfectly.

HTTP/2 communication runs on binary frames. Very first frame your browser sends is a SETTINGS frame on stream 0, announcing preferences for maximum concurrent streams, initial window size, header table size, and maximum frame size. Hardcoded by browser developers. Never changes based on which site you're visiting. Identical for every connection your browser ever makes.

Akamai researchers first documented these fingerprints at Black Hat EU 2017. TU Munich later built an extended tool to capture them. Results are damning.

Chrome sends a header table of 65,536, maximum 1,000 concurrent streams, and an initial window of roughly 6 megabytes. Firefox sends the same header table but an initial window of only 128 kilobytes and a max frame size Chrome doesn't bother setting.

Right after SETTINGS, each browser fires a WINDOW_UPDATE frame to bump the connection-level window. Chrome requests 15,663,105 bytes. Firefox requests 12,517,377. Different numbers. Same purpose. Perfect identification.

Then the detail that seals everything. In HTTP/2, the request line splits into pseudo-headers: :method, :authority, :scheme, :path. Every browser sends all four. In different orders.

Chrome: m,a,s,p. Firefox: m,p,a,s. Safari: m,s,p,a. curl: m,p,s,a.

All four orderings are valid. HTTP/2 spec doesn't mandate one. Each browser team independently picked theirs, and now it's a permanent accent > like saying elevator vs lift vs Aufzug vs ascenseur. Arbitrary, but it pins exactly where you come from.

Two sessions three days apart showing identical HTTP/2 SETTINGS, identical TLS fingerprint, identical WINDOW_UPDATE values? Linked as the same browser. Even if the IP changed. Even if cookies were nuked.

WHOX check A18 catches this: HTTP/2 SETTINGS frame compared against what the claimed browser should send. FORESIGHT session-linking engine uses these same values as high-weight network signals. Your JA4 hash, your HTTP/2 settings, your Alpn preferences. Stable identifiers that survive cookie wipes, IP changes, and incognito mode.

Firefox has one more tell. Builds a complex priority tree at the start of every HTTP/2 connection by firing Priority frames for streams 3, 5, 7, 9, and 11 with specific parent-child relationships and weights. Stream 3 gets weight 201. Stream 5 gets weight 101. Streams 7, 9, and 11 get weight 1. Exact tree, exact weights, unique to Firefox. Chrome does nothing remotely close. Firefox walks into every room and immediately rearranges the furniture in a pattern nobody else uses.

Your browser confesses its identity in hardcoded values you can't change, can't disable, and probably didn't know existed. Encryption hides them from eavesdroppers. Not from the server.

The curl-impersonate Paradox

February 2022. A pseudonymous developer called lwthiker dropped a project on GitHub that became the Swiss Army knife of the fingerprinting arms race: curl-impersonate. Take curl, the command-line HTTP tool shipping on nearly every Unix system, and patch it so its network handshakes look identical to a real browser's.

Engineering was gnarly. Chrome variant: lwthiker compiled curl against BoringSSL, Google's fork of OpenSSL. Firefox variant: built against NSS, Mozilla's own TLS implementation. Swapping the TLS library was just the preamble. lwthiker modified how curl configured TLS extensions, added support for Google-specific extensions like compress_certificate and application_settings, and changed the HTTP/2 SETTINGS values curl sends at connection startup. Every value had to match exactly, because even a single wrong window size or frame setting gives you away. Pivotal moment from lwthiker's blog: after matching the entire TLS Client Hello to Chrome's, the tool was still getting caught. Two small differences in the HTTP/2 frames revealed how deep fingerprinters actually look.

Project Readme doesn't mince words: with the modified curl, TLS and HTTP handshakes look exactly like those of a real browser. Now supports impersonation of Chrome, Edge, Safari, and Firefox across dozens of version targets.

Here's the paradox. lwthiker built curl-impersonate to demonstrate that TLS and HTTP/2 fingerprinting make the web less open, less private, and way more restrictive toward specific web clients. Protest tool. Proof of concept that the open web was closing. Bot operators adopted it overnight. An active fork maintains updated browser profiles. Commercial scraping services wrap it into their products. Tool that exposed how fingerprinting restricts the open web became the primary weapon for circumventing those restrictions.

Irony is thick enough to cut.


Act 4: The Clock

You pressed Enter. Here's what happened.

Blink once. Time it takes your eyelid to drop and rise > roughly 300 milliseconds > the entire sequence below has already finished three times over.

SYN packet leaves your machine. Carries your operating system's accent, your network path's overhead, a VPN tell if you're running one. At 15 milliseconds, TCP handshake finishes and TLS Client Hello fires. Your browser's entire cipher suite preference list, extension set, and protocol support travels in the clear. Server computes a JA4 fingerprint in under a microsecond.

30 milliseconds in, something happens most people don't realize. If the server is Cloudflare, your JA4 hash is already being cross-referenced against JA4 Signals, a behavioral database aggregated from the last hour of global traffic. On any given day, Cloudflare processes over 15 million unique JA4 fingerprints from more than 500 million user agents. Your hash isn't just an ID. It's an index into how every other connection sharing that same fingerprint has behaved today. What percentage came from real browsers. How many tripped bot flags. How much bandwidth they chewed through.

By 50 milliseconds, TLS wraps up. By 70, your browser sends HTTP/2 SETTINGS and WINDOW_UPDATE frames confirming the exact browser version. Pseudo-header order seals it.

By 90 milliseconds, the HTTP request for the actual page goes out. Server already knows your OS, your browser, your TLS library, your network topology, and how trustworthy your fingerprint looks stacked against billions of other connections.

Every fingerprinting service with server-side access captures this same sequence. WHOX lays out the full chain: TCP, TLS, HTTP/2, all readable before the first byte of content arrives.

All of that is just HTTP/2. QUIC and HTTP/3 are the next frontier, and they're already getting picked apart.

QUIC runs over UDP instead of TCP, which means SYN-packet fingerprinting changes entirely. QUIC introduces its own transport parameters, flow control values, and connection setup patterns that are just as fingerprintable. Early research shows QUIC initial packets carry version negotiation fields, transport parameter lists, and flow control windows that vary by implementation. Google's QUIC stack looks different from Cloudflare's, which looks different from Apple's.

Researchers at UC San Diego demonstrated in a 2022 paper they could fingerprint Chrome and Firefox using only QUIC transport parameter values > settings exchanged at connection startup defining flow control limits, maximum idle timeouts, and stream concurrency. A 2021 ETH Zurich paper, Website Fingerprinting in the Age of QUIC, showed QUIC connections are just as vulnerable to traffic analysis as TCP, with browser identification possible from initial packet sizes alone. Encryption QUIC applies to its payload doesn't help when the structure and timing of the packets themselves are distinctive.

Arms race has already migrated. Refraction Networking group at the University of Colorado Boulder built uQUIC, a fork of the standard quic-go library giving low-level access to customize the QUIC Initial Packet > first unencrypted packet in a QUIC connection, the one that spills fingerprintable data. Goal: censorship circumvention. If a censor can ID your QUIC implementation from its Initial Packet, you need the ability to mimic a different one. JA4 already handles QUIC natively, marking QUIC connections with a q transport indicator instead of t for TCP, and fingerprinting the TLS Client Hello embedded within the handshake. Game doesn't end. Migrates to a new protocol with new tells.

You haven't clicked anything. Haven't logged in. Haven't filled out a captcha. Haven't run a single line of JavaScript. Server finished reading you in a tenth of a second. Everything after that was just deciding what to do about it.


You Were Sorted Before You Arrived

Here's what most privacy guides won't cop to.

You don't browse the internet. You are browsed. Before the page loads, before any cookie gets set, before any pixel tracking fires, the server has already slotted you into a behavioral bucket based on protocol fingerprints you can't control. Real human on residential WiFi. Suspicious automation on datacenter IP. VPN user with tunnel overhead matching a known WireGuard profile. Python script pretending to be Chrome but sending the wrong HTTP/2 window size.

Sorting happens to every connection. Billions of times per day. Buckets determine everything that follows: whether you see a captcha, whether prices shift, whether your account gets flagged, whether your traffic even reaches the real server or gets shunted to a honeypot.

The Bot Arms Race

60 million requests per second. Over 300 data centers. Cloudflare processes all of it, and a massive chunk is automated: scrapers, credential stuffers, inventory hoarders. Fingerprinting stack described above is the first trench. No single fingerprint is definitive > a bot might spoof the TLS fingerprint. Does it also match the right HTTP/2 SETTINGS though? Right pseudo-header order? Correct MSS for a residential connection? Each layer stacks another requirement the bot has to satisfy.

Cloudflare's JA4 Signals blog post from August 2024 spelled out the strategy. Because Cloudflare sees traffic from a huge slice of the entire internet, it can aggregate behavioral patterns across billions of connections sharing the same JA4 fingerprint. Fingerprint shows up in 10 million requests today and 94 percent came from verified human browsers? Next connection with that fingerprint gets a high trust score. Fingerprint appears in only 200 requests, all from datacenter IPs, all hammering login endpoints? Flagged before the first byte of content is served. Fingerprinting at planetary scale turns individual spoofing into a futile exercise > server evaluates your hash against the collective behavior of every other connection sharing it.

Arms race is absolutely real. A site called impersonate.pro hawks full-stack TLS/H2/H3/JS fingerprint collection and vibe crawling for $99 a month. Weekly updated fingerprints, HTTP/3 impersonation, UDP proxy support, JavaScript fingerprint data.

Turns out the irony of fingerprinting is baked right into the ecosystem: defenses are published, specs are open, and every time a researcher documents a new technique, bot operators get a shopping list of what to fake next.

The Privacy Bind

All of this happens passively. No cookies. No JavaScript. No installation. Server reads protocol metadata your machine sends voluntarily as part of normal communication. Zero opt-out. You can't tell your OS to stop putting TCP options in SYN packets. You can't tell your browser to stop sending SETTINGS frames.

VPNs help in some ways, hurt in others. Hide your IP but change your MSS, minting a fresh fingerprint. Tor Browser normalizes its TLS fingerprint across all users, but the FOCI 2025 paper showed even Snowflake's Dtls handshake leaks identifiers.

Fingerprints are stable across sessions. Clear your cookies, switch to incognito, nuke your browsing history. None of it touches your TCP options, your TLS Client Hello, or your HTTP/2 SETTINGS frame. Those stay identical because they're determined by your software, not your choices.


What You Can't Fix

What actually works? Honest answer is uncomfortable.

Tor Browser is the most serious stab at protocol-level uniformity. All Tor Browser users share the same TLS fingerprint because the browser presents identical cipher suites, extensions, and TLS parameters regardless of the underlying OS. Tor Project's documentation says it flat out: goal is shrinking the number of distinguishable buckets so individual tracking gets harder. Tor Browser is built on Firefox though, which means it inherits Firefox's HTTP/2 fingerprint > that distinctive priority tree with streams 3, 5, 7, 9, and 11 and their specific weights. Any server receiving a Tor Browser connection over HTTP/2 knows it's Firefox-based, even if the TLS layer looks scrubbed clean.

Mullvad Browser, built by Mullvad VPN in collaboration with the Tor Project, applies many of the same anti-fingerprinting techniques without routing through the Tor network. Normalizes screen size, blocks third-party trackers, resists JavaScript-based fingerprinting. Community researchers on the Privacy Guides forum noted Mullvad Browser has WebRTC enabled and a slightly different NoScript configuration than Tor Browser, meaning its application-layer fingerprint doesn't fully match. At the protocol level, it still fires Firefox's HTTP/2 SETTINGS and priority frames. Server still knows.

Firefox's built-in resist fingerprinting mode, toggled through privacy.resistFingerprinting in the config editor, spoofs screen dimensions, timezone, locale, and canvas output. All application-layer defenses. TLS Client Hello, HTTP/2 SETTINGS frame, and TCP options remain completely untouched. A server running JA4 fingerprinting sees the same result whether that setting is on or off. WHOX check C12 confirms it: flip that switch and the protocol-layer fingerprint doesn't budge.

Brave focuses on farbling > randomizing JavaScript-accessible values like canvas, WebGL, and audio fingerprints per site. An open issue on Brave's GitHub tracker, number 21625, confirms that even with fingerprinting protection cranked to aggressive, Brave doesn't prevent TLS fingerprinting. Under the hood, Brave is Chromium. Sends Chrome's TLS fingerprint, Chrome's HTTP/2 SETTINGS, Chrome's pseudo-header order. m,a,s,p. Every single time.

Pattern is glaring. Every major privacy browser protects the JavaScript layer. Not one of them modifies the protocol-level fingerprints laid out in this article. TCP, TLS, and HTTP/2 signals travel below the altitude where browser privacy features operate.


The Last Packet

History of network fingerprinting compresses like a geological stratum. JA3 dominated from 2017 to 2023. Chrome killed it with randomization. JA4 replaced it within months. Bot operators adopted curl-impersonate to fake JA4. Defenders correlated fingerprints across TCP, TLS, and HTTP/2 layers. Attackers started faking all three. Defenders added behavioral signals computed across billions of requests.

Fundamental asymmetry will never budge. Fingerprinting works because different software makes different choices at the protocol level. Chrome's HTTP/2 windows are tuned for Chrome's performance goals. Firefox's priority tree reflects Firefox's loading strategy. Differences exist for real engineering reasons. Standardizing them would mean every browser performing identically, and that's never happening.

Every connection you make fires a multi-layered identity signal built from decades of engineering decisions by OS developers, browser teams, TLS library maintainers, and protocol designers. None of them intended to create a surveillance mechanism.

That's exactly what they built.



Frequently Asked Questions

What is server-side fingerprinting? Server-side fingerprinting identifies visitors using TCP, TLS, and HTTP/2 protocol metadata sent automatically by your computer during connection setup > before any JavaScript runs. Works without cookies, without scripts, and can't be blocked by browser extensions.

Can a VPN protect against protocol fingerprinting? A VPN hides your IP address but changes your Maximum Segment Size, creating a new fingerprint. WireGuard, OpenVPN, and IPsec each produce different MSS values. Server can detect VPN use and sometimes identify the specific VPN protocol from your very first packet.

What is JA4 fingerprinting? JA4 is a TLS fingerprinting method created by John Althouse at FoxIO in 2023, replacing JA3 after Chrome's extension randomization made JA3 obsolete. JA4 sorts TLS extensions before hashing, defeating randomization. Adopted by Cloudflare, AWS, Google Cloud, and dozens of security tools.

Does incognito mode prevent server-side fingerprinting? Nope. Incognito mode clears cookies and browsing history on your device. TCP options, TLS Client Hello, and HTTP/2 SETTINGS frames are identical in incognito and normal mode because they're determined by your software, not your browsing state.

Which browser best resists protocol fingerprinting? Tor Browser is the only browser that normalizes its TLS fingerprint across all users. Still sends Firefox's HTTP/2 SETTINGS and priority frames though. No browser currently modifies all three protocol layers > TCP, TLS, HTTP/2 > for fingerprinting resistance.



WHOX - We tell real signals from manufactured ones. Check your fingerprint at whox.com and find out what signals leak from your browser and how unique you are.

Sources: FoxIO JA4+ documentation, September 2023 and April 2024. Cloudflare JA4 Signals blog, August 2024. Stamus Networks analysis of TLS extension randomization. Alberto Ventafridda's eBPF TCP fingerprinting series, 2025. TU Munich HTTP/2 fingerprint research. Midtlien and Palma, Fingerprint-resistant Dtls for usage in Snowflake, FOCI 2025. Fastly, The State of TLS Fingerprinting. Michal Zalewski, p0f v3 documentation. lwthiker, curl-impersonate documentation and blog posts, 2022. Turner et al., Evaluating QUIC for Privacy Improvements Over Its Predecessors, UC San Diego, 2022. Smith et al., Website Fingerprinting in the Age of QUIC, PETS 2021. Refraction Networking, uQUIC project documentation. Brave browser GitHub issue #21625. Privacy Guides community, Mullvad Browser fingerprinting discussion.

tcptlsserver-side100ms

Related Articles