What leaves your browser

Your transactions, categories, budgets, and balances stay in browser IndexedDB by default. The summary shows what this deployment can do; the full inventory below preserves every conditional and legacy path.

What stays local

Financial workspace data stays on this device unless you explicitly enable encrypted Cloud sync. Coffer has no analytics or remote error tracking inside the app.

This deployment

Account access is optional. Identity and session requests run only if you choose to sign in.

What can leave after a choice

Encrypted Cloud envelopes, AI model-file requests, and selected FX currency/date pairs leave only after the action named in the inventory. Financial plaintext is never sent with them.

How to verify

Open your browser's Network tab while using Coffer. Every destination, purpose, data shape, trigger, and deployment state is enumerated below.

This list is canonical. Adding a new network destination requires a PR that updates both the code (the Content Security Policy allowlist in vercel.json and public/_headers) and this page.

Only after you choose

Optional requests that start after a named action. Some also require the deployment or account eligibility shown on the row.

Destination
nuvtrqnvulphceqjrkpk.supabase.co
Purpose
Coffer account signup, login, passkeys, and session refresh
Data sent or returned
Email, password or passkey assertion, and account session tokens. No financial data.
Triggered by
User chooses to sign in or manages their account
Opt-in
Yes
Destination
/api/account (same origin)
Purpose
Load account identity, Cloud entitlement, and billing availability
Data sent or returned
Account session token; account ID/email and subscription status, period, and cancellation metadata are returned.
Triggered by
A signed-in user opens the app or Cloud settings
Opt-in
Yes
Destination
/api/account/reconcile (same origin)
Purpose
Refresh the account's Coffer Cloud entitlement from Stripe
Data sent or returned
Account session token. Coffer reads subscription ID, status, billing period, and cancellation metadata from Stripe server-to-server; no financial workspace data is sent.
Triggered by
User returns from Checkout or clicks Check activation again or Refresh plan
Opt-in
Yes
Destination
/api/billing/portal (same origin)
Purpose
Create an account-owned Stripe Customer Portal session
Data sent or returned
Account session token; a short-lived Stripe-hosted Portal URL is returned.
Triggered by
User clicks Manage Subscription
Opt-in
Yes — if eligible for this account
Destination
billing.stripe.com
Purpose
Stripe Customer Portal
Data sent or returned
Billing changes entered directly into Stripe's hosted page.
Triggered by
Coffer redirects the user after the Portal API succeeds
Opt-in
Yes — if eligible for this account
Destination
/api/account/delete (same origin)
Purpose
Delete the Coffer account and server-side Cloud state
Data sent or returned
Phase one sends the account session token. After the local handoff, finalization sends a temporary opaque receipt without workspace data. The browser's local financial data is deliberately retained.
Triggered by
User confirms account deletion in Settings; finalization and retries run automatically after the local handoff
Opt-in
Yes — if account deletion is enabled
Destination
/api/cloud/blob (same origin)
Purpose
Coffer Cloud encrypted blob sync via private server-side Blob relay
Data sent or returned
Account session token (or migration-period signed license) and an encrypted AppData envelope. Coffer does not receive its passphrase or plaintext contents.
Triggered by
User enables Cloud sync in Settings → Storage
Opt-in
Yes — with active Cloud access
Destination
/api/cloud/meta (same origin)
Purpose
Check whether the encrypted Cloud copy changed before sync
Data sent or returned
Account session token (or migration-period signed license); ciphertext object existence, size, last-modified time, and ETag are returned.
Triggered by
Cloud sync checks for a newer or conflicting encrypted copy
Opt-in
Yes — with active Cloud access
Destination
/api/cloud/delete (same origin)
Purpose
Delete the encrypted Cloud copy
Data sent or returned
Account session token (or migration-period signed license). No financial plaintext is sent.
Triggered by
User explicitly removes their Cloud copy
Opt-in
Yes — with active Cloud access
Destination
huggingface.co / cdn-lfs.huggingface.co
Purpose
WebLLM model weight download
Data sent or returned
Model-file request and normal connection metadata; no transactions or category prompts.
Triggered by
User enables AI categorization in Settings
Opt-in
Yes
Destination
api.frankfurter.dev
Purpose
FX rate fetch (ECB-sourced, multi-currency display)
Data sent or returned
Requested base/quote currencies and date; no balances or transactions.
Triggered by
User selects Frankfurter in Settings → Preferences → Rate Source
Opt-in
Yes
Destination
open.er-api.com
Purpose
FX rate fetch (fallback provider, multi-currency display)
Data sent or returned
Requested base currency; no balances or transactions.
Triggered by
User selects open.er-api.com in Settings → Preferences → Rate Source
Opt-in
Yes

Unavailable in this build

Capabilities present in Coffer's canonical inventory but disabled by this deployment.

Destination
/api/billing/checkout (same origin)
Purpose
Create or reuse an account-bound Coffer Cloud Checkout session
Data sent or returned
Account session token. Coffer sends account ID/email and the Cloud price to Stripe server-to-server; no card details pass through Coffer.
Triggered by
User clicks Subscribe to Coffer Cloud
Opt-in
No — unavailable in this build
Destination
checkout.stripe.com
Purpose
Primary account-based Stripe Checkout
Data sent or returned
Billing contact, payment, and tax details entered directly into Stripe's hosted page.
Triggered by
Coffer redirects the user after the account Checkout API succeeds
Opt-in
No — unavailable in this build

Legacy subscribers only

Migration paths retained for existing accountless Cloud subscribers, not new purchases.

Destination
/api/account/claim-license (same origin)
Purpose
One-time migration of a legacy signed Cloud license to an account
Data sent or returned
Account session token and signed legacy license (email, plan, and expiry). A matching legacy encrypted blob may be copied server-side.
Triggered by
An eligible legacy subscriber chooses to claim their plan
Opt-in
Legacy subscribers only
Destination
buy.stripe.com
Purpose
Legacy Payment Link and signed-license activation path only
Data sent or returned
Billing and payment details entered directly into Stripe's hosted page.
Triggered by
A legacy, accountless subscriber follows the old purchase path
Opt-in
Legacy subscribers only
Destination
/api/checkout/license (same origin)
Purpose
Verify a legacy Payment Link session and issue its signed license
Data sent or returned
Stripe Checkout session ID; a signed license is returned after server-side price and subscription checks.
Triggered by
Stripe returns an eligible legacy purchase to /activate
Opt-in
Legacy subscribers only

What still stays local

Same-origin does not mean “nothing leaves the browser.” The table lists Coffer's account, billing, entitlement, metadata, and encrypted-blob APIs explicitly. When Cloud sync is on, your browser sends an encrypted envelope to /api/cloud/blob; the server stores that ciphertext in private Vercel Blob storage. The browser does not talk directly to a public Blob URL.

Third-party analytics on the app itself (Google Analytics, Facebook Pixel, Hotjar, etc.) are not on this page because they do not exist in Coffer. The /app/* routes have no analytics scripts of any kind. The Content Security Policy keeps script execution scoped to Coffer itself.

Error tracking services (Sentry, Datadog, Bugsnag) are also absent by design. If Coffer crashes on your device, the stack trace stays on your device. We would rather fix issues based on user reports than collect them from your browser.