Last updated · May 17, 2026

Privacy policy.

Plain language, no dark patterns. If something here is unclear, email us — we'll fix the page.

We built Expense Tracker because we wanted a finance tool that doesn’t sell us back to ourselves. The same posture applies to your data here. This page describes exactly what we collect, what we don’t, and what you can do about it.

What we store

  • Bank statements you upload (CSV, PDF, XLSX). The original files are kept in a server-side directory so we can re-parse on demand and so you have an audit trail.
  • Transactions parsed from those statements: date, amount, description, the account it belongs to, the category we assigned.
  • Categorization preferences you create or that the AI learns from your edits.
  • AI conversation history — chat messages you send to the assistant and the model’s replies.
  • Account number (Mullvad-style identifier we mint when you sign up) and an optional recovery email if you choose to add one.
  • Subscription state from Stripe (status, current period end) — used to gate paid features.

What we don’t store

  • Your bank login credentials. We never see them. We don’t use Plaid or any other bank-sync provider — uploads are the only ingestion path.
  • Your card numbers. Stripe holds those. We see a subscription status and the last four digits at most.
  • Your real name, address, or phone number. We don’t ask for any of these.
  • Anything from third-party trackers. No Google Analytics, no Meta pixel, no session-replay scripts.

Where it’s stored

A single SQLite database file on a Hetzner server located in the EU. The file is encrypted at rest by the host volume. Backups are pushed nightly to a Cloudflare R2 bucket in the EU jurisdiction, encrypted client-side before upload. The whole stack runs as one Docker container behind Traefik with auto-issued Let’s Encrypt TLS.

Third parties (sub-processors)

We use the smallest set of vendors we can get away with. Each one is scoped to one job.

  • OpenRouter — proxies AI requests to the underlying model (typically Google Gemini Flash). Your bank statements and chat messages pass through OpenRouter to be parsed. OpenRouter’s policy is “no training on user data,” and we use the zero-retention header where available.
  • Stripe — processes payments. Stripe holds your card details under PCI-DSS. We receive only the subscription state.
  • Cloudflare — outbound transactional email (trial ending, payment receipts) if you give us a recovery email.
  • Sentry — optional. If you opt in (or if you self-host and configure it), application-error stack traces go to our Sentry project. PII is filtered before send.
  • Hetzner & Cloudflare R2 — infrastructure (compute & backup storage), EU regions.

Your rights (GDPR & otherwise)

Whatever jurisdiction you’re in, the same two API endpoints work:

  • GET /api/me/export — returns a single JSON file with everything we have about you: accounts, transactions, preferences, chat history, subscription state.
  • DELETE /api/me — permanently purges your user, transactions, accounts, preferences, chat messages, uploaded files, and Stripe customer record. There is no soft-delete. There is no “you have 30 days to change your mind”. It’s gone.

Both are reachable from Settings → Privacyif you don’t feel like cURLing. If you signed up with a recovery email and lose your account number, that email is the only way back — we can’t recover you from a name because we don’t have one.

Anonymous accounts

The default sign-up path mints an account number with no email attached. If you choose to stay anonymous and don’t add a recovery email, we genuinely don’t know who you are. We can’t reset your password, can’t merge accounts, and can’t help if you lose the account number. That’s the deal — we trade convenience for privacy.

Cookies

One cookie: auth_token. HttpOnly, Secure, SameSite=Lax, signed with HMAC-SHA256. It holds your user ID and an expiry timestamp. No tracking cookies. No analytics cookies. No banner to click through.

Retention

We keep your data as long as you keep using the product. If your subscription lapses, we retain read-only access for 12 months in case you come back. After 12 months of inactivity we email a deletion warning to your recovery email (if you set one) and purge 30 days later. You can also nuke everything yourself at any time viaDELETE /api/me — that path is always free, regardless of subscription status.

Children

Expense Tracker is not intended for users under 16. We do not knowingly process data from anyone under that age. If you believe a child has signed up, email us and we’ll purge the account.

Changes to this policy

We’ll update the “last updated” date at the top of this page and announce material changes on the changelog. We don’t email privacy-policy updates because most people would correctly classify that as spam.

Contact

Email support@expenses.pinguin.drilind.com. For EU-specific GDPR requests (data subject access, erasure, portability) please put “GDPR” in the subject — we’ll respond within 30 days as required by Article 12(3).