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.