

SnapSend is zero-knowledge by architecture, not by promise. Every secret is encrypted with AES-256-GCM in your browser, the server only ever stores an opaque blob it cannot decrypt.
Here's the exact lifecycle of a secret, from the moment you hit "Encrypt" to the moment it burns.
Your browser generates the key
When you create a secret, your browser generates a random 256-bit key and IV using the Web Crypto API. No third-party crypto library, no server round-trip, the key is born on your device.
const key = await crypto
.subtle.generateKey(
{ name: 'AES-GCM',
length: 256 }, …)
Encryption happens locally
The secret is encrypted in your browser tab with AES-256-GCM. What leaves your device is ciphertext, mathematically unreadable without the key that never left.
plaintext
──encrypt──▶ a91f…c04e
// only this is sent
The server stores what it can't read
The API drops the ciphertext into Redis with a TTL matching your expiry. There's no relational database, no backup trail, no analytics, an opaque blob with a countdown.
SET secret:8fJq2xVb
{ ciphertext, iv }
EX 3600 // self-destructs
The key travels in the URL fragment
Your share link carries the key after the #. By the URL specification itself, browsers never send fragments to any server, this is a hard guarantee of the web platform, not an app-level promise.
/s/8fJq2xVb#key=X9dK…
// fragment stays
// in the browser
Read once, then it burns
The recipient's browser fetches the ciphertext, decrypts it locally, and displays it. A Lua script decrements views and deletes atomically , even two simultaneous readers can't get a second copy. TTL cleans up anything never opened.
-- atomic burn
if views < 1 then
redis.DEL(id)
end
Everything before the # goes to the server. Everything after it never leaves your browser.
https://snapsend.app/s/8fJq2xVb#key=X9dKpL2mQ7ZrTnE4wA1sHcU6oB3vNyGf
The address
Public routing. It tells your browser where the app lives, nothing sensitive here.
The id
A random handle the server uses to look up the ciphertext. Useless on its own, it unlocks nothing.
The key
Lives after the #. Browsers strip fragments from every request, the server can't receive it even by accident.
The server sees
The server never sees
Encryption
Web Crypto API
Native browser crypto , AES-256-GCM with authenticated encryption. No third-party crypto libraries to audit or trust.
Storage
Redis, and nothing else
Native TTL handles expiry with no cron jobs. A Lua script makes burn-on-read atomic under concurrent reads.
Backend
.NET Web API
A deliberately simple N-tier API: three endpoints, per-IP rate limiting, and zero logging of anything secret-adjacent.
Q. Can SnapSend recover a secret if lost?
No, and that's the design. Without your link's key fragment, the ciphertext is unreadable to everyone, including us. Once it burns or expires, it's gone from Redis entirely.
Q. What if two people open the link at once?
The view counter is decremented and the entry deleted in a single atomic Lua script. Exactly the permitted number of views succeed, a race can't produce an extra copy.
Q. Is the QR code as sensitive as the link?
Yes, the QR encodes the full URL, key fragment included. Treat a screenshot of it exactly like the secret itself.
Q. Why should I trust this more than a promise?
Because it isn't a promise. Browsers never transmit URL fragments, that's the web specification. The server can't leak, log, or be subpoenaed for a key it never received.
No account. No install. Nothing left behind.
Zero-knowledge · Burn-on-read · No accounts