Privacy & Sync Security

A plain, honest account — written to be clear, not to impress.

Again is local-first: the app works fully offline, with no account, no email, and no password. Sync between your own devices is optional and opt-in — nothing leaves your device unless you turn it on.

In short

Identity model

When you enable sync for the first time, your device generates locally:

Both secrets are kept in your device's secure storage — the iOS Keychain directly, and on Android an encrypted store sealed with a key held in the hardware-backed Android Keystore. Server-side, only SHA-256 hashes of each secret are ever persisted — never the secrets themselves.

"Pseudo-anonymous", not "anonymous": Cloudflare logs the client IP per request (their default, retained briefly). A determined adversary who could subpoena Cloudflare could in principle correlate a User ID with an IP. We don't claim more than that.

What's encrypted, what isn't

Each sync event has metadata that stays in the clear — id, user id, device id, event type, a version number, and timestamps — plus a payload field carrying the content (the loop's title, notes, emoji, colour, schedule, completion dates…). That payload is wrapped in an AES-GCM-256 envelope; the 32-byte key is derived on each device from the sync secret via HKDF-SHA256.

HKDF is one-way: even someone who recovered the key could not work back to the sync secret. The key is never stored or transmitted — every device re-derives it on demand, which is how two devices holding the same secret read each other's events.

What the server (or anyone with read access) can see: how many events of each type exist, their timestamps, which device created each, and your overall activity cadence. What it cannot see: your titles, notes, emoji, colours, schedules, or completion dates — and we never collect your email, name, phone, contacts, location, or photos at all.

Linking a second device

QR scan. The new device generates an ephemeral key pair and shows a QR carrying a random pairing id plus its public key — no secret. The existing (already-enrolled) device scans it, performs ECDH against that public key, and AES-GCM-seals your sync secret + user id under the derived key. It posts that sealed blob to a single-use, 60-second relay; the new device claims and opens it with its private key, then enrols. The server only ever holds two public keys and ciphertext — it can't derive the shared key, and the QR carries nothing a photo could exploit. (Same handshake the web companion uses.)

No other device to hand? Settings → Sync → Restore from sync key rejoins from your saved key directly — no second device, no code.

Screen-leak defence

The screens that show the QR or the raw sync key set the platform's secure-window protection — FLAG_SECURE on Android and a secure-layer overlay on iOS — so while they're open, the system blocks screenshots, recents thumbnails, screen recordings, and most screen-mirroring. A separate biometric prompt gates those screens, so even on an unlocked phone you must re-authenticate before anything is revealed.

This closes the easy, accidental exfiltration paths. It is not a defence against an attacker holding your unlocked device — see below.

Data retention & deletion

Cloudflare retains request metadata (including IP) briefly per their own defaults; we have no admin control over that.

Threat model — what we defend, what we don't

Defended:

Not defended (and we won't pretend otherwise):

This is not a marketing document — it's a plain description of how sync actually works, caveats included. If something here doesn't match what you see, the contact address is on the privacy page.