Subprocessors
Every third party that touches Pollis, what each one sees, and where it runs.
What they do see is metadata, and that varies a lot. One sees your email address and one-time login code in plain text; others see when you were active. The table says which is which.
Who sees what
| Subprocessor | Role | What it can see | Where |
|---|---|---|---|
| Turso libSQL |
Metadata database and encrypted-envelope store |
In the clear: account records including your email address and
username, group and DM membership, blocks, conversation timestamps, device registrations,
and security events. Ciphertext only: message bodies. With sealed sender, the stored row does not record who sent what. |
AWS us-east-1 |
| Cloudflare Workers & Containers |
Hosts the Delivery Service — the only writer to the database | Every write as it happens, including the sender's identity, which each request authenticates. Sealed sender protects stored rows only, so it does not hide the sender here. Also the connecting IP, as any edge does. | Cloudflare's global network; placement is not pinned |
| Cloudflare R2 | Attachments, download CDN, transparency-log hosting | Encrypted attachment blobs, their size and upload time, and an object key derived from the content hash; no filename, user or conversation id. Avatars and group icons are not encrypted and are public to anyone with the URL. | Cloudflare global |
| Resend | Sends the login email | Your email address and six-digit one-time code, in plain text, for the duration of the send. This is the largest plaintext exposure in the system. The Delivery Service sends the email; the app never holds a Resend credential. | Provider-determined |
| Expo then Apple APNs / Google FCM |
Background push notifications | Your device's push token, fixed text ("New message") and an opaque per-recipient handle that names no conversation and cannot be matched across users. No content, sender or preview. It still reveals that this device had activity at this time. The Delivery Service sends the push, so Expo sees Cloudflare's address, not the sender's. Your device contacts Expo directly when it registers for a push token, so Expo sees the recipient device's IP then, and Apple or Google see it when they deliver a notification. | Provider-determined |
| Amazon Web Services | The relay pool, its signed directory, and the control plane | A relay sees the ciphertext it forwards and the two ends of its hop. The first hop sees your IP, and every hop learns which account built the circuit, because each verifies your device certificate. Never content. See the roster below. | Nodes across four US regions; control plane us-west-2 |
| A single leased virtual server | Runs the self-hosted LiveKit media server and TURN relay | Who is in a call, which room, when, and your IP, which it needs to route media. Call audio and video are end-to-end encrypted and forwarded as ciphertext; the realtime signalling JSON is not encrypted at the application layer. No call record is written to any database, and the server keeps no access, error or container logs. | One host, one location |
| GitHub | Source, CI, releases, container registry | No user data, but it is inside the publishing trust boundary: the transparency log is built and signed in GitHub Actions, which also holds the release-signing keys. Assurance covers what that means. | Global |
| Apple · Microsoft | Code signing and notarization for macOS and Windows builds | Build artifacts. No user data. | Global |
| Sigstore Fulcio & Rekor |
Keyless signatures and build provenance | Artifact digests and the build workflow's identity, published on purpose in an append-only log Pollis does not operate. No user data. | Global |
| Doppler | Secret management for server credentials | Service credentials. No user data. | Provider-determined |
There is no analytics, telemetry, crash-reporting or advertising subprocessor, and no payment processor. No such SDK is in the codebase.
Providers' own operational data is governed by their policies. That includes Cloudflare edge logs, Turso platform logs, the media server's telemetry and APNs/FCM delivery records. This page says what each party can observe; it cannot promise what they keep.
Recipients are a limit too. Delivered messages live in recipients' local encrypted databases, which Pollis cannot reach.
The relay pool, and who operates it
Pollis has an optional relay overlay that hides your IP address from the first-party services. The design documents describe a stronger arrangement than what actually runs, so here is the current state.
It is opt-in and off by default. Unless you have turned on network privacy in preferences, none of your traffic goes through a relay and this section does not apply to you.
The pool is currently switched off. No relay nodes are running; the pool was small, barely used and cost money to keep up. With network privacy set to off or prefer, nothing changes: prefer connects directly, as it always did when the pool was unreachable. With strict, sending pauses rather than connecting directly; switch to prefer to keep sending. The table describes the pool as configured, and as it will run if switched back on.
| What the design allows for | What runs when the pool is on | |
|---|---|---|
| Operators | Guidance for self-hosters is to run nodes across at least two unrelated providers, so one provider's outage or subpoena cannot take the pool. | Every node is first-party, in one AWS account. The two-provider guidance is for third parties running their own nodes; it does not describe the Pollis pool. |
| Jurisdiction | Placement is drawn from an allowed region set with a jurisdiction denylist available. | Four US regions (Virginia, Ohio, California, Oregon), with the denylist empty. All nodes are in the United States. |
| Placement | A pool-wide node count, not a per-region map. | Each node's region is redrawn at random every 24 hours, with replacement, so two nodes can share a region. There is no stable per-region roster. |
| Size | Floor of 2 nodes, hard cap of 3, bounded by a $20/month budget. | The cheapest ARM instances AWS sells, on spot pricing. |
| Control plane | Subject to the same jurisdiction policy as the nodes. | In us-west-2. It sees every relay's IP. |
Check the roster yourself
The directory is public and signed:
curl -fsSL https://relays.pollis.com/directory.json \
| jq -r .payload_b64 | base64 -d \
| jq '{issued_at, expires_at, relays: [.relays[] | {addr, region}]}'
Returns each node's address and region. While the pool is off, this returns the last signed directory,
with an expires_at in the past; clients refuse an expired directory, so a stale roster
cannot stay in use. When the pool is on, placement rotates daily, so the output changes from day to
day.
A first-party pool means one operator at both ends. With multiple hops no single node holds both your IP and your destination, but we run the first and last hop, so those two logs could be joined. A middle hop in a different trust domain prevents that, which is why the design has volunteer relays and never gives a volunteer the first or last position. There are no volunteer relays today.
This hides your network address, not your identity. Every hop verifies your device certificate and so learns which account built the circuit. Hiding the account needs anonymous credentials, which are not built.
An observer who can watch both ends of a circuit can correlate it by timing and volume, however many hops it has. No overlay of this kind fixes that.
The whole pool currently shares one QUIC identity certificate, so the client pins the certificate rather than any address.
The directory-signing key is Ed25519, not post-quantum, because the signer runs in an environment with no ML-DSA implementation. One key signs both the directory and the revocation list, so a signature proves who signed but not which document.
Push notifications do not use the overlay. APNs and FCM reach your device directly. See the Expo row above.