How DoStash Works: Zero Cookies, Zero Tracking, Zero Accounts
2026-03-06
Most privacy-focused products make you a promise: “we don’t track you.” That promise lives in a privacy policy document, enforced by trust. DoStash takes a different approach. It doesn’t track you because the architecture makes tracking structurally impossible — not because we pinky-swore not to.
This post is a technical walkthrough of how that works.
Privacy by policy vs. privacy by architecture
Privacy by policy means a company collects data but commits to using it responsibly. You’re trusting their intentions, their employees, their future acquirers, and their security posture. It’s better than nothing, but it’s still a promise.
Privacy by architecture means the system is designed so that certain data is never collected in the first place. There’s no database column for your email address because there’s no email address. There’s no IP log because nothing writes IP addresses anywhere. A breach or a policy change can’t expose data that was never stored.
DoStash is built on the second model. Here’s what that looks like in practice.
No accounts, no identity
DoStash has no user accounts. There is no registration flow, no email field, no profile page. When you create a stash, you pick a slug and optionally set a password. That’s it.
Stashes are identified by their slug, not by a user. The database has no concept of ownership. There is no “your stashes” because there is no “you” in the system.
Authentication without sessions
Editing a stash requires authentication, but not in the way most web apps do it. DoStash uses HMAC-based tokens with the structure slug:timestamp:hmac. When you create or claim a stash, you get an edit URL that encodes this token. That URL is your credential.
The token is valid for 24 hours. The server verifies the HMAC signature on each request — no session is stored server-side, no cookie is issued. Every authenticated request is self-contained and cryptographically verified.
The trade-off is real: if you lose your edit URL, there is no “forgot password” flow. We can’t send a reset email because we don’t have your email. We can’t verify your identity because we don’t know who you are. The system isn’t being difficult — it genuinely has no way to help you.
No cookies, no tracking scripts
DoStash sets zero cookies. Not “only essential cookies” — zero. There is no cookie banner because there is nothing to declare.
There are no analytics scripts. No Google Analytics, no Plausible, no Fathom, no PostHog. The static pages that make up most of DoStash load no third-party JavaScript at all. Nothing phones home. Nothing counts your visit.
No fingerprinting, no passive collection
Beyond cookies and analytics, there’s a whole class of passive tracking that most sites do without users noticing: IP address logging, user agent collection, referrer tracking, browser fingerprinting. DoStash does none of these. The infrastructure logs what Cloudflare logs by default (which is minimal and not accessible to us in a useful per-user form), but we don’t write anything identifying to our own database.
Content Security Policy headers on static pages restrict what can load. Third-party resources can’t be injected by a malicious asset URL, and no rogue script can quietly exfiltrate data from the page.
The tech stack
Understanding why DoStash works this way requires understanding what it’s built on.
- Cloudflare Workers: The API runs at the edge. There is no origin server, no application server, no VM sitting in a data center running your request. Requests are handled by Cloudflare’s infrastructure at the nearest point of presence.
- Cloudflare D1: The database is SQLite running at the edge. It stores stash metadata and asset data. It has no columns for personal data because none were ever designed in.
- Cloudflare R2: Object storage for static HTML pages and other assets. When you publish a stash, the generated HTML is written here.
- Hono: A lightweight web framework for Cloudflare Workers. It handles routing and middleware for the API.
- React + Vite: The editor (the create/edit flow) is a client-side SPA. It only loads when you’re actively creating or editing a stash — not on public stash pages.
How stash pages actually work
This is the part that makes passive tracking structurally impossible.
When you publish a stash, the API generates a complete, self-contained static HTML page. Every piece of content — the title, description, asset cards, layout — is baked into that HTML at publish time. This file is then written to R2 object storage.
When someone visits your stash URL, a Cloudflare Pages worker retrieves that static file from R2 and serves it directly. No database query runs. No API call is made. No JavaScript is required to render the page. The content is already there, fully formed, in the HTML.
This has a privacy consequence that isn’t obvious at first: there is literally no mechanism for us to log “someone visited this stash at this time from this IP” even if we wanted to. The serving layer is a file server, not an application. It doesn’t talk to our database. We have no hook to insert logging code.
What this means for page load
Static serving also means fast serving. No server-side rendering on each request, no database round-trips, no cold starts. The file is in R2, Cloudflare serves it from cache or edge storage, and the page loads. The privacy benefit and the performance benefit come from the same architectural decision.
Password protection without sessions
Password-protected stashes work without setting a session cookie. Here’s the flow:
- The visitor lands on a static password gate page — a plain HTML form.
- They submit the password. This makes a single API call to verify it.
- The password is checked against a
bcrypthash stored in D1. The plaintext password is never stored. - If the password is correct, the stash content is returned by the API and rendered.
- No session cookie is set. No persistent state is written anywhere.
Each visit to a password-protected stash requires re-entering the password. This is by design. Persistence would require state, and state would require either a cookie or a server-side session — both of which we don’t want.
What we store — and what we don’t
The database schema is a direct reflection of what the product actually needs. Here’s what’s in it:
- Stashes: slug, title, description, password hash, status, timestamps, report count
- Assets: stash ID, asset type, URL, title, description, image URL, domain, text content, position, embed data, timestamps
- Reports: stash ID, reason, optional details, optional contact email (user-submitted, not collected), status, timestamp
There is no users table. There is no sessions table. There is no column called ip_address, user_agent, referrer, email, name, or anything that would hold personal data. It’s not that these columns are empty — they don’t exist. A subpoena couldn’t produce data we don’t have.
Why this matters
Consider how a typical web app works. You sign up with an email. A session cookie is set. Every page view is logged with your user ID, your IP, your device. Analytics track which features you use, how long you stay, what you click. That data is stored, aggregated, and often monetized or sold. Even if the company is well-intentioned, that data exists and is a liability — for you.
The default architecture of the modern web is surveillance. It’s not malicious, it’s just what you get when you build with the standard stack and don’t actively design against it. Accounts, sessions, analytics, and logging are the path of least resistance. They’re also the path that creates a detailed record of your behavior.
DoStash chose the harder path upfront. No accounts means no identity graph. No cookies means no cross-session tracking. Static serving means no server-side logging hook. The privacy properties aren’t bolted on — they’re the direct result of the architecture.
The real trade-offs
This approach has costs, and it’s worth being honest about them.
- No account recovery. Lose your edit URL, lose access to your stash. There is no recovery path because there is no account to recover.
- No cross-device sync. Your edit URL is your credential. It’s a URL — you can save it, share it, and open it anywhere. But there’s no magic sync layer that knows about your stashes on multiple devices.
- No usage analytics for us. We genuinely don’t know how many people use DoStash actively, which features are popular, or where people drop off. Building a product without usage data means relying on user feedback and intuition instead of dashboards. It’s harder.
- No personalization. Because we don’t know who you are, we can’t recommend stashes to you, suggest content, or remember your preferences.
These aren’t oversights. They’re the price of the architecture. The question is whether the privacy guarantee is worth the functionality cost. For DoStash, the answer is yes — but it’s a deliberate choice, not a free lunch.
An open architecture
DoStash isn’t open source yet. But the approach is intentionally transparent. This post is the architecture documentation. The decisions aren’t hidden or obscure: no accounts, no cookies, HMAC tokens, bcrypt hashes, static HTML, R2 storage, Cloudflare Workers. Anyone technical can verify the claims made here by inspecting the network tab of any stash page, running a cookie audit, or reading the Content Security Policy headers.
Privacy claims shouldn’t require trust in the claimant. They should be verifiable. That’s the standard we’re trying to hold ourselves to.
If you want to try it, you can create a stash in about 30 seconds, no signup required.