Encrypted relay
For colleagues who aren't on the same network, DeepState syncs through a relay: a small service that stores and forwards encrypted change bundles between devices. The relay is a dumb mailbox. It never has the board key, cannot decrypt anything it holds, and cannot even tell which board a mailbox belongs to.
DeepState runs a relay at relay.getdeepstate.app, included with every license. You can also run
your own; the app accepts any relay URL.
Turning it on
In the board's Collaborate dialog, under Encrypted relay, the URL field is pre-filled with DeepState's relay. Click Connect. The status line shows Connecting… then Connected · synced just now. Do the same on each device, with the same URL. Everyone else joins with Join shared board… → Relay and the same URL.
Once connected the dialog offers:
- Pause / Resume - stop exchanging without forgetting anything.
- Push full history - re-publish everything this device knows about the board to the relay. Use it to seed a new relay, or after the relay has expired old history (below).
- Change… - switch to a different relay URL.
- Remove - stop using the relay for this board.
How it works
- The board key is hashed to produce a room ID. Devices with the same key derive the same room; nobody else can guess it, and the relay cannot link a room to a board name, a license or a person.
- Each device keeps a WebSocket open to its rooms. Local changes are encrypted with the board key (the room ID is bound into the encryption so a frame can't be replayed into another room) and published; the relay assigns a sequence number and fans the frame out to every connected device, which decrypts and applies it.
- Devices that were offline read forward from the last sequence number they saw when they reconnect. The relay keeps frames for 90 days.
- Media files are encrypted, named by a hash, and stored in the relay's blob store; devices upload what they have and download what they lack. File names travel inside the ciphertext.
- Every device publishes its own edits. When you first connect a board that already has history, DeepState also publishes the full history once so that newcomers can rebuild it.
Retention and re-seeding
Frames older than 90 days are pruned from the relay. If a device has been away longer than that, the relay tells it so and the Collaborate dialog shows: The relay no longer holds the early history of this board. Any current device fixes it by clicking Push full history, which republishes the complete board; the stale device then catches up. Nothing is lost - every device has the full board locally - this is only about what the relay is holding at the moment.
Self-hosting
The relay is a Cloudflare Worker with a Durable Object per room and an R2 bucket for blobs. It is
open in the repository under relay/ and deploys with wrangler deploy to any Cloudflare
account; it fits in the free tier for a small team. Then enter https://your-relay.example.com in
the Collaborate dialog on every device.
GET /health
GET /rooms/:room/ws?since=N WebSocket: replay frames after N, then live
POST /rooms/:room/frames append a ciphertext frame
GET /rooms/:room/frames?since=N poll instead of WebSocket
PUT /rooms/:room/blobs/:name store an encrypted blob (idempotent)
GET /rooms/:room/blobs/:name
GET /rooms/:room/blobs
Retention, frame size (1 MB) and blob size (64 MB) limits are Worker variables. The relay has no accounts: possession of a room ID is the only credential, and a room ID is derived from a 256-bit key. If you self-host, put the Worker behind Cloudflare Access or an IP allow-list if you want a second factor.
What the relay sees
| The relay knows | The relay does not know |
|---|---|
| A room ID (a hash) | Which board, license or person it belongs to |
| Ciphertext frames and their sizes and times | Any node content, titles, URLs or names |
| Encrypted blobs under hashed names | Original file names or contents |
| The IP addresses that connect | Device identities (device IDs are inside the ciphertext) |
DeepState's hosted relay is not authenticated against your license; anyone who knows a room ID could read that room's ciphertext. Since the room ID is a hash of the key, the only way to know it is to hold the key - at which point one could decrypt anyway. Rotating the key (stop sharing, create a new invite) moves the board to a fresh room.
Troubleshooting
- Stuck on Connecting…. Check the URL (it must start with
https://), and that outbound WebSocket connections are allowed on your network. Corporate proxies that strip WebSockets will block it; the app falls back to reconnecting with backoff up to once a minute. - Connected, nothing arrives. The other device must be connected to the same relay URL with the same key. Ask them to click Push full history.
- "History no longer available". See Retention and re-seeding above.