Docling OCR Engines
There is no single “best” OCR engine — the right choice depends on your platform, languages and appetite for setup. This page compares every engine, shows install + CLI + Python for each, explains the portable iso: language system, covers GPU backends, and gives copy-paste recipes. Engine facts are checked against the official OCR concepts and native engine reference.
Which engine should you pick?
| Your situation | Pick | Why |
|---|---|---|
| Default / unsure | RapidOCR | Pip-only install, CPU-friendly, multilingual, GPU-capable. The safest first choice. |
| 100+ languages or custom traineddata | Tesseract (CLI or tesserocr) | Mature engine, script models (script/Latin), vertical Japanese (jpn_vert), your own trained files. |
| On a Mac, zero setup | OcrMac | Uses Apple Vision on-device; no binaries, no models to download. |
| Simple CJK + Latin, easy install | EasyOCR | pip-only with self-downloaded gen2 models; takes several languages at once. |
| NVIDIA server farm, max throughput | Nemotron OCR | GPU-accelerated; English + multilingual models (Linux x86_64, CUDA 13.x). |
| OCR lives on another service | KServe v2 | Docling calls your remote endpoint; language codes are your deployment’s own. |
| Need a niche model | Plugin (OnnxTR, SuryaOCR) | Install via the plugin system with --allow-external-plugins. |
--no-ocr first for maximum speed, and only add an engine for scanned pages.How OCR fits in the pipeline (modes & flags)
OCR is on by default (--ocr). Three flags control where it runs and which engine runs it:
| Flag | Values / default | Meaning |
|---|---|---|
--ocr / --no-ocr | default on | Master switch. --no-ocr skips OCR entirely — fastest for digital PDFs. |
--ocr-mode | default, full_page, layout_regions, pdf_aware_layout_regions | Which regions go to the engine. full_page OCRs every page end-to-end (slower, best for scans). |
--ocr-engine | auto (default), rapidocr, easyocr, tesseract, tesserocr, ocrmac, nemotron-ocr, kserve_v2_ocr | Which engine. auto picks from what is installed on your platform. |
--ocr-lang | comma-separated, e.g. ch, deu, iso:de | Languages, native or portable (see section 11). Empty (--ocr-lang "") lets the engine decide. |
--psm | 0–13 | Page Segmentation Mode for the OCR engine. |
--force-ocr is deprecated — use --ocr-mode full_page.Python equivalent: PdfPipelineOptions().do_ocr = True plus one of RapidOcrOptions / EasyOcrOptions / TesseractOcrOptions / TesseractCliOcrOptions / OcrMacOptions / NemotronOcrOptions with mode=OcrMode.FULL_PAGE when you want full-page behavior. Debug what OCR sees with --debug-visualize-ocr.
Engine comparison table
| Engine | Best for | Platform | Notes | Docs |
|---|---|---|---|---|
| auto (default) | Let Docling pick an available engine. | All | Default --ocr-engine. Docling chooses based on what is installed and the platform. Python: leave ocr_options unset. | Docs → |
| RapidOCR | Lightweight, CPU-friendly multilingual OCR; good default. | Cross-platform | ONNX Runtime default backend (also openvino/paddle/torch). pip install "docling[rapidocr]". Single language per run; PP-OCR v4/v5/v6 tokens, incl. script families latin/cyrillic/arabic/devanagari. Python: RapidOcrOptions. | Docs → |
| Tesseract (CLI) | Mature OCR with 100+ languages; custom traineddata. | Cross-platform (system binary) | Needs system Tesseract + TESSDATA_PREFIX (trailing /). No pip extra for CLI use. Python: TesseractCliOcrOptions. Empty lang triggers OSD script detection (needs osd file). | Docs → |
| Tesseract (tesserocr) | Same Tesseract accuracy, faster via Python bindings. | Cross-platform (compiled) | pip install "docling[tesserocr]" after the system binary. May need C++ build tools on Windows. Python: TesseractOcrOptions. | Docs → |
| EasyOCR | Easy multilingual setup; CJK + Latin scripts. | Cross-platform | pip install "docling[easyocr]". Downloads its own gen2 models. Takes several languages at once — keep the list short (en alone beats en+de). Python: EasyOcrOptions. | Docs → |
| OcrMac | Zero-setup native OCR on Macs (Apple Vision). | macOS only | pip install "docling[ocrmac]". No models shipped — language set comes from the macOS version. Python: OcrMacOptions. | Docs → |
| Nemotron OCR | GPU-accelerated OCR at scale on NVIDIA servers. | Linux x86_64 + CUDA 13.x | pip install "docling[feat-ocr-nemotron]" with the cu130 index (Python 3.12; v2.0.2 adds 3.11/3.13). english or multilingual (+~170 Latin best-effort). Python: NemotronOcrOptions. | Docs → |
| KServe v2 OCR | Calling a remote OCR microservice. | Service | Connects to a KServe v2 endpoint. lang is sent verbatim (first entry only) — use the codes your deployment expects. No validation or mapping. | Docs → |
No engines match your search.
Install each engine
| Engine | Install | System dependency? |
|---|---|---|
| RapidOCR | pip install "docling[rapidocr]" (or pip install rapidocr onnxruntime) | No — pip-only. |
| EasyOCR | pip install "docling[easyocr]" (or pip install easyocr) | No — downloads its own models on first use. |
| Tesseract CLI | System binary only (below); no pip extra needed | Yes — binary + TESSDATA_PREFIX (trailing /). |
| Tesseract (tesserocr) | System binary first, then pip install "docling[tesserocr]" | Yes — plus a compiler on Windows for the binding. |
| OcrMac | pip install "docling[ocrmac]" | macOS only; no models — Vision ships with the OS. |
| Nemotron | pip install "docling[feat-ocr-nemotron]" --extra-index-url https://download.pytorch.org/whl/cu130 --index-strategy unsafe-best-match | Linux x86_64 + Python 3.12 + CUDA 13.x. |
| OnnxTR (plugin) | pip install "docling-ocr-onnxtr[cpu]" + --allow-external-plugins | No — plugin system. |
Tesseract system binary per OS
brew install tesseract leptonica pkg-configsudo apt-get install -y tesseract-ocr tesseract-ocr-eng libtesseract-dev libleptonica-dev pkg-configsudo dnf install -y tesseract tesseract-devel tesseract-langpack-eng tesseract-osd leptonica-develWindows: install the UB Mannheim build, add it to PATH, and set TESSDATA_PREFIX to its tessdata\ folder. If tesserocr fails to compile: pip uninstall tesserocr, then pip install --no-binary :all: tesserocr. Full per-OS steps live in the install hub and OS guides.
Pre-download OCR models for offline or CI machines: docling-tools models download --all, or targeted --easyocr-lang de / --rapidocr-backend-lang onnxruntime:el. See the CLI reference.
RapidOCR deep dive (backends, PP-OCR versions, languages)
RapidOCR wraps PP-OCR models. Two things vary independently: the backend (runtime) and the PP-OCR version (model generation).
Backends
| Backend | PP-OCR versions | Notes |
|---|---|---|
onnxruntime (default) | v4, v5, v6 | Fullest coverage — the only backend serving PP-OCRv5 eslav/cyrillic. |
openvino | v4, v5, v6 | Intel hardware path. |
paddle | v4, v5, v6 | PaddlePaddle runtime. |
torch | v4, v5 (Chinese only), v6 | PP-OCRv5 on torch supports Chinese only. |
Language tokens (native codes)
- v4:
arabic, ch, chinese_cht, cyrillic, devanagari, en, japan, ka, korean, latin, ta, te. - v5:
arabic, ch, cyrillic, devanagari, el, en, eslav, korean, latin, ta, te, th. - v6:
ch, chinese_cht, en, japan+ ~45 European codes (de, fr, es, it, pt, nl, pl …) with aliaseszh→ch, zh_cn→ch, zh_tw→chinese_cht, ja/jp→japan, ko→korean(note: Korean has only the alias in v6).de/germanandfr/frenchboth exist. - Script families (one token covers many languages):
cyrillic(34: Russian, Ukrainian, Kazakh … + English),devanagari(14: Hindi, Marathi, Sanskrit … + English),arabic(9: Arabic, Persian, Urdu … + English),eslav(East Slavic: Russian, Belarusian, Ukrainian + English).
Single language per run: RapidOCR uses the first lang entry and warns about the rest. Python: RapidOcrOptions(lang=["eslav"], backend="onnxruntime"); custom checkpoints are supported (see the custom-models example).
docling convert scan.pdf --ocr-engine rapidocr --ocr-mode full_pageEasyOCR deep dive (keep your language list short)
EasyOCR (gen2 checkpoints, craft_mlt_25k.pth detector) accepts several languages at once — but resolution picks the single checkpoint covering all requested languages.
["en"] selects the accurate english_g2.pth, while ["en","de"] falls back to the broader latin_g2.pth.| Checkpoint | Covers |
|---|---|
english_g2.pth | en |
latin_g2.pth | European/Latin family (de, fr, es, it, pt, nl, pl …) |
zh_sim_g2.pth | ch_sim + en |
japanese_g2.pth / korean_g2.pth | ja / ko + en |
telugu.pth / kannada.pth | te / kn + en |
cyrillic_g2.pth | ru, be, bg, uk, mn … + en |
docling convert scan.pdf --ocr-engine easyocr --ocr-lang enTesseract deep dive (CLI vs tesserocr, traineddata)
- Two flavors, one engine:
tesseractshells out to the system CLI (no pip extra);tesserocrbinds the library in-process (faster, needs the compiled binding). Same accuracy, same traineddata. - Language = traineddata stem:
deu, chi_sim, chi_tra, srp_latn, aze_cyrl, deu_latf, frk, jpn_vert, script/Latin, script/Cyrillic— plus any file you trained yourself. Whatever.traineddatafiles are installed is what you can use. - Checked at construction time: missing files fail immediately with the installed set in the error message — not mid-conversion.
- Empty
lang= script detection:--ocr-lang ""runs per-page orientation/script detection, which requires theosdtraineddata file. - Auto language detection is demonstrated in the official example.
docling convert scan.pdf --ocr-engine tesseract --ocr-lang deu+engTESSDATA_PREFIX=/opt/homebrew/share/tessdata/ docling convert scan.pdf --ocr-engine tesserocrOcrMac deep dive (macOS only)
OcrMac is a thin wrapper over Apple’s Vision framework: no binaries, no downloadable models — the recognizers ship with the OS, so the supported language set is a property of your macOS version, not the ocrmac release.
- Install:
pip install "docling[ocrmac]"; Python:OcrMacOptions. - Matching is by BCP-47 with regions:
iso:defindsde-DE,iso:ptfindspt-BR,iso:zh-CNfindszh-Hans. - Odd region codes like
vi-VTmust be passed bare (native). Emptylanglets Vision choose automatically.
docling convert scan.pdf --ocr-engine ocrmac --ocr-mode full_pageNemotron OCR deep dive (Linux + CUDA)
| Nemotron version | Python | Languages |
|---|---|---|
| v2.0.0 | 3.12 only | english (alias en), multilingual (alias multi: en, zh sim+trad, ja, ko, ru) + ~170 Latin-script best-effort codes (warn, untested by NVIDIA) |
| v2.0.2 | 3.11, 3.12, 3.13 |
Requires Linux x86_64 with CUDA 13.x and the cu130 torch index (install line in section 4). Single language per run (first entry wins). Python: NemotronOcrOptions.
KServe v2 + plugin engines (OnnxTR, SuryaOCR)
- KServe v2: for teams whose OCR runs as a remote microservice.
langis neither validated nor mapped — the first entry is sent verbatim, the rest dropped with a warning. Use whatever codes your deployment expects;iso:only works if the server speaks it (none do). - OnnxTR plugin:
pip install "docling-ocr-onnxtr[cpu]", enable--allow-external-plugins, select with the plugin’s engine name. See the docling-OCR-OnnxTR repo. - SuryaOCR with custom models is demonstrated in the official example; list third-party options with
--show-external-plugins.
Languages: native codes vs portable iso: tags
Every engine takes languages through one field, OcrOptions.lang. Each entry has exactly two forms:
- Native code (no prefix) — the engine’s own spelling, passed through verbatim:
ch(PP-OCR Chinese),deu(Tesseract German),ch_sim(EasyOCR),en-US(Vision). - Portable tag — BCP-47 behind
iso:, mapped onto the engine:iso:de,iso:en-US,iso:zh-Hant. Always include the script when it is non-default: Serbian Latin must beiso:sr-Latn(default Serbian is Cyrillic).
from docling.datamodel.pipeline_options import TesseractCliOcrOptions
TesseractCliOcrOptions(lang=["deu", "eng"]) # native: tesseract -l deu+eng
TesseractCliOcrOptions(lang=["iso:de", "iso:en"]) # portable: same thing
Tags Docling refuses
| Tag | Means | Say this instead |
|---|---|---|
mul | multiple languages | The engine’s multilingual code (e.g. Nemotron multilingual) |
und | undetermined | Empty list, or a language in the script you want |
zxx | no linguistic content | Turn OCR off: --no-ocr / do_ocr=False |
What an empty language list means per engine
| Engine | lang=[] (--ocr-lang "") |
|---|---|
| Tesseract (both) | Per-page orientation + script detection (needs the osd file) |
| EasyOCR | English (en) |
| RapidOCR | Simplified-Chinese default (ch) |
| Nemotron | English model |
| OcrMac | Vision’s automatic behavior |
| KServe | Sends en |
Codes that shadow a language tag (write carefully)
A few bare codes mean something different from the same BCP-47 subtag. Bare = the model; iso: = the language:
| Code | Bare reaches | iso: means |
|---|---|---|
ch | PP-OCR Chinese Simplified | ch-Latn = Chamorro |
ka | PP-OCR Kannada | ka-Geor = Georgian (PP-OCR can’t serve it — error) |
ang | EasyOCR Angika | Old English |
frk | Tesseract German Fraktur | Frankish |
tab | EasyOCR Tabasaran (Cyrillic) | Tabasaran (Latin) |
mah | EasyOCR Magahi | Marshallese |
Ask any engine what it serves: supported_ocr_languages() returns native + BCP-47 codes in a spelling you can paste back into lang. Docling never silently substitutes — an unservable language raises, naming what the engine can serve. RapidOCR and Nemotron run one language at a time (first tag wins, rest warn).
GPU acceleration for OCR
- RapidOCR on CUDA: install the GPU ONNX Runtime —
pip install "docling[onnxruntime]"— confirmCUDAExecutionProvideris inort.get_available_providers(), then use theonnxruntimebackend with a CUDA device. Thetorchbackend is the alternative (remember: PP-OCRv5 + torch = Chinese only).
import onnxruntime as ort
assert "CUDAExecutionProvider" in ort.get_available_providers()
from docling.datamodel.accelerator_options import AcceleratorDevice, AcceleratorOptions
from docling.datamodel.pipeline_options import PdfPipelineOptions, RapidOcrOptions
pipeline_options = PdfPipelineOptions(
accelerator_options=AcceleratorOptions(device=AcceleratorDevice.CUDA),
ocr_options=RapidOcrOptions(backend="onnxruntime", lang=["eslav"]),
)
- Nemotron is GPU-only by design (CUDA 13.x, Linux x86_64).
- EasyOCR / Tesseract / OcrMac are effectively CPU-bound — put them on a fast CPU and spend GPU budget on layout/table stages instead. Full tuning (batch sizes, VLM servers) is in the official GPU guide.
Copy-paste recipes (CLI + Python)
Scanned PDF, full-page OCR
docling convert scan.pdf --ocr-mode full_pagePick an engine explicitly
docling convert scan.pdf --ocr-engine rapidocrSkip OCR for digital PDFs (fastest)
docling convert report.pdf --no-ocr --to mdOCR in German + English, portable tags
docling convert scan.pdf --ocr-engine rapidocr --ocr-lang iso:de,iso:enPython: full-page OCR with backend choice
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
OcrMode, PdfPipelineOptions, RapidOcrOptions,
)
from docling.document_converter import DocumentConverter, PdfFormatOption
pipeline_options = PdfPipelineOptions()
pipeline_options.do_ocr = True
pipeline_options.ocr_options = RapidOcrOptions(mode=OcrMode.FULL_PAGE)
# Swap in EasyOcrOptions / TesseractOcrOptions / TesseractCliOcrOptions
# / OcrMacOptions (macOS) / NemotronOcrOptions (Linux CUDA) as needed.
converter = DocumentConverter(
format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)}
)
doc = converter.convert("scan.pdf").document
print(doc.export_to_markdown())
More worked examples: force full-page OCR, Tesseract language detection, RapidOCR custom models, local examples library, and the config generator.
Troubleshooting OCR
- Scanned text not recognized — OCR is off or the default mode missed the missing text layer: force
--ocr-mode full_page, try another engine. See OCR a scanned PDF. - OCR extra won’t install — RapidOCR/EasyOCR are pip-only; Tesseract needs the system binary +
TESSDATA_PREFIXfirst. See OCR package installation error. - Conversion is slow — OCR + enrichment models are the costliest CPU stages:
--no-ocrfor digital PDFs,--table-mode fast, or a GPU. See conversion is slow. - GPU ignored — confirm
torch.cuda.is_available()/CUDAExecutionProvider, use--device cuda(mpson Apple Silicon). See GPU not used. - Wrong language output — check shadowing (
kavsiso:ka-Geor), keep EasyOCR lists short, and verify withsupported_ocr_languages().
OCR FAQ
Which engine is best for beginners?
pip install "docling[rapidocr]" and --ocr-engine rapidocr.Do I even need OCR?
--no-ocr is faster and often more accurate. If output is empty on a scan, that is the sign you need --ocr-mode full_page.Native code or iso: tag?
ch, deu) is shortest when you know the engine. Portable (iso:de, iso:zh-Hant) survives engine swaps and is required for scripts like iso:sr-Latn. Never mix up shadowing codes like bare ka (Kannada model) vs iso:ka-Geor (Georgian).Why is EasyOCR worse when I add a language?
["en","de"] drops from the English-specific model to the general Latin one. Request only what the document contains.Can RapidOCR do several languages at once?
latin, cyrillic, arabic, devanagari, eslav) to cover a family, or run per-language passes.Tesseract can’t find my language?
tesseract-ocr-<lang>), confirm it is listed by tesseract --list-langs, and export TESSDATA_PREFIX with a trailing slash. The constructor error message lists exactly what is installed.Which engines use the GPU?
How do I use a custom OCR model?
--allow-external-plugins.Verified with Docling v2.129.0 · Last checked 2026-09-22 · Official source