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.
// the anatomy of a URL
// 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
OAuth 2.0 implicit flow — returns the access token appended to the redirect URL's fragment specifically so it never lands in the redirect target's server logs. (Implicit flow is now discouraged in favor of Authorization Code + PKCE, for other reasons — token lifetime and same-page script exposure — but the redirect step still works this way because of exactly this behavior.)
Client-side routers — older single-page apps (early Angular, hash-mode React Router) used #/users/42-style routes precisely because changing the fragment doesn't trigger a full page reload or a new server request — the app's own JavaScript reads the change and re-renders.
This site's share-pad — the offline-link mode compresses your text directly into the fragment. The tool page can decompress and display it purely from window.location.hash — the text was never sent to ToolSharp's server, or anywhere else, to produce that link.
// 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:
Any JavaScript on the page can read it. window.location.hash is a normal DOM property — the page's own script, any third-party script it loads (ads, analytics, a chat widget), and any browser extension with page access can all read it freely. The guarantee is about the network, not about code running in the browser.
It still leaves outbound in one place: your own history. Your browser stores the full URL, fragment included, in local history — and if browser sync is turned on, that history (fragment included) can sync to your browser vendor's account.
The Referer header is fragment-free too — which helps. If a page with a sensitive fragment contains a link to somewhere else, the outbound Referer header sent to that destination is defined to exclude the fragment. That's one fewer leak path, not an exception to watch for.
Copying the link still copies the data. If you paste the full URL into a chat, an email, or a bug report, the fragment goes with it as plain text. The guarantee is "your server's access logs won't have it" — not "this data can't end up anywhere."
// frequently asked questions
Does the URL fragment (after #) ever get sent to the server?
No. Everything up to and including the query string goes out in the HTTP request line. The fragment — everything from the # onward — is stripped off by the browser before the request is even built. The server has no way to see it, because it was never sent, verifiable with a real network capture in devtools.
Why does the URL fragment exist if it's never sent to the server?
It predates any privacy use case. In the original URL design, a fragment like #introduction identifies a location within a resource the browser has already retrieved — the classic "jump to this heading" anchor. Since it only makes sense once the page is already loaded, it was never part of what gets sent to request that page. Developers later noticed this side effect and started building on it deliberately.
What actually relies on the URL fragment never being sent?
OAuth 2.0 implicit flow returns the access token in the redirect URL's fragment specifically so it never lands in server logs. Older single-page app routers (hash-mode) used fragment-based routes because changing the fragment doesn't trigger a page reload. This site's share-pad offline-link mode compresses text directly into the fragment so it's never sent anywhere.
Is data in a URL fragment actually private?
Not in general — "never sent to the server" is a narrow guarantee, not a statement that the data is secret. Any JavaScript on the page (including third-party scripts and extensions) can read it via window.location.hash. It's stored in your browser history, and copying the full URL into a chat or email copies the fragment as plain text too.
// 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.
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.