Privacy-first receipt extraction
In-browser receipt OCR — extract merchant, date, total, tax & currency
Extract merchant, date, total, tax, currency and category hints from receipt JPG, PNG, HEIC, or PDF files in your browser.
- OCR and PDF text extraction run in your browser — nothing is uploaded
- iPhone HEIC photos and scanned PDFs work without converting them first
- Every field is editable before export, and ambiguous parses are flagged
Private by default: processing happens in your browser, with no upload or account required.
Try a clear receipt photo or a PDF. Pages with a text layer are read directly; pages without one (scans) are OCR'd automatically.
Ready. A sample preview is shown below until you choose a receipt.
In-browser receipt OCR — extract merchant, date, total, tax & currency
What this tool will not do
- One receipt at a time. There is no server-side batch mode; browser memory and CPU make large batches impractical.
- Accuracy drops on poor input. Below roughly 200 DPI, in bad lighting, at a steep angle, or on crumpled thermal paper, expect to correct fields.
- Handwriting is not recognised.
- The Excel export is an HTML table saved as
.xls, not a binary XLSX. It opens correctly in Excel, Numbers and Google Sheets, but it is not a real workbook file. - A bare currency symbol is ambiguous. "$" maps to one default currency and is flagged as
symbol_ambiguous— correct it if it guessed wrong. - It does not categorise your spending for accounting. The category hint is a suggestion, nothing more.
Runs Tesseract.js client-side (in the browser) to extract merchant, date, total, tax and currency from JPG, PNG, HEIC (auto-converted) and PDF (single or multi‑page — pages with an embedded text layer are read directly, pages without one are rendered to an image and OCR'd), then exports clean CSV, Excel-compatible XLS and JSON. Everything runs in your browser — there's no upload, no account, and no server-side processing.
Quick usage (3 steps)
- Upload or drag a receipt photo (JPG/PNG/HEIC) or a PDF, scanned or text-based, single or multi-page.
- Review the parsed preview table and correct any field before exporting — the tool never guesses silently past what's shown.
- Export downloadable CSV, Excel-compatible XLS, or JSON.
How it works — key principles & formulas (sources cited)
- Text normalization: OCR output is normalized with Unicode NFKC, trimmed and control characters removed before parsing (Unicode Normalization Forms, UAX#15: https://www.unicode.org/reports/tr15/).
- Digit mapping: fullwidth digits (e.g. 123) are folded to ASCII by NFKC; Arabic‑Indic digits (٠‑٩, ۰‑۹) have no NFKC compatibility decomposition to ASCII, so they're mapped explicitly by codepoint offset.
- Currency fraction digits: a compact currency→digits table (USD, EUR, GBP, CAD, AUD, JPY, KRW, BHD, KWD, OMR) sourced from CLDR digit counts (e.g. USD=2, JPY=0, BHD=3) is used as minor_units. Source: CLDR currencyData.json (https://github.com/unicode-org/cldr/blob/main/common/supplemental/currencyData.json). Currencies outside this table default to 2 digits.
- Canonical amount fields (machine-friendly):
- amount_decimal: string (decimal in major units, e.g. "1234.56").
- minor_units = digits_table(currency_code) // integer, default 2
- amount_minor_units = round_half_up( amount_decimal shifted by minor_units ), computed with BigInt to stay exact past Number.MAX_SAFE_INTEGER.
- Rounding mode: always ROUND_HALF_UP — there's no cash-rounding option.
- Separator & currency parsing heuristic (implementation order):
- Normalize text (NFKC) and map digits.
- Detect ISO currency code ([A-Z]{3}) if present.
- Otherwise detect a currency symbol ($, €, £, ¥) and map it to one default currency; this is inherently ambiguous (e.g. $ could be USD/CAD/AUD, ¥ could be JPY/CNY), so it's flagged "symbol_ambiguous" in parsing_flags rather than resolved via locale or EXIF data.
- Decimal separator rules: if both "." and "," appear, treat the rightmost separator as the decimal separator; otherwise decide by the currency's known minor_units or by the length of the fractional part (community heuristics; see Handsontable issue & Wikipedia: https://github.com/handsontable/handsontable/issues/4396, https://en.wikipedia.org/wiki/Decimal_separator). A single separator with exactly 3 trailing digits is genuinely ambiguous (thousands grouping vs. a 3‑decimal currency) and is flagged "ambiguous_separators".
- Remove thousands separators, normalize decimal to ".", then parse the digit string directly (no floating‑point arithmetic) and convert to minor units with BigInt.
- Date and currency normalization: dates are output in ISO‑8601 (YYYY-MM-DD) where parseable; currency codes follow ISO‑4217 when detectable.
- Output validation & flags: ambiguous parses are still returned as a best-effort value — shown in the editable preview for you to correct — and annotated with a parsing_flags array (e.g. "ambiguous_separators", "symbol_ambiguous") rather than silently blanked. For values whose minor-units amount exceeds Number.MAX_SAFE_INTEGER, amount_minor_units is returned as a string and metadata "big_integer": true is set.
Example JSON output fields (schema)
{
"merchant": "string|null",
"date": "YYYY-MM-DD|null",
"amount_decimal": "string|null",
"tax_decimal": "string|null",
"currency_code": "ISO-4217|null",
"amount_minor_units": "integer|string|null",
"minor_units": "integer|null",
"rounding": "ROUND_HALF_UP",
"confidence": 0..1,
"parsing_flags": ["ambiguous_separators","symbol_ambiguous"],
"big_integer": false,
"category": "string|null"
}
FAQ
- Does the tool upload my receipts to a server?
- No — there's no server component. All OCR, PDF text extraction and parsing run entirely in your browser; nothing is ever uploaded.
- Which input formats are supported?
- JPG, PNG, HEIC/HEIF (converted in-browser, so iPhone photos work directly) and PDF, single or multi‑page. PDF pages with an embedded text layer are read directly (fast, no OCR needed); pages without one — scanned receipts — are rendered to an image and OCR'd automatically, the same way a photo would be.
- How accurate is the OCR and why can amounts be wrong?
- Client‑side OCR (Tesseract.js) is reliable on clean, high‑DPI printed receipts, whether from a photo or a rendered scanned PDF page. Accuracy drops on low‑resolution photos (< ~200 DPI), poor lighting, heavy skew/perspective, handwriting or complex layouts. Always review the parsed fields before exporting — there's no server-side fallback.
- Which currencies and date formats are supported?
- The tool outputs ISO‑4217 currency codes and ISO‑8601 dates when detectable, with minor-unit digit counts sourced from CLDR for a compact set of common currencies (USD, EUR, GBP, CAD, AUD, JPY, KRW, BHD, KWD, OMR; other codes default to 2 digits). A bare symbol like $ or ¥ maps to one default currency and is flagged "symbol_ambiguous" in the JSON export — correct the currency field if it's wrong.
- Can I process receipts in bulk?
- One receipt at a time, processed locally — there's no server batch mode. Browser memory/CPU limits make this best suited to individual receipts rather than large batches.
- How do exports (CSV/Excel/JSON) behave?
- CSV follows RFC4180 quoting/escaping. The Excel export is an HTML table saved with an .xls extension (no external library) — it opens correctly in Excel, Numbers and Google Sheets but isn't a binary XLSX file. JSON uses the documented schema fields above, including parsing_flags and a confidence score.
- How does the tool handle currencies with 0 or 3 decimal digits?
- The tool applies amount_minor_units = round_half_up(amount_decimal * 10^minor_units) using BigInt so precision holds even for unusually large amounts. For example: USD (digits=2) -> 1234.56 => 123456; JPY (digits=0) -> 1234 => 1234; BHD (digits=3) -> 1.230 => 1230.