Skip to content
Products
Encrypted Email Messenger Group Chat For teams
Security
How encryption works What our servers can and cannot see Account security Private.Ki over Tor Private.Ki and VPNs
Company
Pricing About Careers Statement Help center Contact
Language
EnglishEN DeutschDE · soon EspañolES · soon FrançaisFR · soon
Create a free account Sign in
Transparency

What our servers can see — and what they can't

Five things you can count on. Each one is checked against the running code; the detail behind every claim is further down the page.

We can't read your messages.Every email, chat, attachment and voice message is encrypted on your device. Our servers only ever hold ciphertext they cannot open.
We don't keep logs.No access logs, no connection logs. Your IP address is not recorded — not who connected, not from where, not what was requested.
No links between accounts.Not one column in our database ties your conversation to anyone else's.
Your password never reaches us.OPAQUE lets your device prove it knows the password without sending it. We store a record that can check it, not read it.
Metadata kept to the minimum.Only what's needed to deliver: your username, who a message is for, and roughly when it was stored.
What we don't keep

We don't keep logs.

Most services write down every connection. We don't. Here is exactly what that means.

  • No access logs. Our web servers write no access log. Nothing records your IP address, your browser or which pages you requested.
  • No connection history. There is no record of who connected, from where, or from which device.
  • No mail-transport logs. Mail that crosses to or from the open internet is handed over and forgotten. We keep no log of who it was from or to.

The one thing derived from your IP address is a rate-limit counter: a keyed hash of the address, kept in memory for at most an hour so nobody can flood sign-up. It cannot be turned back into the address. What the service must hold to run at all — your username, the encrypted rows of your mailbox and their timestamps — is listed item by item below.

The complete list

What we can and cannot see

Every data item, sorted into five tiers. "Where" names the actual store; "how long" is the lifetime of the value in that store.

  • 1Never leaves your device
  • 2Ciphertext only
  • 3Transient, then gone
  • 4Hash only
  • 5Stored in the clear
Data itemTierWhere it livesHow longWhy
Message content
Message bodies — mail and chat2 CiphertextDatabase, content column, PGP-encrypted on your deviceUntil you delete it, or the self-destruct timer firesIt is your mailbox; it has to persist somewhere
Attachments, voice messages, inline images2 CiphertextInside the encrypted body, as MIMEWith the messageSame blob as the body
Attachment names, counts and types2 CiphertextInside the encrypted body and encrypted headersWith the messageNot needed for delivery
Subject lines of internal mail2 CiphertextEncrypted headers blob, AES on your deviceWith the messageNot needed for delivery
Sender line on a delivered copy ("name, address")3 Transient → 2Read in the request, encrypted to the recipient's public key, then stored as ciphertextClear for one requestThe recipient's client has to know who wrote
Reactions (emoji, and which message they refer to)2 CiphertextOne encrypted row per participant; the two rows share no valueUntil withdrawnDelivered like a message
Unsend / destroy instructions2 CiphertextEncrypted instruction row for the peer; deleted once applied. The kind ("unsent" or "destroyed") is in the clearUntil the peer's app applies itThe servers must stamp the kind onto the peer's row
Email signatures2 CiphertextDatabase, AES-encrypted on your deviceUntil you delete themYours to sync across devices
Drafts2 CiphertextDatabase, same encryption as sent mailUntil you delete themSync across devices
Message size (ciphertext length)5 ClearDatabase, used_bytesWith the messageStorage accounting; preload limit
Addressing — who talks to whom
Recipient addresses on an internal send3 TransientThe send request, in memory. Resolved to mailboxes, one encrypted copy written per recipient, and the list is not stored on any rowOne requestDelivery needs a destination
Recipient addresses while undo-send is open (mail only)5 Clear, short-livedJob-queue table, so the send can fire or be cancelled. Cancelling deletes the job; a fired job is disabled in place. Chat is never queuedYour undo window, 0–60 s (default 10 s)Undo-send needs the request kept until it fires
Who you correspond with (peer identity on a conversation)4 Keyed hashDatabase, derived_peer_email: HMAC of the peer's address under a key derived from your master key. The peer's row uses their key, so the two never matchLife of the conversationYour app needs to find the right thread
Group roster — name, members, admin2 CiphertextOne encrypted, signed state row per member; each encrypted separately, so no two rows share a blob. Group id is an HMAC under each member's own keyLife of the groupA member who reinstalls has to read the group back
Number of recipients at send time3 TransientThe recipient list in the send requestOne requestDelivery
Message ids and reply chains4 Keyed hashderived_message_id: HMAC of the Message-ID under your key. In-Reply-To is read once to pick the thread and not storedWith the messageThreading inside your own mailbox
Thread grouping inside your account5 ClearDatabase: which of your rows belong to one thread, and the newest row per folderWith the threadFast mailbox listing
Autocomplete history of people you wrote to2 CiphertextEncrypted blob per address, keyed by an HMAC under your keyUntil removedSync across devices
Timing and state
Timestamps on your rows5 ClearDatabase. Each recipient's copy is shifted by an independent random offset of up to 1 s (up to 60 s on group state), so copies of one send never share a valueWith the rowSorting your mailbox; expiring timers
Read and starred state5 ClearDatabase, two booleans on your own row. There are no read receipts, so nothing is sent to the other sideWith the messageUnread counts and sync
Delivery state of an outgoing mail5 Clearmailed_at, scheduled_at on your rowWith the messageUndo-send and the "sending" indicator
Self-destruct timer on a chat5 ClearDuration and mode, one row per participant; who set it is encryptedUntil changedThe servers run the sweep, so they must read the deadline
Self-destruct deadline on a message5 Clearself_destruct_at, with the recipient's copy pushed later by a random few secondsUntil the sweep, every minuteServer-side deletion
Typing indicators3 TransientRelayed over the WebSocket; never writtenMillisecondsLive UI
Online presence3 TransientRedis flag with a 100 s expiry, refreshed by the app's keepalive100 s after your last pingDecides whether to send a push instead of a socket message
External mail (ordinary SMTP)
Incoming mail from outside: headers, sender, body3 Transient → 2Readable on arrival. The whole raw message, the header set and the sender line are each encrypted to your key at once and stored as ciphertext. The importer writes nothing to disk in the clearClear for one importSMTP delivers plaintext; we cannot change what the sender's provider did
Envelope addresses of mail crossing to or from the internet3 TransientThe mail transport, in memory while the message is handed over. No transport log is keptOne hand-overThe other provider needs a sender and a recipient
Outgoing mail to outside addresses: To, Cc, Bcc, Subject3 TransientSet by the servers as SMTP headers and handed to the mail transport; not stored (except during an undo window, above)One requestThe other provider needs them
Outgoing external body3 Transient, or 2 if you imported their keyPasses through once. Domains and IP addresses found in an unencrypted outgoing mail are looked up against DNS blocklists; ciphertext is never scannedOne requestDelivery; outbound spam prevention
Imported public keys of outside contacts2 CiphertextKey and its metadata, AES-encrypted on your device; the address is an HMAC under your keyUntil you remove themSync across devices
Keys and credentials
Passphrase1 Never sentYour device only
Private key2 CiphertextDatabase, encrypted under a key derived from your passphrase, on your deviceLife of the accountSo a new device can fetch it and unlock it locally
Master key (AES and HMAC keys)2 CiphertextDatabase, encrypted to your keyLife of the accountSame reason
Public key5 ClearDatabaseLife of the accountPublic by definition; others must encrypt to it
Password1 Never sentOPAQUE: your device proves knowledge without transmitting it. We store an OPAQUE record that cannot be reversedRecord: life of the accountSign-in
Sign-in handshake state3 TransientRedis, 10 s expiry10 sOPAQUE is a two-step protocol
Session tokens and DPoP proofs3 TransientTokens are stateless and bound to a key on your device; each proof id is remembered in Redis for 14 s to refuse replays. Rotated refresh tokens are blacklisted until expiryAccess 30 min, refresh 90 daysAuthentication
Sign-in and token-refresh records5 ClearDatabase: token id, issue time and expiry per account, so a replayed or revoked refresh token can be refusedUntil the token expires, then prunedSession revocation and replay protection
Two-factor (TOTP) seed5 Stored, server-key encryptedDatabase, AES-256-GCM under a key kept outside the database. A dump alone cannot mint codes; the running service canUntil you turn 2FA offThe servers verify codes before your key is unlocked
Quick-unlock half key (PIN and biometric mode)5 Stored, server-key encryptedDatabase, same scheme; handed back only to the device whose DPoP key created the sessionSession expiry; swept dailyYour device combines it with its own half
Recovery address4 Salted hashArgon2 hash in the database. In the clear only in Redis, for the 15-minute verification window plus 5 minutes after use, then expiredHash: until you remove itTo check the address you type during recovery
Sign-in email (email-code accounts)4 Keyed hashHMAC-SHA256 under a server secretLife of the accountLook you up at sign-in without storing the address
WebSocket ticket3 TransientRedis; PGP-signed by your key; deleted on use, 10 s life10 sAuthenticate the live connection
Account, devices and invitations
Username, display name, account creation date5 ClearDatabaseLife of the accountYour address is your username; the display name goes on outgoing mail
Whether 2FA is on; undo-send length; unlock-method flags and salt; setup-checklist state5 ClearDatabase, flags on your accountLife of the accountThe server enforces them
Push tokens and device names5 ClearDatabase. The push itself says only "New email" or "New chat message" — no sender, no previewUntil the token is revoked or rejectedApple and Google need the token to deliver
Device pairing (QR) channel3 TransientRedis: 30 s while the QR is shown, 90 s once a phone claims it. What is relayed is encrypted to the new deviceAt most 2 minutesTwo devices need a meeting point
Whether you have ever paired a device5 ClearOne booleanLife of the accountSetup checklist
Chat invitation by email2 + 4The address AES-encrypted by you, plus a keyed hash so the accepting account can be matched. The invitation mail itself passes through onceUntil accepted or expired (24 h)Match the invitee when they arrive
Invite links (QR or URL)5 Code + 2A random code in the clear, plus the guest's proposed name encrypted under a key that travels only in the URL fragment, which browsers never send to usUntil redeemed, revoked or expired (7–30 days)Single-use redemption needs a lookup value
Sign-up invitation codes5 ClearRandom code, expiry, used flagUntil used or expiredInvite-only sign-up
Network and operations
IP address, browser, requested page3 TransientSeen on the connection, never written down. There is no access log, and the application stores no IP address in the databaseThe connectionAnswering your request
Rate-limit counters4 Keyed hashRedis, keyed by HMAC of the IP under the server secret, expiring within one hour≤ 1 hBrute-force and sign-up flood protection
Proof-of-work challenges3 TransientRedis, 2-minute expiry2 minBot resistance on public endpoints

Tiers 1–4 are what we designed for. Tier 5 is what a mail service cannot run without; every item in it is listed above, and nothing is left out because it looks unflattering.

No links between accounts

How the database is laid out

The usual way to store mail is one table with a sender column and a recipient column. Ours has neither. This is a conversation between Ada and Ben, as we see it.

Every conversation key is computed by you, not by us

The identifier that ties your messages to a peer or a group is an HMAC of that address under a key that exists only on your device once you have entered your passphrase. Ada's HMAC of Ben's address and Ben's HMAC of Ada's address are two unrelated values. There is no table with a "from" and a "to", and no value that appears in both accounts' rows.

The copies of one message share no value

A send writes one encrypted copy per recipient. Left alone, those rows would carry the same timestamp, and a GROUP BY on it would recover a roster. So every copy is moved by an independent random offset — up to a second for message rows, up to a minute for group state — and nothing in the table is a join key.

What this does not hide, stated exactly

Two things remain. The send request itself names the recipients, because a message has to be delivered somewhere; that list exists in memory for the request (and in the job table during an undo window) and is not written onto any message row. And a full dump still shows that rows in different accounts were written at about the same time — a weak statistical signal on quiet servers, weaker as the service grows. We would rather say that plainly than claim more.

In one line: the servers see an address when they deliver and forget it when they are done; what they keep is written so that no two accounts' rows can be joined.
Threat model

What a full database dump yields

Assume someone walks away with a complete copy of the database and nothing else — no server keys, no running application.

They would not get

  • Any message body, subject, attachment, reaction, signature or draft — all PGP or AES ciphertext under keys they do not have
  • Your private key or master key — encrypted under your passphrase
  • Your password — the OPAQUE record cannot be reversed or used to log in
  • Your recovery address — an Argon2 hash with a random salt; guessing would have to be done one candidate at a time, per account
  • Working 2FA codes or quick-unlock secrets — encrypted under a key that is not in the database
  • The sender or recipient of any message, or the roster of any group — encrypted per participant with no shared value
  • The names of your correspondents from autocomplete, imported keys or invitations — ciphertext and keyed hashes

They would get

  • The list of accounts: usernames, display names, public keys, creation dates, which have 2FA on
  • Per account: how many messages, their sizes, their timestamps, which are read or starred, how they group into threads, and when it signed in
  • Self-destruct durations and deadlines, in the clear
  • Push tokens and device names; invitation codes and their state
  • Any undo-send job still in the table: recipient addresses and, for external mail, the outgoing message
  • Write-time proximity across accounts, from which a determined analyst could attempt statistical correlation
Process

What a legal request could yield

We can only hand over what exists. This is what exists, and what does not, for a named account. It describes the system as built; it is not legal advice and makes no promise about jurisdiction or procedure.

Does not exist on our side

  • The content of any message, mail or chat, or of any attachment
  • Subject lines of internal mail
  • A list of who the account has written to or heard from
  • Group memberships
  • The password, passphrase or private key
  • The recovery address in readable form — we could only confirm or deny a candidate address supplied to us
  • Any log of IP addresses, connections or requested pages — none is written
  • Any log of mail passing to or from the outside — none is written

Exists, and could be produced

  • That the account exists, its username, display name, public key, creation date and 2FA status
  • Counts, sizes and timestamps of its messages; read and starred flags; self-destruct settings
  • Sign-in and token-refresh times, for as long as those token records are kept
  • There is no setting or mode in the service that makes content readable. The keys that would be needed are not on our side

Mail exchanged with outside providers is only as private as the other provider makes it. Their copy is theirs.

In numbers

Four numbers to remember

Each one comes straight from the code.

0 logsWe keep no access or connection logs. Nothing records your IP address.Nothing to hand over, nothing to leak.
0 linksNot one database column connects one person's conversation to anyone else's.A copy of the database shows no who-talks-to-whom.
≤ 1 sEvery copy of a message gets its own slightly different timestamp, so copies can't be matched by time.A random offset of up to one second per recipient copy.
20 minYour recovery address is held in memory only while a code is being sent — never longer than 20 minutes. After that only a salted hash exists.A 15-minute code window, plus 5 minutes after the code is used.
Check it yourself

Don't take our word for it

The same facts are written up in the help center, and two public documents say what has — and has not — been asked of us.

Below: the screens in the app that correspond to rows in the list. The captures are unedited.

Recovery address — tier 4, hash onlyEntered once, verified by a code sent to it, then stored as an Argon2 hash. The clear address lives in Redis for at most 20 minutes and is never written to the database.
Your keys — tiers 5 and 2The public half is public by design and stored in the clear. The private half is generated on your device and stored only encrypted under your passphrase.
Imported keys — tier 2An outside contact's public key is encrypted with your AES key before upload, and the address it belongs to is stored as an HMAC under your key.
Pairing — tier 3, transientThe channel is a Redis key that lives 30 seconds unclaimed and 90 seconds once claimed. The comparison of the code happens between two screens you are holding.
Invitations — tiers 2 and 4The invitee's address is encrypted by you and matched by a keyed hash. For link invites, the key that reveals the guest's name never leaves the URL fragment.
Two-factor on — tier 5The on/off flag is account data. The seed itself is stored encrypted under a key that is not in the database, so a dump alone cannot mint codes.

Questions

Write to [email protected]. If a row on this page is wrong, or has gone out of date, we would like to know — the matrix is maintained against the code, and corrections go in.

For how the encryption itself works, see Encryption.