1 What arrived before you saw anything
No JavaScript produced this section. It is the HTTP request: assembled by your browser, your network, and the edge in front of this site.
Every server on the internet receives this before it receives anything else. It is not a name, but it is usually stable for hours and it is shared with everyone in your household or office.
An ISP, a mobile carrier, a hosting company, or a VPN. The name alone sorts you into a category the site can act on.
City level from the address database, not from you. The latitude and longitude are the centre of an address block, so they can be a few kilometres off, or exactly right in a small town.
Stored with the address block, not with you. Postcode is often wrong and sometimes precise.
Inferred from the address. Your browser knows its own timezone too, and the two disagreeing is the cheapest VPN detection there is.
A three letter airport code naming the Cloudflare site that terminated your TLS. It locates you within a few hundred kilometres, whatever your address says.
The negotiated version and cipher. The full list of ciphers you offered is not shown to us, but Cloudflare fingerprints it (JA3 and JA4) and scores you with it.
HTTP/3 means your browser speaks QUIC, which narrows the version. HTTP/2 behind a proxy is a different shape.
Half of it bounds your distance. A sudden change means you changed network, or a proxy did.
One identifier for one request. It exists whether or not this page is looked at, and it is how any of this can be found again.
This request carried none. If you are signed in to anything under zpe.vc, this number would not be zero.
The clock the page was assembled on. It is the server's, and it drifts from yours silently.
The raw request
Exactly what this visitor typed or sent, before any of it was interpreted. If a line is missing here that you expected, your browser chose not to send it, and that absence is itself a signal.
GET /privacy HTTP/2
accept: */*
accept-encoding: gzip, br
cf-connecting-ip: 216.73.216.40
cf-ipcountry: US
cf-ray: a4f5bb1c397b0acb
cf-visitor: {"scheme":"https"}
connection: Keep-Alive
host: zpe.vc
user-agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
x-forwarded-proto: https
x-real-ip: 216.73.216.40
Every header, and what it hands over
All 11 headers in the order they arrived. The middle column is the value this request carried. The right column is what a site can do with it. One edit: a cookie value is a credential, so it is replaced before printing. The name and the count stay, because a cookie's name is not a secret and its value has no business on a screen.
| Header | Your value | What it reveals |
|---|---|---|
| accept | */* | The file types this browser will take. A long, ordered list is a fingerprint on its own. |
| accept-encoding | gzip, br | Compression it understands. zstd support in particular dates a browser build. |
| cf-connecting-ip | 216.73.216.40 | Your address as Cloudflare saw it. This is the value the site is trusted to act on. |
| cf-ipcountry | US | The country the edge resolved your address to. |
| cf-ray | a4f5bb1c397b0acb | The identifier for this one request in Cloudflare's logs. It ties any support question to a log line. |
| cf-visitor | {"scheme":"https"} | How the edge classified your connection (https, http, or a scheme it rewrote). |
| connection | Keep-Alive | Connection handling. Under HTTP/2 most of this header is ignored, so its presence dates the client. |
| host | zpe.vc | The hostname you typed. With Cloudflare in front it also says which zone routed you. |
| user-agent | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) | Browser, version, engine and OS in one string. Roughly 10 bits: enough to sort you into a bucket of thousands, not millions. |
| x-forwarded-proto | https | |
| x-real-ip | 216.73.216.40 | Another proxy convention for the same fact as cf-connecting-ip. |
Not sent, which is also information
These are the headers a site looks for and this request did not carry. A missing Cookie says you are not signed in. A missing Sec-CH-UA says you are not on Chromium. A missing DNT or Sec-GPC says you have not asked anyone to stop.
dnt sec-gpc referer cookie authorization sec-ch-ua sec-ch-ua-full-version-list if-none-match if-modified-since range
The edge object, unedited
Cloudflare hands the worker this object beside the request. It is printed as it arrived, key by key, including the keys we have no sentence for. This is the whole of what the edge decided it would tell us.
| Key | Value | What it means |
|---|---|---|
| asOrganization | Anthropic, PBC | The name of that network. This single string often says "this is a VPN" or "this is a datacentre". |
| asn | 16509 | The network your address belongs to, as a number. An ASN identifies an ISP, a mobile carrier, a hosting provider, or a VPN. |
| city | Columbus | City, from your address. Typically accurate to a few kilometres, sometimes to a street in dense areas. |
| clientAcceptEncoding | gzip, deflate, br | The compression the edge saw, before it rewrote the header. |
| clientQuicRtt | 0 | |
| clientTcpRtt | 8 | The round trip time to you in milliseconds. It bounds how far away you are, and a change in it is a change of network. |
| colo | CMH | The Cloudflare datacentre that terminated your TLS. A three-letter airport code, and a rough map of where you are. |
| continent | NA | Continent code. |
| country | US | Country code, from your address. |
| edgeL4.deliveryRate | 1881741 | |
| edgeRequestKeepAliveStatus | 1 | |
| httpProtocol | HTTP/2 | HTTP/2 or HTTP/3. HTTP/3 also tells the server your browser has QUIC. |
| isEUCountry | false | Whether the address is in the EU. It changes which rules apply to you. |
| latitude | 39.96118 | Latitude of the address block, not of you. City level at best. |
| longitude | -82.99879 | Longitude of the address block. |
| metroCode | 535 | |
| postalCode | 43215 | Postal code where the address database has one. Often wrong, sometimes exact. |
| region | Ohio | Region or state name. |
| regionCode | OH | Region code. |
| requestHeaderNames | :method, :scheme, :authority, :path, accept, user-agent, accept-encoding | |
| requestPriority | weight=16;exclusive=0;group=0;group-weight=0 | The urgency the browser assigned this request. |
| timezone | America/New_York | Timezone inferred from the address. Compare it with the browser timezone in section 2: a mismatch is usually a VPN. |
| tlsCipher | AEAD-AES256-GCM-SHA384 | The cipher suite. The exact list a client offers is a fingerprint (JA3); the one chosen is a coarser one. |
| tlsClientAuth.certChainRFC9440 | ||
| tlsClientAuth.certChainRFC9440TooLarge | false | |
| tlsClientAuth.certFingerprintSHA1 | ||
| tlsClientAuth.certFingerprintSHA256 | ||
| tlsClientAuth.certIssuerDN | ||
| tlsClientAuth.certIssuerDNLegacy | ||
| tlsClientAuth.certIssuerDNRFC2253 | ||
| tlsClientAuth.certIssuerSKI | ||
| tlsClientAuth.certIssuerSerial | ||
| tlsClientAuth.certNotAfter | ||
| tlsClientAuth.certNotBefore | ||
| tlsClientAuth.certPresented | 0 | |
| tlsClientAuth.certRFC9440 | ||
| tlsClientAuth.certRFC9440TooLarge | false | |
| tlsClientAuth.certRevoked | 0 | |
| tlsClientAuth.certSKI | ||
| tlsClientAuth.certSerial | ||
| tlsClientAuth.certSubjectDN | ||
| tlsClientAuth.certSubjectDNLegacy | ||
| tlsClientAuth.certSubjectDNRFC2253 | ||
| tlsClientAuth.certVerified | NONE | |
| tlsClientCiphersSha1 | WUS9+h7TjVkF9aEouGuCEMjGQGA= | |
| tlsClientExtensionsSha1 | pAC3WkxDYgBkLPcbbFW+xdSr87k= | |
| tlsClientExtensionsSha1Le | ycZgmMxtCCRwbYKJg/cjUhf4t60= | |
| tlsClientHelloLength | 242 | |
| tlsClientRandom | t4DKx43x7PjVft9nAnEBai57Zy99piugxIvnVJpuqHM= | |
| tlsExportedAuthenticator.clientFinished | 9527e041db7dfd42a5766f88dcd31f853f7d8241363a04e4798008d6c3684ec1f4cd4bd13bf69f252b367df6ffa860f7 | |
| tlsExportedAuthenticator.clientHandshake | e5a83fa5dcd28b30669e3e19fdb84e87259fa19a55463c3cf6ba7e0857cb068d96f112f81e9996091f52c08ef9b0005a | |
| tlsExportedAuthenticator.serverFinished | 6d88760f99f5e520cc8139b3b54a3732f8c82a83bc95a7777a8001c3d0018f63a17c397746a4bbf099e3a09e43708be9 | |
| tlsExportedAuthenticator.serverHandshake | a6c2520e5fdd847d42f626773aa897356521d66fc749c9e9c93a5618c883c994dd32b6865a4f70faf1f5ff067f807e72 | |
| tlsVersion | TLSv1.3 | The TLS version negotiated. An old one is a weak client and a small fingerprint. |
| verifiedBotCategory | AI Crawler | Set only when the request is a known, verified crawler. |
Not exposed to us even though Cloudflare computes it: botManagement, clientTrustScore, clientTcpRttMs, metropolitan_area, place. A score that exists and is not shown is still a score that decided something.
2 The page looks back
Everything above arrived on its own. Everything below needs code running inside your browser, which is why none of it has run yet: this page ships one script, and it waits for a press. What it reads is what any site reads without asking: screen, graphics card, fonts, timezone, storage, sensors, the shape of your typing. It also reads the things that need a prompt, and it will only ask for those if you press the second button.
Nothing leaves your browser. There is no endpoint here to receive it, and the headers on this response forbid one (see section 9).
Cheap proofs, on purpose
Three demonstrations that need no theory. Each one runs only after you press it, and none of them sends anything: open the network panel and watch it stay empty.
This page can read what you type
Type in this box. The count is real and the text is real. A login form is the same object with a different label, and an extension you installed reads it the same way.
Nothing typed yet.
Your mouse is a signature
Move the pointer across the square. Curvature, pauses and acceleration are stable enough per person that behavioural systems use them as a soft identifier.
No movement captured yet.
Clearing cookies does not clear this
The scan stores its own fingerprint in this page's storage under a name of its own, then clears it and rebuilds it from the browser. Same hash after the clear means the identity was never in the cookie.
Run the scan first.
3 The verdict
Every point of the score, taken apart: what it costs, why, and whether it is yours to change. Then the histogram the ranking is counted from, printed in full, because a number nobody can inspect is a number to distrust.
Run the scan above and this section fills in. Nothing has been measured yet.
4 What you cannot change
A short list, because it is short. These arrived with the request, on every site, for the life of the connection. Changing them means changing browser, network, or device, and some of them are not yours to change at all.
| What | Who gets it | Why it cannot be withheld |
|---|---|---|
| Your address | the server, the CDN, your ISP, the destination network | A reply has to be routed somewhere. A VPN moves the address, it does not remove the fact that there is one, and the VPN now knows instead. |
| The hostname you asked for | your resolver, your ISP, every hop, the CDN | It is in the DNS query and in the TLS handshake. Encrypted DNS hides it from the resolver. Encrypted Client Hello hides it from the hops. Neither hides it from the site. |
| The fact that you connected | everyone in the path | Traffic analysis: sizes and timings of packets. Content encryption does not remove the pattern. |
| Your operating system and browser family | any site | They follow from which features work and which headers appear. A user agent can be edited. The behaviour that produced it cannot. |
| Your GPU | any site that runs script | The renderer string is readable through WebGL unless the browser deliberately lies or randomises it. Most do not. |
| Your timezone and language order | any site | They come from the operating system and are readable in one call, with no permission and no prompt. |
| Whether you are on a VPN | any site with an address database | A datacentre ASN, a country that disagrees with your timezone, or a latency that does not match the distance. Detection is a guess, and usually a good one. |
The one prompt worth feeling
Location is the only permission this page will ask for, and only because reading about it is unconvincing. Camera, microphone and the rest are refused in this response's headers before the page loads, so no site on this host can even ask. A fix from your device is not a city: it is a street, and it comes with a timestamp.
Not asked. Nothing has been requested from your browser.
5 Who else sees it
This page is not the observer. It is one of about a dozen parties on the path, and it is not the one with the most access. In order, from your device outward.
- Anything running inside your browser. Extensions, userscripts, a malicious bookmarklet, an injected ad frame. They read the page after it renders, including what you type into it. They are invisible to the server.
- Your browser itself. It decides which headers to send, whether to use encrypted DNS, and whether to randomise a canvas. It also reports crashes, and in most builds some telemetry, to its own vendor.
- Your operating system. It resolves names for every app, keeps the timezone, and may run its own telemetry and captive portal checks.
- Your local network. Router, hotel, office, cafe. It sees every name you look up unless DNS is encrypted, and every address you connect to regardless.
- Your ISP or mobile carrier. The same, at scale, plus the ability to correlate across every site you visit. This is the party that knows the most about you and is discussed the least.
- Your DNS resolver. One line per domain, with a timestamp. Encrypted DNS moves that trust to a different company, usually a large one.
- Transit networks. They see the address and the cleartext server name in the TLS handshake. Not the content.
- Cloudflare, in front of this site. TLS terminates at their edge, so they see the request in cleartext, exactly as this page does, and they keep their own logs under their own policy. No site behind a CDN can honestly claim otherwise.
- This worker. The code in this repository, which for this page keeps nothing. Section 9 is the detail, including the one route on this host that does keep something.
- Our DNS provider and registrar. They publish the fact that zpe.vc exists and which names under it answer.
- The certificate authority, and everyone. Every certificate issued for a name is written to public transparency logs. That is why a hostname cannot be kept secret, even if it is never linked from anywhere. Check this one: crt.sh/?q=zpe.vc.
Your connection, described by the edge
Fetched from this same origin, so it adds no third party. This is Cloudflare's own summary of the connection it just terminated.
The three sentences that matter here
Your address is not a secret, it is a routing fact. The name you asked for is not a secret, it is a lookup. The content is the only part that encryption actually protects, and only from the parties in the middle, never from the two ends.
6 DNS, and the parts that travel in the clear
Before a single byte of this page was sent, your device asked a resolver for the address of zpe.vc. That question is the most revealing thing most people never think about.
The question, and who hears it
- Your device asks its resolver: what is the address of
zpe.vc. Plain DNS means anyone on the path reads that question, in clear text, with a timestamp. - The resolver asks upward until it reaches the zone. It now has a log line for you, and it keeps it far longer than any web server keeps a request.
- Your browser opens a connection and names the site again in the TLS handshake. That name (SNI) is cleartext unless Encrypted Client Hello is in use.
- The edge picks a certificate for that name, terminates TLS, and forwards the request to this worker.
What the name alone gives away
- Which sites exist under a domain, from certificate transparency, linked or not.
- Which one you are about to read, from the subdomain, which is often a product name you are interested in.
- How often, and when, from the resolver's logs.
- Who else in your household uses it, if your resolver is per-connection rather than per-device.
- What your browser will pre-connect to next, from
preconnectanddns-prefetchhints. A page can resolve a name for a site you have not clicked yet. This page sends none, and you can check that in the network panel.
Live: what your own handshake exposed
The sni line in the edge's trace, read from your connection just now. If it says plaintext, every hop between you and this edge could read the name you asked for. Encrypted Client Hello is the only fix, it is per site, and many sites still do not switch it on.
Three tricks built on DNS and caches
- Unique subdomains as a cookie
- A page asks your device to resolve
random.zpe.vc. The resolver logs the random string against your address. No cookie, no storage, no script, and it survives a private window in some setups. Any zone the tracker controls can do this. - Favicon and cache supercookies
- A site loads a sequence of images and measures which ones come back instantly. The pattern is a number it can read back later without storing anything on your device. Browsers have narrowed this, and not closed it.
- HSTS and preload lists
- A site pins itself to https in your browser's own settings, which is a per-site bit that survives a cookie clear. Preload lists ship in the browser build, so membership in one is a small fingerprint of the build you run.
8 Extensions
An extension is the most privileged code on this page and the only code we cannot see. It runs after the response arrives, in your browser, with access to the rendered page, your keystrokes, your cookies if it was granted them, and every request the page makes. Nothing about it reaches this server.
Run the scan to test what can be detected from inside: whether a content blocker changed this page, and whether a known extension exposes a resource. Expect the answer to be partial, and read why below.
Why extension detection is unreliable by design
What we can see
- Whether an element the page created was hidden by a filter list. That proves a content blocker, which is the common case.
- Whether a request to a known tracker was refused. Same proof, different mechanism.
- Whether a resource at a known extension address loaded. It works only for extensions that expose web accessible resources, and many do not.
- Side effects in the DOM: injected badges, replaced text, extra stylesheets. These are fingerprints of specific products.
What we cannot see
- The list of installed extensions. The browser gives no page that list.
- Anything inside a content script's isolated world. The page and the extension share a DOM and not an environment.
- An extension that reads without changing the page, which is most of them, most of the time.
- Any permission the extension holds. It does not report to the page.
So the honest statement is not "we detected your extensions". It is: an extension is invisible to the server, invisible to the page, and reads everything the page reads. The demonstration in section 2 is the only reliable proof, and it works because the page and the extension have the same view.
9 What we keep, and what this page refuses to do
A privacy page that describes the whole world and not itself is a brochure. Here is this site's own ledger.
| Thing | This page | The rest of zpe.vc |
|---|---|---|
| Cookies set | None. The response carries no Set-Cookie, and you can confirm that in the network panel. | The sign-in at auth.zpe.vc sets a session cookie, scoped to .zpe.vc, HttpOnly and Secure. That one is a credential and it travels to every name under the zone. |
| Stored request data | None. Nothing that arrived in your request is written anywhere: no address, no agent, no path, no time. The one write on this host is the score histogram below, and it cannot be traced back to a request. | The idea forge on zpe.vc keeps a rate limit keyed by your address for 10 minutes, a daily counter of tokens, and the ideas you submit for 30 days with no address attached. That is the whole of it, read from its source. |
| Third party requests | None loaded. default-src 'none', and everything the page needs comes from this origin. One is attempted and refused: Cloudflare injects its Web Analytics beacon (static.cloudflareinsights.com) into every HTML response on this zone, for browsers, and this page's own policy stops it before it runs. The card at the top counts both. | The main zpe.vc page loads two: fonts.googleapis.com and fonts.gstatic.com. Google receives your address, your user agent and the page you are reading on every visit. This page has no webfont, deliberately. |
| The ranking | One integer per scan: which two-point bucket your score fell in. 51 counters in total, no address, no cookie, no timestamp, no row per visit, and no way for this page to tell two visitors apart. The full histogram is printed in section 3, so you can see the entire store. The trade is real: a percentile requires counting, and counting is the one thing this page does keep. | |
| Analytics, pixels, session recording | None. Nothing is measured about your visit, so nothing is reported. | None on the apex page either. If that changes, this row is wrong and should be corrected the same day. |
| What the CDN keeps | Cloudflare terminates TLS in front of every name here, so it sees each request in full and keeps its own logs under its own policy, which we do not control and cannot audit from inside. Anyone who tells you a site behind a CDN keeps nothing at all is describing the application, not the path. | |
| One header we did not write | The edge adds report-to and nel to this response, pointing at a.nel.cloudflare.com. They are the browser's crash and network-error reports, they fire only when a request fails, and this page cannot switch them off. It is the one place where the page's own claim of zero third parties needs a footnote, so here it is. | |
What this page will not do
- Load a font, a script, an image or a stylesheet from anyone else.
- Set a cookie, or read one it did not need. The scan reads
document.cookiebecause section 7 would be an assertion otherwise. - Keep the scan. The result exists in this tab and is gone when you close it, apart from the one score bucket the ranking is counted from.
- Ask for your location, camera, microphone or contacts automatically. Two of the three are refused in the response headers before the page loads.
- Send one byte anywhere. There is no endpoint, and no code to call one.
- Pretend the list above is complete. It is complete about us, and section 10 is where it stops being complete about the world.
10 The full inventory
Every attribute this page read, with the cost of reading it and what it narrows you to. Run the scan and the values fill in. The column on the right is the one that matters: some of these are exact, and some are a coarse guess dressed as a number.
| Attribute | Value | Cost to the site | Narrows you to |
|---|---|---|---|
| Run the scan above. | |||
What no page can read in 2026, and why
The other half of "everything". A page that only lists what it can take is selling. Here is the list of things it cannot, with the reason, so you can tell which defences are real.
| Not readable | Why not |
|---|---|
| Which sites you visited before | The history object gives a length and no URLs. The :visited style was restricted in 2010 after it was used to read history, so a link you have visited can no longer be styled into a readable bit. |
| Your files, folders or other applications | The page is sandboxed. A file becomes readable only when you pick it in a file dialog, and then only that file. |
| Other tabs and what they hold | Cross-origin isolation. A page cannot read another tab's DOM, and cannot read the clipboard without a click and a permission. |
| Your name, address or email | Unless you type it, or autofill puts it in a field the page can read, which is the one case where autofill is a real risk. |
| Your precise location | One permission prompt away, and refused by default. Without it, an address database gives city level and is often wrong. With it, GPS or wifi triangulation gives metres. |
| Your installed fonts, exactly | Enumerated by measurement, which is slow and approximate, and browsers are narrowing the technique by limiting font metrics. The shortlist of common fonts is still readable, which is enough to fingerprint. |
| Your plugin list | Frozen to a fixed stub in Chromium since 2021. A once great fingerprinting source, now dead, which is worth remembering: entropy can be revoked. |
| Your local network address over WebRTC | Masked with a random .local name in Chromium and Safari. The old local IP leak is mostly closed, and the section below still measures it because "mostly" is honest. |
| Your battery level, in most browsers | Removed from Firefox and Safari after it was shown useful for linking sessions. Still present in Chromium. |
| The TLS fingerprint we would need | Cloudflare computes JA3 and JA4 from your handshake and does not pass them to the worker. The score exists. We cannot show it, and that is a fact about the CDN, not about your browser. |
| Whether you are in a private window | Never directly. Inferred from a storage quota that is smaller, or from a write that fails. Every method is a guess and every guess has false positives. |