Privacy tools
What a site actually learns from your public IP, request headers, and JavaScript-readable hardware — plus how to redact HAR files, URLs, and tokens before you share them.
3 tools
Three observers, three layers of data
By the time your JavaScript runs, the site already knows a great deal. The transport layer has handed it the public IP address you exited from, and from that address alone: the ASN announcing the prefix, a coarse geographic guess, the negotiated HTTP version, and the TLS version your client offered. None of this is optional, none of it involves a cookie, and every reverse proxy in the path logs most of it by default. The IP Address Checker shows what your own connection exposes — IP, city, region, country, ISP, ASN, timezone, the edge PoP that terminated the request, HTTP protocol and TLS.
The second layer is what the browser volunteers in request headers:
User-Agent, Accept-Language, Accept-Encoding, Referer, and the
Sec-CH-UA-* client hints. Cheap to collect, logged everywhere, and — unlike
the network layer — self-reported, so also trivially spoofed. The third layer
is what script measures after load: screen.width and devicePixelRatio,
Intl.DateTimeFormat().resolvedOptions().timeZone,
navigator.hardwareConcurrency, navigator.deviceMemory, maxTouchPoints,
plus rendering artefacts from <canvas>, WebGL, AudioContext and font
probing. The Browser Fingerprint Test reads that layer
locally, down to a canvas rendering signature.
The mental model that matters: no single value has to be secret. Your
timezone is public information. Fingerprinting works on the joint distribution
— a value shared by one user in 2^k contributes k bits of entropy, and bits
accumulate, with roughly 33 bits separating one person from 8.6 billion.
Correlated signals add less than the sum of their parts (platform: MacIntel
and a Macintosh user agent are nearly the same bit), so published per-attribute
figures never simply add up. Panopticlick measured roughly 10.0 bits for the
User-Agent, 6.09 for the Accept headers, 4.83 for screen resolution plus
colour depth and 3.04 for timezone; the much-quoted ~18.1 bits was the average
for a whole fingerprint in that study, dominated by plugin (15.4 bits) and font
(13.9 bits) enumeration that modern browsers have largely closed off — and
because the header and screen values overlap, they cannot combine to more than
that whole-fingerprint average. Later work on a far larger population
(Gomez-Boix et al., 2 million fingerprints) found everyday browsers less unique
still. The lesson is the mechanism rather than a target number: a dozen boring
attributes are enough to keep a returning visitor recognisable with no cookie at
all.
Two consequences engineers get backwards: the IP address is the most durable
identifier in the stack and one of the weakest location signals; and entropy is
symmetric, so spoofing a value to something unusual makes you more
identifiable. A User-Agent claiming iPhone next to a 3440×1440 screen, 16 CPU
cores and maxTouchPoints: 0 is a fingerprint of one.
Signal reference
| Signal | Observer | Approx. entropy | Stability |
|---|---|---|---|
| Public IP | Network, pre-JS | High, shared with NAT peers | Changes per network / VPN |
| ASN + organization | Network, pre-JS | ~5–10 bits | Stable per ISP |
Accept-Language | Request header | ~5–8 bits | Very stable |
User-Agent, Sec-CH-UA-* | Header + JS | ~10 bits, shrinking | Stable until browser update |
| Timezone | JS | ~3–5 bits (~400 IANA zones) | Travels with you, not the IP |
Screen + devicePixelRatio | JS | ~5–8 bits | Changes when you dock a monitor |
CPU cores (hardwareConcurrency) | JS | ~2–3 bits | Fixed per machine; a raw count, not bucketed (6, 10, 12, 20 all common) |
Device memory (deviceMemory) | JS | ~1–2 bits | Fixed; bucketed to 0.25/0.5/1/2/4/8 GB and capped at 8 |
| Canvas rendering | JS | ~8 bits | Very stable per GPU + driver |
| WebGL renderer string | JS | ~10 bits or more | Very stable |
| Font enumeration | JS | High on desktop | Stable per install |
Cookie / localStorage ID | Server-assigned | Unique by design | Until the user clears it |
Figures are order-of-magnitude estimates from published population studies, not a measurement of your browser: a signal is worth more bits in a diverse population and fewer in a homogeneous one. Note that the last row is the only identifier a user can delete — everything above it regenerates on the next visit.
What leaves with the artifact
Most real leaks are not tracking. They are a debug artifact pasted into a ticket.
| Artifact | What the receiver gains | Fields that carry it |
|---|---|---|
| HAR export | A working session, plus every response body that tab could read | Cookie, Set-Cookie, Authorization, x-api-key, ?token=, postData.text, content.text |
| A URL in a ticket | Account identity, and access that keeps working until it expires | ?session=, ?sig=, X-Amz-Signature, tracking params holding a hashed email |
| A JWT in a bug report | Who the user is and what they may do — no key needed to read it | sub, email, tenant, roles, exp |
Raw mail headers, .eml | The sender’s real path and your internal topology | Received: (from host, originating IP), X-Originating-IP, internal by hostnames |
| A log line in a ticket | The user’s real IP alongside device model and OS build | X-Forwarded-For, remote_addr, User-Agent model tokens (SM-G991B, Build/…) |
| DevTools screenshot | Whatever panel was open, as pixels no secret scanner will catch | Network → Response body, Application → Cookies Value column |
Which tool for which question
“What address am I on right now?” is the one question that cannot be answered
locally: only a remote endpoint sees the address you exit from, which is why
IP Address Checker queries api.sitekits.dev (metadata echoed
back, nothing stored). ifconfig gives you a LAN address, not the one your
firewall allowlist needs. “What can a script read about this machine?” is the
opposite case, entirely local: Browser Fingerprint Test
covers the header, screen and hardware rows plus a truncated canvas signature,
but does not enumerate fonts, WebGL or audio — read it as an inspection aid,
not a uniqueness score. Reach for User Agent Parser
instead when you have a UA string from a log and no live browser.
Use HTTP Headers Checker to audit what an origin says about
your privacy: Referrer-Policy decides how much of the URL is forwarded to
third parties, Set-Cookie flags decide how long an assigned identifier
survives. The fetch is server-side, so you get raw origin headers without
browser noise — headers only, never the body.
Routing the table above: put a HAR export through
HAR File Sanitizer before it leaves your machine — it
replaces the matching headers, query-string tokens and both bodies with
[REDACTED] and reports how many values it touched — then open the sanitized
copy in HAR File Viewer to confirm the timings and status codes
you needed survived; that pairing is covered in the HAR guide.
Expand a suspicious link with URL Parser before you paste it,
decode a captured token with JWT Decoder to see exactly which
claims you would be forwarding, and run a raw header block through
Email Header Analyzer to see the Received: chain you are
about to publish. Those four run in the page and upload nothing. A screenshot
has no such option: crop it, because blurring is not redaction. Token hygiene
more broadly sits under security tooling and
/for/security/.
Gotchas
Treating geolocation as a position
The city field is where the prefix is registered. Mobile carriers land whole
regions on one record, and a datacenter ASN carrying a residential-looking city
is a contradiction worth investigating rather than trusting.
Redacting only the fields you can see
Pattern-based redaction matches a fixed list of header names and parameter
names containing token|key|secret|password|passwd|pwd|auth|session|sig|signature.
A secret in a URL path segment (/v1/reset/9f3a…) or under a house-style name
is missed. Skim the sanitized output before attaching it.
Forgetting the URL itself is data
Query strings land in Referer headers, CDN access logs, browser history and
analytics pipelines. That is why signed URLs expire, and why personal data
should never be a query parameter. Parse before you paste.
Assuming a browser-side HTTP client is neutral
REST API Tester sends requests from your browser straight
to the URL you type — no sitekits server in the path. Good for privacy, but the
target therefore sees your real IP, your User-Agent, and any credential you
paste into the header box. Use a throwaway token when the endpoint is not yours.