A personal expense tracker built to replace an Excel sheet: monthly budgets, daily expenses, fixed payments, category breakdowns, and receipt scanning via OCR. Built with React, TypeScript, Vite and Tailwind, with a small Express backend for the OCR step.
- Monthly overview with budget progress, top-line cards and month switching (opens on the month of your latest entry)
- Daily expenses with add, edit and delete (themed in-app confirmation dialogs)
- Fixed expenses that carry over each month, with paid/unpaid tracking
- Category breakdown showing where the money goes
- Receipt scanning: upload a photo or PDF, review the extracted items, fix any uncategorised ones, then confirm. Tuned for German supermarket receipts (comma decimals, tax-code letters, English and German category keywords)
- Three themes: light, dark and a coffee-inspired latte/mocha
- Private by design: all data lives in your browser's
localStorage. No accounts, no database
React 19, TypeScript, Vite, Tailwind CSS, Express, OCR.space (free tier)
Get a free OCR key at https://ocr.space/ocrapi, then:
cp server/.env.example server/.env # paste your key into OCR_SPACE_API_KEY
npm installStart both servers, each in its own terminal:
npm run dev # frontend on http://localhost:5173
npm run server # OCR backend on http://localhost:8787npm run dev:full runs both in one terminal (requires Node 20+). Without the backend, everything except receipt scanning still works, and uploads simply show as "Failed" in the inbox.
- GitHub Pages (frontend only): a workflow in
.github/workflows/deploy.ymlbuilds and publishes the site. Set Settings → Pages → Source to GitHub Actions. Receipt scanning needs a separately hosted backend; set the repo variableVITE_OCR_SERVER_URLto its address. - Vercel (frontend and OCR backend together):
api/index.jsexposes the Express app as a serverless function. AddOCR_SPACE_API_KEYin the project's environment variables.
Browser uploads file → /api/parse-receipt → OCR.space (key stays on the server)
→ raw text → parseReceiptText.js extracts date, line items and total
→ items are matched to categories, anything unmatched goes to "Needs Review"
→ you review and confirm, and only then are expenses created
The API key never reaches the browser. Nothing is guessed: uncategorised items block confirmation until you assign them.
- OCR.space's free tier accepts files up to 1 MB and PDFs up to 3 pages, and is occasionally throttled during busy periods (error
E571, just retry later). - Parsing is heuristic, not a receipt-understanding model. Faded thermal paper, glare or tilted photos will land more items in "Needs Review".
- Data is per browser and per address; there is no export/import yet.
src/ React app (components hold UI only, lib/calculations.ts holds all the maths)
server/ Express OCR backend and receipt text parser
api/ Vercel serverless entry point
.github/ GitHub Pages deploy workflow
Never commit server/.env; it is already in .gitignore. Only .env.example (placeholder values) belongs in the repo.