Tesseract --oem modes: use 1, and check what 3 does
91.6%
of book words found with --oem 1
Try it on your PDF, $0.006 a page
Four modes, and the one to pick
| Flag | Engine |
|---|---|
--oem 0 |
Legacy only |
--oem 1 |
Neural LSTM only. Use this one. |
--oem 2 |
Legacy and LSTM together |
--oem 3 |
Default, based on what is available |
This is the engine, not the page layout. Layout is
--psm. To print this list, run
tesseract --help-oem.
--oem 3 means two different things
| Model file | --oem 3 runs | --oem 0 or 2 |
|---|---|---|
| tessdata_fast | LSTM, same as --oem 1 | Error |
| tessdata_best | LSTM, same as --oem 1 | Error |
| tessdata | Both, same as --oem 2 | Runs |
Same means the same text on all 60 scans. Homebrew, Ubuntu 24.04 and a
Debian image all held
tessdata_fast. If you use plain
tessdata, pass --oem 1 yourself.
--oem 1 won on real book scans
| Mode, file | 60 pages, 15,622 words | 55 printed pages, 14,693 words |
|---|---|---|
| 1, fast | 14,310 | 13,858 |
| 1, best | 14,313 | 13,840 |
| 1, tessdata | 14,312 | 13,848 |
| 2, tessdata | 14,050 | 13,748 |
| 0, tessdata | 13,827 | 13,719 |
One book is a handwritten manuscript, and legacy read very little of it. That is most of the gap, so read the printed column too.
Against LSTM on the same file, legacy was worse on 42 of 60 pages, and both engines together on 45. Legacy took less CPU than that LSTM run, and more than tessdata_fast.
Legacy beat LSTM on made-up invoices
I expected legacy to lose everywhere. It did not.
| Test | LSTM | Legacy |
|---|---|---|
| Made-up invoices, 2,454 numbers | 2,218 | 2,409 |
| Real receipts, 1,117 digit words | 345 | 252 |
| Book scans, 235 digit words | 174 | 172 |
Those invoices use common computer fonts with a made-up scan look. The gap was widest in Courier: 612 of 612 for legacy, 514 at best for LSTM. Georgia was the one font where LSTM led, and the book row is a tie.
My advice: if your pages are typed tables, run some
both ways and count. Otherwise stay on
--oem 1.
Fix the legacy engine error
Error: Tesseract (legacy) engine requested, but components are not present in /opt/homebrew/share/tessdata/eng.traineddata!!
Your file is LSTM only, so you have nothing to repair unless you want legacy. This prints 0 for LSTM only, and 1 when legacy is inside:
combine_tessdata -d "$(brew --prefix)/share/tessdata/eng.traineddata" 2>&1 | grep -c inttemp
To run legacy, get plain tessdata. This ran as printed, exit 0:
mkdir ~/tessdata-legacy
curl -fsSL -o ~/tessdata-legacy/eng.traineddata \
https://raw.githubusercontent.com/tesseract-ocr/tessdata/4.1.0/eng.traineddata
tesseract page.jpg stdout --tessdata-dir ~/tessdata-legacy --oem 0
What else people type
| You typed | Result |
|---|---|
--oem=1, -oem 1 |
Exit 1, unknown argument |
--oem 4 |
Exit 1, Invalid OEM value |
--oem lstm_only |
Works, same text as --oem 1 |
-c tessedit_ocr_engine_mode=1 |
Works, same text as --oem 1 |
--psm 0 --oem 1 |
Prints an LSTM error, still exit 0, same answer |
From Python: put it in config
import os
import pytesseract
print(len(pytesseract.image_to_string("page.jpg", config="--oem 1").split()))
legacy = os.path.expanduser("~/tessdata-legacy")
text = pytesseract.image_to_string("page.jpg", config=f"--tessdata-dir {legacy} --oem 0")
print(len(text.split()))
It printed 212 and 214 words for one page. With an LSTM-only file,
--oem 0 raises
TesseractError with the same message.
Our Actor stays on LSTM
PDF OCR to Markdown, our Apify Actor, has no engine setting. It runs Tesseract with tessdata_fast, reads tables cell by cell, checks the math, and sends unsure numbers the math does not back to tessdata_best.
| Same pages | Read right |
|---|---|
| Book scans, of 15,622 words | 14,532 |
| Invoices, of 2,454 numbers | 2,451 |
- If Tesseract reads an English page badly, RapidOCR reads it too.
- The invoice score is not blind: its table code was tuned on some of these pages, and its scorer reads Markdown cells.
- Real receipt photos stay weak, at 67% of words, and handwritten notes at 52%.
- $0.006 a page, plus $0.00005 a run at the default 1 GB. Files go to no LLM or other API.
Questions people ask
Can I set --oem and --psm together?
Yes. With --psm 4, LSTM on tessdata_best read 2,226 invoice numbers and legacy read 2,414, so layout did not close the gap.
Can I whitelist characters without legacy?
Yes. On one invoice, --oem 1 with tessedit_char_whitelist put out no character outside the list. I did not score its accuracy.
Method, limits and sources
How I tested it
Every mode ran on all 3 English model files on the book scans, and every mode that starts ran on the invoices. The runs that repeat /tessdata-best-vs-fast/ gave the same scores.
- Book scans: 60 pages from 12 Wikisource books, each checked by two people. A seeded draw picked the books.
- Invoices: 73 made-up pages, each scored by the exact text on the right row.
- Receipts: 100 CORD v2 phone photos, without --oem 3. Their truth holds only item and total lines.
- Digit words: true words with a digit, found anywhere on the page.
- Raw phone photos of full pages: every mode found under 4% of the words, legacy the most. That set decides nothing.
CPU is the median of 3 rounds with 8 workers, on a Mac running other jobs, so treat it as rough. Memory is one run on one page.
The Actor ran locally from its build code, not as a paid Apify run. Scripts and results are in research/bench/tesseract-oem-2026-11-05/.
CPU and memory by mode
| Mode, file | CPU seconds | Peak memory |
|---|---|---|
| 1, fast | 70.4 | 110 MB |
| 0, tessdata | 87.0 | 172 MB |
| 1, tessdata | 103.3 | 174 MB |
| 2, tessdata | 106.7 | 178 MB |
| 1, best | 137.5 | 160 MB |
What I did not test
- Why legacy does better on those invoices.
- Real invoice scans: I have none with checked text.
- Other languages and custom models.
- Book pages with tables: the draw left them out.
- Other psm values: my invoice scorer needs rows, so only --psm 3 and 4 count.
- Windows, and Linux in this run.
Versions and sources
- Tesseract 5.5.3 on one Mac, models at tag 4.1.0, pytesseract 0.3.13.
- Tesseract data files documentation
- Page scans and text: Wikisource.
- Receipts: CORD v2, CC BY 4.0.
- We make the Apify Actor. The other tools are open source, and we do not make them.
Two ways to skip the work
Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.
Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.