This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
A web page that turns receipt pictures into a spreadsheet you check before you use it. You drop in pictures, the page reads vendor, date, total and tax, it highlights anything it is unsure of, you fix the fields and tick "I checked this", then you download a CSV. No terminal, no account, no API key.
Who would pay: my guess is a freelancer or a tiny shop with a pile of receipts who would rather not upload them to a cloud service. That is a guess. I have no users and nobody has paid or been asked to pay.
Demo
https://maybesomeone-arc18.github.io/receipts-to-csv/
Open it, choose a few receipt pictures (JPG, PNG or WebP), check the highlighted fields, download the CSV. The first load downloads the reading models and runtime, roughly 60 MB by file size, so use wifi.
Code
https://github.com/MaybeSomeone-arc18/receipts-to-csv
MaybeSomeone-arc18
/
receipts-to-csv
Local-first receipt reader: pictures to a checked CSV, all in your browser (open OCR models, no upload)
Receipts to spreadsheet
Add pictures of receipts, check the highlighted fields, download a CSV. No terminal, no account, no API key. Everything is read in your browser; your pictures are not uploaded.
Built for DEV's Hacktoberfest "Side Hustle" challenge (Oct 2026). Built with AI coding help. Nobody is paying for it and it has no users yet.
How it works
- Reading: PP-OCRv5 mobile detection and recognition models (Apache-2.0) run through PaddleOCR.js and ONNX Runtime Web (wasm), in the page.
- A rules-based step picks vendor, date, total and tax from the text lines. Anything unsure is shown as "Please check".
- The CSV has a BOM (opens in Excel), quoted text, and a leading apostrophe on text that starts with = + - @ so spreadsheets do not run it as a formula.
- One-time model download is roughly 60 MB uncompressed (models 21 MB, script 11 MB, ONNX wasm up to 28…
How I Built It
- Reading: PP-OCRv5 mobile text detection and recognition models (Apache-2.0) through PaddleOCR.js and ONNX Runtime Web, running in the browser page.
- A rules step picks vendor, date, total and tax from the text lines. Unsure fields are marked "Please check" with a plain reason. Tax is always marked, because it is the weakest field.
- The CSV opens in Excel, Google Sheets and LibreOffice. Text that starts with = + - or @ gets a leading apostrophe so a spreadsheet does not run it as a formula.
- Memory was the hard part. Reading many receipts in one page ran my 2 GB test machine out of memory after about 5. The reader now runs in a hidden frame that is replaced every few pictures. 67 receipts in a row then ran without a crash on that machine (peak browser memory about 1.5 GB). I did not test a phone.
I built this with AI assistance (an AI coding agent wrote and tested much of the code). Checks: automated browser runs of the full upload, edit and download flow, and a held-out evaluation.
Measured, on 100 Indonesian receipt photos (CORD-v2 test split, CC-BY-4.0, used for testing only). I tuned the rules on 50, froze them, then scored the other 50 once:
- Total exactly right: 35 of 47 counted receipts on the tuning half, 35 of 48 on the held-out half. 5 receipts had no usable ground-truth total and were left out.
- All 13 wrong held-out totals were flagged "Please check", but about half of all receipts get flagged. This is one dataset. Other layouts, languages and currencies are untested and will do worse.
- Tax was right 10 of 23 times on the held-out half. Vendor and date were not scored, and on these photos they were often not read at all.
- It is not for accounting. Amounts are plain numbers and the currency is not read.
Why Does Open Innovation Matter?
The reading models and the runtime are open and run in the page, so the page does not need an API key or a per-receipt fee, and I do not need to run a server for it. In one scripted browser session against the live page, after uploading three pictures every request was a GET to the same site (the page, the script, the two model files and the runtime) and none carried the picture. That is one session on one machine, not a guarantee for every browser. A closed API would have meant keys, costs and sending the pictures to someone else's servers.
Credits
PaddleOCR / PP-OCRv5 (Apache-2.0), ONNX Runtime Web (MIT), CORD-v2 (CC-BY-4.0).
Top comments (0)