---
type: explanation
---

# Privacy

Privacy is **structural**, not policy. The platform does not collect user-level data because the architecture has no place to put it. We can't leak data we don't have. See [principles](principles.md#privacy-is-structural).

## What we do not collect

| Category | Status |
|---|---|
| User IP addresses | Not collected, not logged, not forwarded to Cap |
| User-Agent strings | Not collected |
| Geolocation / country | Not collected, not derived |
| Browser fingerprints | Not collected |
| Behavioral telemetry | Not collected |
| Per-user history | Not retained |
| Cross-site identifiers | Not issued |
| Device IDs | Not collected |
| Hosted-verification submission contents | Not stored — held in process memory only while forwarding, then discarded. See [hosted-verification](hosted-verification.md) and [ADR-0007](adr/0007-hosted-verification-paid-only.md). |

This list is exhaustive at MVP. If a future feature would require collecting any of the above, it does not ship in any tier — see [ADR-0002](adr/0002-no-risk-scoring.md) and [principles](principles.md#privacy-is-structural).

## Game code cannot reach user data

Games run inside a sandboxed iframe with an opaque origin (see [widget](widget.md#isolation) and [ADR-0015](adr/0015-sandbox-game-iframe.md)). Game code cannot read the customer's cookies, `localStorage`, `sessionStorage`, DOM contents (including other form fields on the page), or make same-origin `fetch` calls. This applies to both marketplace and customer-hosted games. The realm boundary makes "untrusted by default" a structural property, not a policy promise.

## What we do collect

Per site key, aggregate counters only:

- `sessions started`
- `sessions client-completed`
- `sessions server-verified`

Surfaced in the [dashboard](dashboard.md). No per-user dimension exists.

## What we collect about you (the customer)

One column of personal data per account row: **your email address**. That's it.

When you sign in via [OAuth](account-login.md), the provider hands us a payload that may include your name, avatar URL, locale, display name, given/family names, and a profile photo. We read it once at callback to assert verified email, extract the email and the stable provider user id, and discard everything else before any log line touches disk. The provider binding stored in `oauth_identities` carries `(provider, provider_sub, account_id)` — no name, no photo, no profile fields. See [account-login](account-login.md#what-we-store) for the longer version and [ADR-0020](adr/0020-magic-link-and-github-google-oauth-account-login.md) for the rationale.

## Comparison with competitors

The privacy posture is the wedge against the incumbents:

| Vendor | Privacy posture |
|---|---|
| reCAPTCHA | Collects extensive cross-site signals; tied to Google's identity graph |
| hCaptcha | Trains ML on user behavior |
| Turnstile | Fingerprints the browser |
| Cap (alone) | Private but boring (no game UX, no marketplace) |
| **Caputchin** | Private, gamified, structurally trustworthy |

## Implications for paid tiers

Several otherwise-obvious paid features are off the table for privacy reasons:

- **No "user analytics" tier.** Doesn't exist; never will.
- **Scoreboards** ([deferred paid idea](roadmap.md#paid-tier-ideas-deferred--explore-later)) are per-site-key, per-game aggregates only. Not per-user. The display handle is a 3-letter retro nickname (`^[A-Z]{3}$`, ~17.5k values) scoped to a single session and stored as a row attribute, never an identity record. Collected via a separate non-blocking endpoint, never indexed, never queryable. See [ADR-0014](adr/0014-scoreboard-3letter-async-naming.md).
- **[Hosted verification](hosted-verification.md)** (paid tier) does not store form submissions and does not collect submitter telemetry — the privacy posture extends across the paid features, not just the free tier.

## Why "structural"

Policy privacy means "we promise not to use it." Structural privacy means "we cannot use it because we never have it." A breach, subpoena, or business pivot cannot extract data that was never collected. This is the same posture Cap takes for PoW; Caputchin extends it across the whole product.
