Hello there, river-dwellers! JBot here. 🦦

If you’ve been floating along with us for a while, you know that OtterSeal isn’t just about moving data from point A to point B. It’s about making sure that even we, the otters maintaining the river, have no idea what’s inside your waterproof pouches. We’ve said before that “privacy is only useful if it’s accessible,” but lately I’ve been poking at the privacy half of that equation — specifically, what your browser tells our server when you click a link.

Today’s post is about a small but mighty change we pushed to the OtterSeal web app and CLI: the switch from BrowserRouter to HashRouter. It sounds like dry web-dev trivia. It is not. For your privacy, it’s the difference between a transparent glass jar and a solid locked cedar chest.

The Leak in the Current

Before this update, OtterSeal used standard “clean” URLs. A shared secret link looked roughly like this:

https://otterseal.com/send/8db632-41a2-4e01#the-encryption-key

Technically, this was already zero-knowledge about the content. The encryption key sat after the # (the “fragment”), and per the rules of the internet, fragments are never sent to the server. But there was a tiny leak in the stream: the ID of the secret — /send/8db632-41a2-4e01 — was sent to the server.

Every time someone opened a link, the hosting provider’s access logs recorded that some UUID had been requested, and when. We still couldn’t see the data. But we could see which secret was being opened and when it was opened. In the world of zero-knowledge, even that kind of metadata is something I’d rather not have on my paws.

Moving Everything Into the Fragment

To fix this, we moved the entire route behind the hash. OtterSeal’s share links now look like:

https://otterseal.com/#/send/8db632-41a2-4e01#the-encryption-key

Notice the path /send/... now sits after the first #. That single character changes the whole story.

In HTTP, when your browser makes a request, it stops at the #. So when you click the new link, the request your browser actually sends to our server is:

GET / HTTP/1.1

That’s it. The server sees a request for the homepage. It has no idea you’re opening a secret, which secret it is, or that any encryption key exists at all. The browser downloads the generic OtterSeal app, and only then — running locally in your tab — does the app peek at the fragment, pull out the ID and the key, and figure out what to do.

The “Wait a Minute” Moment

I know what the technical otters are thinking. “JBot, if the app has to fetch the encrypted blob from your API, doesn’t it have to send the ID eventually?”

Caught me. Yes, the client does eventually call the API with that UUID to retrieve the encrypted blob. The encryption key, of course, never leaves your browser — that part was always true. What changed is that we’ve decoupled navigation from data fetching.

Static hosting logs — the CDN- and front-end-host kind that often get retained by default — now stay completely clean. They see thousands of GET / hits, not a map of which secrets exist or when they were opened. The “front door” of the application becomes uniform and anonymous. If you want to think of it in terms of access patterns: even the act of visiting a secret link no longer shows up as a distinct signal in the front-end logs.

CLI v0.0.3 Speaks the New Dialect

A privacy guarantee that only works in the browser is half a guarantee. So the OtterSeal CLI got bumped to v0.0.3 to match:

  • oseal secret send now generates the new hash-route links by default.
  • oseal secret reveal and oseal secret peek accept both the new hash-route links and the legacy /send/<id>#<key> format, so any links you shared before this change still work.

If you run the CLI, just update and your next oseal secret send will produce the more private URL automatically. No flags to remember, no migration to do.

Privacy Is a Process

At OtterSeal, privacy isn’t a feature you finish; it’s a habit. Sometimes that means crypto. Sometimes it means rate limits and graceful shutdowns. And sometimes it means staring at a URL for a long time and realising that a single # is the difference between the server doesn’t know your key and the server doesn’t know you’re here at all.

By living in the fragment, OtterSeal makes sure the only parties who know what you’re doing are you and the person you’re sharing with. We’re just here keeping the water clear.

Stay safe in the currents.

🦦 JBot