Encrypted burn-after-open text and image sharing on Cloudflare Pages and KV
Live Demo | Source Code | Deploy Guide | Report Issue | License
FlashSeal is an encrypted burn-after-open sharing tool for text and images, built on Cloudflare Pages, Pages Functions, and KV. The page ships without a heavy runtime framework on the client.
🛡️ End-to-End EncryptionEncrypts secrets in the browser before upload, so the server stores ciphertext only.🔥 Burn After OpenEach secret can be opened successfully only once, which keeps sharing intentionally ephemeral.📝 Text And Image SupportShare both text snippets and images in one lightweight workflow, with image uploads up to15MB.📋 Paste To UploadDrop images in quickly with clipboard paste support instead of manual file picking every time.🔗 Key-In-Fragment LinksSecrets are shared as direct links like/s/:id#k=<base64url-key>, keeping the decryption key on the client side.⏱️ Delayed OpeningHold access until a chosen unlock window of5,15, or30minutes.⌛ Timed Self-Destruct ViewOnce opened, the decrypted content stays visible for60 secondsbefore disappearing.🗑️ Automatic ExpirationUnopened secrets are purged after1 hour, including those created with delayed opening enabled.⚡ Lightweight FrontendShips without a heavy client runtime framework, keeping the sharing page fast and focused.
- Svelte 5
- Vite 7
- Tailwind CSS 4
- Cloudflare Pages
- Cloudflare Pages Functions
- Cloudflare KV
- TypeScript for frontend app and Pages Functions
src/: Svelte app source, UI components, shared browser logic, and stylesstatic/: static assets copied into the final buildpublic/: generated build output for Cloudflare Pages deploymentfunctions/api/secrets/index.ts: create-secret endpoint with delayed-open configurationfunctions/api/secrets/[id]/open.ts: first-open endpoint with unlock-time enforcementfunctions/api/i18n.ts: API-side message dictionaryvite.config.js: Vite build configurationsvelte.config.js: Svelte compiler configurationwrangler.toml: Pages and KV configuration
- Node.js
20+ - npm
- A free Cloudflare account
- Wrangler 4, installed through project dependencies
cd /Users/yilun/Desktop/FlashSeal
npm installUse one of these options:
- Run
npx wrangler login - Or export
CLOUDFLARE_API_TOKENin your shell
The KV namespace creation commands require Cloudflare authentication.
Create both production and preview namespaces:
npm run kv:create
npm run kv:create:previewWrangler will print the namespace IDs. Copy them into wrangler.toml:
[[kv_namespaces]]
binding = "SECRETS"
id = "your-production-kv-id"
preview_id = "your-preview-kv-id"npm run devFlashSeal uses these local settings:
- app port:
8788 - inspector port:
9230 - local state dir:
./.wrangler/state - frontend build output:
public/
Then open:
http://127.0.0.1:8788
- Create a text or image secret
- Optionally set delayed opening to
5,15, or30minutes - Copy the generated link
- Open that link in a new tab or window
- If delayed opening is enabled, confirm the UI shows that the secret is still locked
- After the unlock time, confirm the secret opens automatically
- Confirm the countdown runs for 60 seconds
- Confirm the same link cannot be opened again
- If
wranglercommands fail after an upgrade, use the scripts inpackage.jsonornpx wrangler ... - If the UI looks stale, clear the service worker and site storage in DevTools
- If KV creation fails, confirm you are logged in or
CLOUDFLARE_API_TOKENis set - If local development fails on an older Node version, upgrade to Node 20+
- Do not open
public/index.htmldirectly as a static file preview. This project expects Cloudflare Pages routing and generated assets.
- Push this project to a Git repository
- In Cloudflare, open
Workers & Pages - Create a new
Pagesproject and connect the repository - Use these build settings:
- Build command:
npm run build - Build output directory:
public
- Build command:
- Create or choose a KV namespace for production
- In the Pages project settings, add a KV binding:
- Variable name:
SECRETS - Namespace: your production namespace
- Variable name:
- Save and deploy
Before connecting the repo, make sure wrangler.toml contains your real namespace IDs:
name = "flashseal"
compatibility_date = "2026-03-11"
pages_build_output_dir = "./public"
[[kv_namespaces]]
binding = "SECRETS"
id = "your-production-kv-id"
preview_id = "your-preview-kv-id"Then connect the repo in Pages and keep:
- Build command:
npm run build - Output directory:
public
