Open any website and, before the page has finished rendering, a small amount of information
about you has already left your device. None of it required a popup, a permission prompt, or a
single click. It's just how HTTP and the browser platform work, and it's been true since long
before "privacy" was a marketing category.
Most explanations of this lump everything into one long list. It's clearer split by where each
piece of information actually comes from, because the three layers behave very differently:
what you can block, what a site can request, and what genuinely can't be hidden without breaking
the page.
Three layers of exposure
Layer 1: what the network already reveals
Your IP address is the most obvious one. It's visible to any server you connect to directly, simply because that's how a response knows where to go, and it typically narrows your location down to a city or region even without anything else.
Less obvious: the shape of your TLS handshake, the initial negotiation that sets up an encrypted connection, is itself a fingerprint. The specific order and combination of ciphers, extensions, and versions your browser offers during that handshake varies enough between browser versions and configurations that it can be reduced to a short hash, commonly called a JA3 or JA4 fingerprint. Two different visits from the same browser version tend to produce the same TLS fingerprint, which is one of the reasons a VPN or proxy alone doesn't fully anonymize a connection: the network path changed, but the "shape" of the handshake didn't. The domain you're connecting to is also, by default, visible at this layer through the SNI field, a topic covered in more depth in our DNS explainer.
Layer 2: headers sent before any page loads
Every HTTP request carries a set of headers along with it automatically. None of this requires JavaScript, cookies, or any interaction, it's built into how a browser constructs a request.
| Header | What it reveals |
|---|---|
| User-Agent | Browser and OS identity, though heavily reduced in modern Chrome (see below) |
| Accept-Language | Preferred language(s), often a strong regional signal |
| Accept-Encoding | Which compression formats your browser supports |
| Referer | The URL of the page you came from, if any |
| Cookie | Any stored cookies for that domain, covered in our cookies guide |
| Sec-CH-UA | Structured browser brand and major version (see below) |
| Sec-Fetch-Site / Mode / Dest | Context about how the request was triggered (navigation, image load, script, and so on) |
| Sec-GPC | Global Privacy Control signal, if enabled, indicating an opt-out preference for data sale/sharing |
The User-Agent string isn't what it used to be
This is worth calling out specifically because it's a genuine, under-reported privacy improvement, not the usual story of things quietly getting worse. Older User-Agent strings were extremely detailed, often including your exact OS build and sometimes your specific device model, all sent by default on every request. Chrome finished a multi-year "User-Agent reduction" effort by 2023, and the header now reports a frozen, generic value: Windows versions all appear as Windows NT 10.0, and minor version numbers show as 0.0.0 regardless of your actual browser build.
The detail didn't disappear, it moved. A separate mechanism called Client Hints (Sec-CH-UA and related headers) sends a small, structured set of low-detail information by default (browser brand, major version, whether you're on mobile), and only sends anything more specific, like your exact device model, if the site explicitly requests it via an Accept-CH response header. That's a meaningfully different architecture: opt-in and structured, instead of always-on and free-text.
One nuance worth knowing if you use a privacy-focused Chromium browser like Brave: Brave's main User-Agent header deliberately identifies as plain "Chrome," specifically so sites can't single out or discriminate against Brave users. But a site checking via JavaScript rather than reading the header, specifically navigator.userAgentData.brands, can still see "Brave" listed alongside "Chromium." Header-level spoofing and script-level identity aren't the same protection, and a site that wants to know badly enough usually has a way to ask a different question.
Layer 3: what JavaScript can additionally read
If scripting is enabled, and it is for almost everyone, a page can query a much wider set of properties directly from the browser, no server request required for most of it.
| Property | What it reveals |
|---|---|
| screen.width/height | Physical screen resolution and color depth |
| navigator.hardwareConcurrency | Number of logical CPU cores |
| navigator.deviceMemory | Approximate device RAM, rounded to a coarse value |
| Intl.DateTimeFormat | Your system timezone, often precise enough to narrow location further than IP alone |
| navigator.languages | Full ordered list of preferred languages, more detail than the header alone |
| WebRTC / RTCPeerConnection | Can expose local and public IPs independent of the page's normal network path, covered in our WebRTC leak guide |
Canvas, WebGL, and audio fingerprinting
These three deserve their own mention because they don't read a stored value, they generate one on the spot by asking your hardware to do a small rendering task, then measuring tiny, consistent differences in the output. A script draws an invisible shape or text string to a canvas element, then reads back the resulting pixel data. Differences in your GPU, drivers, font rendering, and even anti-aliasing settings produce a slightly different result on a per-device basis, consistent enough across visits to work as an identifier despite never touching stored data at all. WebGL fingerprinting does the same thing with 3D rendering output, and the WebGL_debug_renderer_info extension can additionally reveal your exact GPU model by name. Audio fingerprinting runs a signal through the Web Audio API and measures minor floating-point differences in how your specific hardware processes it.
None of these three require permission prompts, because from the browser's perspective they look identical to legitimate uses: a game rendering graphics, a site using audio processing. That's exactly what makes them effective for tracking and hard to block without also breaking real functionality. Our canvas fingerprint test shows exactly what your own canvas output looks like to a tracking script.
APIs that got removed for revealing too much
Browser vendors have occasionally shipped a feature, realized how effective it was as a tracking vector, and pulled it back. The clearest example is the Battery Status API, which let a page check your device's current battery percentage and charging status, a genuinely useful feature for things like warning users before a large download on low battery. Researchers later showed that the specific, frequently-changing combination of battery level and charge rate could work as a short-lived identifier, precise enough to re-link a user across sites within the same browsing session even with cookies cleared. Firefox removed the API's exposure to regular web pages not long after, and it's a useful case study: a feature can be entirely well-intentioned and still turn into a fingerprinting vector nobody planned for.
Why this adds up to more than any single signal
Almost nothing on this page is dangerous by itself. Your screen resolution alone is shared by millions of people. Your timezone alone narrows almost nothing down. The concern is entropy stacking: combine ten or fifteen individually unremarkable signals, and the resulting combination is often unique or close to it among the browsers a site sees, without a single cookie, login, or explicit tracking identifier involved anywhere in the process.
That's the entire premise behind browser fingerprinting as a tracking method, and it's why clearing cookies or using a VPN, while useful for what they actually cover, doesn't touch this layer at all. If you want to see exactly what your own current combination of signals looks like and how identifying it is, run our browser fingerprint test, which checks the same categories of signal covered in this article against your browser as it's configured right now.