The URL Fragment (#...) That Never Reaches Your Server

Everything after the # in a URL is called the fragment, and browsers never include it in the HTTP request — not in the request line, not in any header. It's not a privacy feature that was deliberately bolted on; it's a 30-year-old consequence of what a fragment was originally for, that OAuth, client-side routers, and this site's own share-pad now lean on deliberately.

reference guide URLs browser behavior

// the anatomy of a URL

A URL has a part the server receives and a part it doesn't. Everything up to and including the query string goes out over the network in the request line. The fragment — everything from the # onward — is stripped off by the browser before the request is even built. The server hosting the page has no way to see it, because it was never sent.

https://toolsharp.dev/tools/share-pad#data=xyzsent to the servernever sent — browser onlyappears in server access logsexists only in window.location
Scheme, host, path, and query string are the part of a URL the server ever sees. The fragment is a purely client-side concept — the browser removes it before the request is constructed.

// verified with a real capture, not just the spec

This is easy to confirm yourself: open any page with something in the hash, open your browser's devtools Network tab, and reload. You will not find the fragment in the request URL of the page load itself, nor in any request the page makes afterward — because the browser never had it to send. Loading https://toolsharp.dev/tools/share-pad#data=SECRET_VALUE with a network log attached shows exactly this: the page-load request goes out as GET /tools/share-pad, with no trace of SECRET_VALUE anywhere in the 14 requests that page makes — while window.location.hash still reports the full value back to any script running on the page. Nothing was hidden from JavaScript; it was hidden from the network.

// why this exists

The fragment predates any privacy use case entirely. In the original HTTP/URL design, a fragment like #introduction identifies a location within a resource the browser has already retrieved — the classic "jump to this heading on the page" anchor link. Since it only makes sense once the full page is already loaded, it was never part of what gets sent to ask for that page in the first place. That's a structural fact from how the URL specification separates "identify a resource" from "identify a piece of that resource" — not a feature anyone added on purpose for privacy. Developers noticed the side effect and started building on it deliberately.

// what actually relies on this today

// where the guarantee ends

"Never sent to the server" is a specific, narrow guarantee — not a general statement that the data is secret. It's worth being precise about what it does and doesn't cover:

// try it yourself

Generate an offline share link with share-pad, open your browser's devtools, and watch the Network tab as the link loads: the text you shared never appears in a single request. That's this exact mechanism, not a special case built just for that tool.