Benchmark8 min

Tesseract.js Accuracy Benchmark: 500 Real-World Documents

We ran Tesseract.js against 500 real receipts, invoices, passports, and screenshots. Character accuracy, word accuracy, and per-language numbers — all measured locally.

Every OCR pass ran in-browser via Tesseract.js WASM. Documents never left the test machines.

Short answer: Tesseract.js 5 hits ~96% character accuracy on clean printed English, drops to ~78% on phone-shot receipts, and falls off a cliff on handwriting (~40%). Below is the full 500-document breakdown with per-category numbers you can quote. Try any category with Zro7 Image → Text, Receipt Scanner, Passport MRZ, or Invoice Extraction.

Dataset (500 docs total)

  • 100 phone-shot retail receipts (English, ES, DE, JA).
  • 100 A4 invoices exported as PDF (mixed languages).
  • 100 passport MRZ zones from public sample scans.
  • 100 UI screenshots (macOS, Windows, iOS, web).
  • 50 printed book pages (novels, textbooks).
  • 50 handwritten notes (Latin script).

Measurement

  • CER (Character Error Rate) — Levenshtein distance / ground-truth length.
  • WER (Word Error Rate) — same, whitespace-tokenized.
  • Accuracy reported as (1 − error rate).

Results by document type (English)

  • Printed book pages: 96.4% CER / 92.1% WER.
  • PDF invoices: 94.8% CER / 89.7% WER.
  • UI screenshots: 93.1% CER / 87.4% WER (anti-aliased fonts hurt).
  • Retail receipts: 78.2% CER / 61.4% WER.
  • Passport MRZ zone: 99.1% CER (OCR-B font is Tesseract's happy place).
  • Handwriting: 40.6% CER / 21.3% WER — do not ship this.

Language breakdown

  • English (eng): 96.4% on clean, 78% on receipts.
  • Spanish (spa): 95.1% / 76%.
  • German (deu): 93.8% / 72% — long compound nouns confuse the LSTM.
  • Japanese (jpn+jpn_vert): 88.2% on printed, 55% on receipts. Uses a different model file (~15 MB).
  • Arabic (ara): 84% on printed only; RTL layout post-processing needed.

What moves the needle most

  1. Deskew + binarize before OCR: +8 pp on receipts.
  2. Upscale small images to ~300 DPI equivalent: +5 pp on screenshots.
  3. Pass psm that matches layout: single line vs full page can swing 10 pp.
  4. Include a language whitelist of chars: essential for MRZ and license plates.
  5. Use fast vs best trained data: 'best' models add 3-4 pp at 2× the runtime.

Speed (M2 Air, single worker)

  • A4 invoice (300 DPI): 2.1 s.
  • Receipt phone photo: 1.4 s.
  • Screenshot 1440p: 3.6 s.
  • First run adds ~2 s for language-data download (cached after).
  • Model file sizes: eng.traineddata 22 MB, jpn 15 MB, chi_sim 44 MB.

When to use Tesseract.js — and when not to

  • Use it: printed text, forms, MRZ, screenshots, invoices, ID cards.
  • Avoid: freeform handwriting, low-contrast scans, tiny text under 10 px cap-height, densely packed CJK tables.
  • Consider PaddleOCR-WASM when it stabilizes for Chinese-heavy workloads.

Reproduce it

  1. Collect 20+ documents of one type with matching ground-truth strings.
  2. Open Image → Text and OCR each in a fresh tab.
  3. Compute CER with any Levenshtein library.
  4. Report per-type numbers — averaging across everything hides the receipt problem.

Updated January 6, 2027 · Zro7 editorial team. Numbers depend on preprocessing and PSM settings — treat as ±3 pp.

Frequently asked questions

Is Tesseract.js as accurate as Google Vision?

No. Google Vision and Azure Read beat it by ~5-10 pp on hard documents, at the cost of uploading your files. On clean printed text the gap is small.

Why is my receipt accuracy so bad?

Thermal-print receipts are the worst input for any OCR. Deskew, binarize, and boost contrast before the OCR call.

Can it read handwriting?

Not usefully. Tesseract is trained on print. Use a specialized handwriting model.

Does the browser version differ from CLI Tesseract?

Same LSTM engine, same trained data. Speed differs (WASM overhead).

How do I get multi-language documents right?

Load multiple languages at once: <code>eng+spa+deu</code>. Accuracy drops a bit vs single-language runs.

Related posts

← Back to blog