Expensify
A weekend of work, and real gaps remain.
Expense reports: photograph a receipt, it reads the amount and the merchant, it goes into a report, somebody approves it and it is reimbursed.
Build the expense tracking I actually need instead of Expensify — with a clear line around what stays outside. **Do not build the payment rail.** Reimbursing people means moving money, which means regulation, bank integration and liability. Build everything up to the payment file and let the bank or the payroll system do the last step. STACK - Node 20+ with Fastify, server-rendered HTML with a little vanilla JS - SQLite through better-sqlite3, WAL mode - Tesseract for reading receipts locally - Caddy in front THE DATA MODEL - expenses: id, person_id, spent_at, amount_cents, currency, merchant, category, project, receipt_id, note, status, submitted_at - receipts: id, path, sha256, ocr_json, ocr_confidence, uploaded_at - reports: id, person_id, period, status, submitted_at, approved_by, approved_at, exported_at - approvals: id, report_id, approver_id, decision, note, at — append-only - rates: date, base, quote, rate, source — **stored per day**, so a converted amount can be reproduced years later - Money in integer minor units. Never a float, anywhere, for any reason CAPTURE, WHICH MUST BE TRIVIAL - Photograph a receipt on a phone, it uploads and creates a draft expense. If it takes more than two taps, expenses are entered in a spreadsheet at month end from memory - Tesseract reads total, date and merchant; store the confidence and **pre-fill rather than decide**. An OCR error that silently changes an amount is a false accounting record - Anything under a confidence threshold is highlighted for the person to confirm - Duplicate detection on hash, and on amount plus date plus merchant — the same lunch submitted twice is the most common error and it is honest, not fraudulent CURRENCY, WHICH IS WHERE HOMEMADE VERSIONS BREAK - Store the original amount and currency, always. Convert for reporting using the stored rate for the spend date - Never overwrite an amount with a converted one. **The receipt says €48 and the record must always say €48** APPROVAL - Submit a report, route by amount and by cost centre, approve or reject with a note. Every decision recorded and none of them editable - A threshold above which a second approver is required, configurable - Policy checks as warnings on submission — missing receipt above a limit, spend outside a date range, a category that needs a project — shown to the person before they submit rather than bounced back a week later GETTING IT OUT - A CSV per accounting system with the exact columns it expects, and a payment file for the bank in its own format - Mark a report exported with the batch reference. **Reimbursed twice is the failure that costs real money**, and an export flag with a unique batch is what prevents it - Receipts exported as files alongside, named by expense id, because the tax authority wants the image and not the row RETENTION - Receipts kept for the statutory period in your country, which is years, and never deleted before it WHAT MATTERS MOST Original currency preserved and a hard export flag. One keeps the records true; the other stops anybody being paid twice.
What you lose
- Actual money movement — reimbursement into a bank account
- Receipt reading accurate enough that nobody checks it
- Accounting integrations that reconcile properly
- Corporate cards with transactions arriving automatically
If you would rather not build
- A shared folder and a spreadsheet, which is what this replaces for most teams
The escape hatch
open source · no votes, no paid placement
Firefly III
$0Self-hosted personal and small-business finance with rules and reports.
firefly-iii/firefly-iiifree · open source
Why this verdict
our own opinion · changed only by a person
48/100
Verdict kinda at 48: the tracking and approval are straightforward, the money movement is deliberately out of scope. Storing the original currency and the daily rate is the detail that keeps the archive defensible.
History
tracked since 14 Aug 2026 · nothing is ever overwritten
Nothing recorded yet. This chart fills in once the page has visitors, votes or prompt copies — it will not draw a flat line to look busy.
Questions about Expensify
answered from the record above
Is Expensify free?
No — the plan we track is $5 a month. Collect at $5 per member per month with the Expensify Card, $10 without.
Can you replace Expensify by building your own?
ALMOST. A weekend of work, and real gaps remain. Replacement score 48 out of 100, build time a weekend. Read what you lose before you decide.
How much does Expensify cost?
$5 a month on Collect — $60 a year. Recorded 14 Aug 2026.
What do you lose by replacing Expensify?
Actual money movement — reimbursement into a bank account; Receipt reading accurate enough that nobody checks it; Accounting integrations that reconcile properly; Corporate cards with transactions arriving automatically. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Expensify?
Yes: Firefly III, Invoice Ninja. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

