If we get subpoenaed, here is everything we can hand over. This is the whole list.
The complete list of what's on our servers.
Everything below is stored on our control plane in Postgres. Some of it we need to route your alerts and bill you; some of it is ciphertext we can't read without a key we've never had.
- Your email address The address you signed up with.
- An opaque Firebase Auth user id A stable identifier issued by Google. Not your password. See Where else to look below.
- Sign-in provider Either
passwordorgoogle.com. Which one you used to create the account. - Account timestamps Created, last logged in, last token refresh.
- TOTP ciphertext, if you enabled two-factor The 2FA seed is envelope-encrypted with a key derived from your login. We can't decrypt it without you.
- Per-device label you picked e.g.
jvs,MacBook — Sam. Whatever you named it in the app. - Platform + agent version e.g.
macos-aarch64 / v0.0.57. - Heartbeat timestamps When each device last checked in. Retained ~90 days.
- Device fingerprint A local-only hash the endpoint computes to detect duplicate enrollments.
- Enrollment PKI records Public cert issued to the device, revocation entry if the device has been removed.
- Alert id + timestamp When each alert fired.
- Which endpoint sent it Alert → device linkage.
- A coarse severity bucket Two values,
routineorurgent. That's the whole enum. - Ciphertext of the alert body ChaCha20-Poly1305, encrypted on the endpoint with a key we've never seen. We store bytes and can't read them.
- Ciphertext of your taxonomy, blocklists, cadence The rules that decide what counts as an alert. Opaque to us. Ships from your PWA to your endpoints; we relay bytes.
- Version number of each config Endpoints ask "give me anything since version N." We answer with ciphertext.
- Channel + destination you chose e.g. "SMS to +1-555…", "email to
you@example.com", or a browser push subscription URL. We need these to deliver the "you have an alert" ping. - Delivery ledger When each notification was enqueued, dispatched, whether it delivered, and — for SMS/email — a content-free preview like "You have a new Backstop alert."
- Stripe customer id + subscription id Stripe's identifiers, not your card. We use them to look you up in Stripe.
- Plan, status, trial end, current period end Whether you're on monthly, annual, trial, active, past-due, or canceled.
- Request-level logs from Cloud Run Method, path, status, duration. No bodies. Retained per Google Cloud defaults.
- Postgres itself, at rest Hosted at Neon; encrypted at rest. A subpoena to Neon reveals the same rows listed above — same ciphertext.
These never touch our servers. By design.
Third parties in your account's supply chain.
Backstop is not the only service touching your account. A subpoena to Backstop cannot produce what these other companies hold, so we name them explicitly.
We can't hand over what we don't have. The architecture predates any subpoena.
The other products in this category have to negotiate with law enforcement about which alerts to disclose, which screenshots to pull from the cloud, which DMs to hand over. Backstop doesn't, because those things don't exist on our servers to begin with.
The trade-off is real: our servers cannot help you recover an alert if you lose your recovery mnemonic. That's not a bug we're working on — it's the same property that makes this page short.