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
- No account, no email, no password. Your sync identity is just two random 256-bit secrets generated on your device.
- End-to-end encrypted sync. Your content is encrypted with AES-GCM-256 using a key derived (via HKDF-SHA256) from one of those secrets. That key never leaves your device.
- The server never receives your encryption key — or the secret it comes from. When linking or restoring, your device sends only a one-way SHA-256 fingerprint of the secret (which is all the server stores to recognise you). The raw secret, and the key derived from it, never travel over the network.
- Metadata is not encrypted. The server can see that you synced something and when (event timestamps, device id, a version number), but not what — titles, notes, schedules, and completion dates are all inside the encrypted payload.
Identity model
When you enable sync for the first time, your device generates locally:
- User ID — a random identifier (UUID) for your data, not tied to your name, email, or phone. Sent in the clear.
- Sync secret — 256-bit random root of both authentication and the encryption key. Never sent raw — only its SHA-256 fingerprint is transmitted.
- Device ID — identifies this specific device (UUID). Sent in the clear.
- Device token — a 256-bit per-device key that authenticates this device to the API. It is auth-only and cannot decrypt anything. Sent once when registering/linking a device, then only its hash is stored.
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. Both devices derive and display the same six-digit confirmation code from the shared secret. Compare those codes before accepting the link. The server only ever holds public keys and ciphertext, so it cannot derive the shared key. The QR does not contain a secret, but someone who captures it can attempt to substitute a different pairing; a mismatched confirmation code exposes that attempt. (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
- Settings → Sync → Delete cloud data — hard-deletes all of your sync data on the server (events, device records, link tokens, sync state, and your encrypted snapshot blob) along with your user record.
- No device authenticates for 6 months — the same deletion runs automatically via a periodic inactivity cull.
- You disable sync on a device — that device's local credentials are wiped and its server record revoked. Your other devices and data stay intact.
- Expired, single-use link codes are purged regularly.
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:
- Network eavesdroppers — TLS protects every request, and the raw sync secret + encryption key never traverse the network at all (only the SHA-256 fingerprint does).
- A malicious or compromised server reading your content — because the client only ever sends the fingerprint, even a server that logged every request could not derive your encryption key. (It could capture a device token to act as one of your devices, but a device token can't decrypt anything, and a malicious server already controls its own data store.)
- A read-only breach of the database or snapshot storage — both hold only ciphertext + nonce + auth tag plus routing metadata. No content is readable without the sync secret, which is never stored.
- Pairing substitution — the two devices derive a confirmation code from their shared secret; a substituted pairing produces different codes. This depends on the user comparing them.
- Accidental screen leaks — secure-window protection on sensitive sync-key screens.
- An unlocked device in someone else's hands, briefly — the biometric gate on cross-device-security actions.
Not defended (and we won't pretend otherwise):
- A captured pairing QR when its confirmation code is not checked — the QR contains no decryption key, but an attacker can try to replace the intended pairing. Stop whenever the two codes differ.
- An attacker with your unlocked device and your biometric (coercion): no software-only product can defend against this.
- Traffic-pattern analysis — a passive network observer can see request timing, IP, and rough payload size.
- State-level adversaries / forensic device extraction — out of scope for a personal tracker.
- Forward secrecy — one key decrypts all of your events; if the sync secret leaks, past events under it are exposed. Rotating the sync key (in Settings) re-keys going forward and removes the old ciphertext from the server.
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.