Your finances, on your machine.

Sync with your bank, detect subscriptions, track spending, catch anomalies. SQLite database, system keyring credentials, encrypted backups. No cloud. No tracking. No account required.

$ pip install getfin

What it does

Bank sync

Connect via SimpleFIN for automatic daily sync, or drag-and-drop CSV exports from Chase, BofA, Amex, Wells Fargo, Capital One.

Subscription detection

150+ known services recognized instantly. Pattern detection finds the rest from 3+ recurring charges. Audit accuracy anytime.

Spending analysis

Auto-categorized transactions, top spending by category, 3-month rolling averages, outlier badges for unusual months.

Anomaly alerts

Duplicate charges, unusual amounts, price increases on subscriptions, bundle overlap detection (Disney+/Hulu/ESPN+).

Dashboard

Web UI at localhost. Cash flow, commitments, spending breakdown, alerts, 6-month trend. Drill into any number.

Full CLI

Everything the dashboard does, from the terminal. Sync, analyze, export, audit. Script it, cron it, pipe it.

Security model

This isn't checkbox security. fin's architecture eliminates entire threat categories by design.

Your financial data never leaves your machine. There is no cloud sync, no telemetry endpoint, no analytics pixel, no account system. The attack surface most finance apps spend millions defending simply doesn't exist here.

Where fin does handle sensitive data, it delegates to proven, audited tools — not homebrew crypto. OS keyrings for credentials. age for backup encryption. Your OS's full-disk encryption for data at rest. Every layer is something you can independently verify.

What we don't do

No cloud storage. No remote API. No user accounts. No login tokens. No session cookies. No telemetry. No analytics. No phoning home. Ever.

What we delegate

Credentials to your OS keyring. Backup encryption to age. Disk encryption to BitLocker/FileVault/LUKS. We didn't build our own — and that's the point.

Security details

For the auditors, the skeptics, and the people who read source code before installing anything.

Credential storage

Credentials are stored via the keyring library (v25.0+), which maps to the OS-native secure store: Keychain on macOS, Credential Manager on Windows, Secret Service (GNOME Keyring / KWallet) on Linux. Service name "fin". Falls back to environment variables if no keyring backend is available. Credentials are never written to disk in plaintext.

Encrypted backups

Backups use age — a modern, audited file encryption tool using ChaCha20-Poly1305. Two modes: passphrase-based (age -p) or recipient public key (age -r age1...). The age binary is invoked as a subprocess — fin does not implement its own cryptography.

TLS

The local web server generates a self-signed RSA-2048 certificate with SHA-256 signatures via the cryptography library. SANs include localhost, 127.0.0.1, and ::1. Certificate validity is 825 days (browser maximum). TLS is required for non-loopback binding — if you expose fin on your LAN, it will refuse to start without a valid certificate.

Full-disk encryption enforcement

On startup, fin checks whether full-disk encryption is enabled: fdesetup status on macOS, manage-bde -status on Windows. If FDE is off, fin blocks startup with setup instructions. This can be overridden with --i-understand-no-fde, but you have to mean it.

Web hardening

LayerImplementation
Rate limitingslowapi token bucket — 200/min API default, 60/min drilldown/search, 10/min sync
CSPdefault-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Frame protectionX-Frame-Options: DENY
MIME sniffingX-Content-Type-Options: nosniff
SQL injection100% parameterized queries (? placeholders). Zero string concatenation.
CSV formula injectionAll exports sanitized — leading = + - @ \t \r prefixed with apostrophe
Upload limits5 MB hard cap with overshoot detection. Returns 413 if exceeded.

SimpleFIN transport

HTTPS-only — rejects non-https:// URLs at validation time. Authentication via HTTP Basic Auth (RFC 7617). Credentials are extracted from the URL and sent as a header; only the hostname is ever logged. Retry logic via tenacity: 3 attempts, exponential backoff 2–10s, retries on transport errors only (not HTTP status codes).

File permissions

Database files: chmod 0600 on Unix, icacls user-only ACLs on Windows. Data directories: chmod 0700 / restricted ACLs. Best-effort on creation — non-fatal if the OS rejects the call.

Data integrity

Transaction fingerprinting uses SHA-256 over normalized fields — no raw sensitive data in hash output. Amount parsing uses Python's Decimal type with ROUND_HALF_UP (standard financial rounding, not banker's rounding). Amounts exceeding $1M are rejected as a sanity check.

Access logging

Every HTTP request is logged with client IP, method, path, status code, and response time in milliseconds. Static asset requests are excluded. SimpleFIN access URLs containing auth tokens are never exposed in error responses.

The source is the spec. If any of the above doesn't match what you see in the code, open an issue.

Install

Requires Python 3.12+.

# Install from PyPI
pip install getfin

# Start the dashboard
fin web
# Opens http://127.0.0.1:8000/dashboard

Or install from source:

git clone https://github.com/arclighteng/fin.git
cd fin
python -m venv .venv
source .venv/bin/activate  # .venv\Scripts\activate on Windows
pip install -e .
fin web

Docker:

docker compose build
docker compose run --rm fin sync
docker compose run --rm fin web

Connect your bank

CSV import — download a transaction export from your bank and drag it onto the import page. Format detection is automatic for major banks.

SimpleFIN — automatic daily sync. Subscribe at SimpleFIN Bridge (~$1.50/month), link your bank, paste the setup token into fin.

CLI reference

CommandDescription
fin syncPull latest transactions from bank
fin webStart the web dashboard
fin statusFinancial summary at a glance
fin trendMonthly trend over time
fin drill recurringAll recurring expenses
fin drill one-offsDiscretionary spending
fin drill alertsUnusual charges with details
fin audit-subsVerify subscription detection accuracy
fin bundle-checkFind overlapping subscriptions
fin export-backup -pEncrypted backup with passphrase
fin export-csvExport all data to CSV
fin credentials setStore credentials in system keyring

Sync options

FlagWindowUse case
--quick14 daysDaily sync
(default)30 daysWeekly sync, covers statement cycle
--full120 daysAfter a gap or absence
--annual-bootstrap400 daysInitial setup, finds yearly subscriptions

Data storage

OSDatabase location
Windows%APPDATA%\fin\fin.db
macOS / Linux~/.local/share/fin/fin.db

Override with FIN_DB_PATH environment variable.

Enable full-disk encryption (BitLocker, FileVault, LUKS) for at-rest protection with zero fin configuration.

Known services

150+ services recognized on first charge. A sample:

Netflix Spotify Disney+ YouTube TV HBO Max Hulu Adobe CC Microsoft 365 GitHub ChatGPT 1Password Dropbox iCloud Peloton Planet Fitness Strava

Unknown merchants detected automatically after 3+ recurring charges with consistent amounts and regular intervals.