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.

1
Choose engine

Which engine should you pick?

Your situationPickWhy
Default / unsureRapidOCRPip-only install, CPU-friendly, multilingual, GPU-capable. The safest first choice.
100+ languages or custom traineddataTesseract (CLI or tesserocr)Mature engine, script models (script/Latin), vertical Japanese (jpn_vert), your own trained files.
On a Mac, zero setupOcrMacUses Apple Vision on-device; no binaries, no models to download.
Simple CJK + Latin, easy installEasyOCRpip-only with self-downloaded gen2 models; takes several languages at once.
NVIDIA server farm, max throughputNemotron OCRGPU-accelerated; English + multilingual models (Linux x86_64, CUDA 13.x).
OCR lives on another serviceKServe v2Docling calls your remote endpoint; language codes are your deployment’s own.
Need a niche modelPlugin (OnnxTR, SuryaOCR)Install via the plugin system with --allow-external-plugins.
Digital (born-text) PDFs often need no OCR at all — try --no-ocr first for maximum speed, and only add an engine for scanned pages.
2
Pipeline

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:

FlagValues / defaultMeaning
--ocr / --no-ocrdefault onMaster switch. --no-ocr skips OCR entirely — fastest for digital PDFs.
--ocr-modedefault, full_page, layout_regions, pdf_aware_layout_regionsWhich regions go to the engine. full_page OCRs every page end-to-end (slower, best for scans).
--ocr-engineauto (default), rapidocr, easyocr, tesseract, tesserocr, ocrmac, nemotron-ocr, kserve_v2_ocrWhich engine. auto picks from what is installed on your platform.
--ocr-langcomma-separated, e.g. ch, deu, iso:deLanguages, native or portable (see section 11). Empty (--ocr-lang "") lets the engine decide.
--psm0–13Page 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.

3
Compare

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 →
4
Install

Install each engine

EngineInstallSystem dependency?
RapidOCRpip install "docling[rapidocr]" (or pip install rapidocr onnxruntime)No — pip-only.
EasyOCRpip install "docling[easyocr]" (or pip install easyocr)No — downloads its own models on first use.
Tesseract CLISystem binary only (below); no pip extra neededYes — binary + TESSDATA_PREFIX (trailing /).
Tesseract (tesserocr)System binary first, then pip install "docling[tesserocr]"Yes — plus a compiler on Windows for the binding.
OcrMacpip install "docling[ocrmac]"macOS only; no models — Vision ships with the OS.
Nemotronpip install "docling[feat-ocr-nemotron]" --extra-index-url https://download.pytorch.org/whl/cu130 --index-strategy unsafe-best-matchLinux x86_64 + Python 3.12 + CUDA 13.x.
OnnxTR (plugin)pip install "docling-ocr-onnxtr[cpu]" + --allow-external-pluginsNo — plugin system.

Tesseract system binary per OS

brew install tesseract leptonica pkg-config
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng libtesseract-dev libleptonica-dev pkg-config
sudo dnf install -y tesseract tesseract-devel tesseract-langpack-eng tesseract-osd leptonica-devel

Windows: 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.

5
RapidOCR

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

BackendPP-OCR versionsNotes
onnxruntime (default)v4, v5, v6Fullest coverage — the only backend serving PP-OCRv5 eslav/cyrillic.
openvinov4, v5, v6Intel hardware path.
paddlev4, v5, v6PaddlePaddle runtime.
torchv4, v5 (Chinese only), v6PP-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 aliases zh→ch, zh_cn→ch, zh_tw→chinese_cht, ja/jp→japan, ko→korean (note: Korean has only the alias in v6). de/german and fr/french both 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_page
6
EasyOCR

EasyOCR 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.

!Adding a language you don’t need silently downgrades the model: ["en"] selects the accurate english_g2.pth, while ["en","de"] falls back to the broader latin_g2.pth.
CheckpointCovers
english_g2.pthen
latin_g2.pthEuropean/Latin family (de, fr, es, it, pt, nl, pl …)
zh_sim_g2.pthch_sim + en
japanese_g2.pth / korean_g2.pthja / ko + en
telugu.pth / kannada.pthte / kn + en
cyrillic_g2.pthru, be, bg, uk, mn … + en
docling convert scan.pdf --ocr-engine easyocr --ocr-lang en
7
Tesseract

Tesseract deep dive (CLI vs tesserocr, traineddata)

  • Two flavors, one engine: tesseract shells out to the system CLI (no pip extra); tesserocr binds 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 .traineddata files 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 the osd traineddata file.
  • Auto language detection is demonstrated in the official example.
docling convert scan.pdf --ocr-engine tesseract --ocr-lang deu+eng
TESSDATA_PREFIX=/opt/homebrew/share/tessdata/ docling convert scan.pdf --ocr-engine tesserocr
8
OcrMac

OcrMac 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:de finds de-DE, iso:pt finds pt-BR, iso:zh-CN finds zh-Hans.
  • Odd region codes like vi-VT must be passed bare (native). Empty lang lets Vision choose automatically.
docling convert scan.pdf --ocr-engine ocrmac --ocr-mode full_page
9
Nemotron

Nemotron OCR deep dive (Linux + CUDA)

Nemotron versionPythonLanguages
v2.0.03.12 onlyenglish (alias en), multilingual (alias multi: en, zh sim+trad, ja, ko, ru) + ~170 Latin-script best-effort codes (warn, untested by NVIDIA)
v2.0.23.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.

10
Remote & plugins

KServe v2 + plugin engines (OnnxTR, SuryaOCR)

  • KServe v2: for teams whose OCR runs as a remote microservice. lang is 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.
11
Languages

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 be iso: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

TagMeansSay this instead
mulmultiple languagesThe engine’s multilingual code (e.g. Nemotron multilingual)
undundeterminedEmpty list, or a language in the script you want
zxxno linguistic contentTurn OCR off: --no-ocr / do_ocr=False

What an empty language list means per engine

Enginelang=[] (--ocr-lang "")
Tesseract (both)Per-page orientation + script detection (needs the osd file)
EasyOCREnglish (en)
RapidOCRSimplified-Chinese default (ch)
NemotronEnglish model
OcrMacVision’s automatic behavior
KServeSends 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:

CodeBare reachesiso: means
chPP-OCR Chinese Simplifiedch-Latn = Chamorro
kaPP-OCR Kannadaka-Geor = Georgian (PP-OCR can’t serve it — error)
angEasyOCR AngikaOld English
frkTesseract German FrakturFrankish
tabEasyOCR Tabasaran (Cyrillic)Tabasaran (Latin)
mahEasyOCR MagahiMarshallese

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).

12
GPU

GPU acceleration for OCR

  • RapidOCR on CUDA: install the GPU ONNX Runtime — pip install "docling[onnxruntime]" — confirm CUDAExecutionProvider is in ort.get_available_providers(), then use the onnxruntime backend with a CUDA device. The torch backend 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.
13
Recipes

Copy-paste recipes (CLI + Python)

Scanned PDF, full-page OCR

docling convert scan.pdf --ocr-mode full_page

Pick an engine explicitly

docling convert scan.pdf --ocr-engine rapidocr

Skip OCR for digital PDFs (fastest)

docling convert report.pdf --no-ocr --to md

OCR in German + English, portable tags

docling convert scan.pdf --ocr-engine rapidocr --ocr-lang iso:de,iso:en

Python: 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.

14
Fix

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_PREFIX first. See OCR package installation error.
  • Conversion is slow — OCR + enrichment models are the costliest CPU stages: --no-ocr for digital PDFs, --table-mode fast, or a GPU. See conversion is slow.
  • GPU ignored — confirm torch.cuda.is_available() / CUDAExecutionProvider, use --device cuda (mps on Apple Silicon). See GPU not used.
  • Wrong language output — check shadowing (ka vs iso:ka-Geor), keep EasyOCR lists short, and verify with supported_ocr_languages().
15
FAQ

OCR FAQ

Which engine is best for beginners?
RapidOCR: one pip extra, no system packages, CPU-friendly, multilingual, and GPU-capable later. Start with pip install "docling[rapidocr]" and --ocr-engine rapidocr.
Do I even need OCR?
Only for scanned/image PDFs. Digital PDFs already carry text — --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?
Native (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?
By design: EasyOCR selects one checkpoint covering every requested language, so ["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?
No — one language per run (first entry wins). Use a script-family token (latin, cyrillic, arabic, devanagari, eslav) to cover a family, or run per-language passes.
Tesseract can’t find my language?
Install the matching traineddata (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?
RapidOCR (onnxruntime/torch backends with CUDA) and Nemotron (CUDA-only). EasyOCR, Tesseract and OcrMac are CPU-bound in practice.
How do I use a custom OCR model?
RapidOCR and SuryaOCR both support custom checkpoints — follow the RapidOCR custom-models example and the SuryaOCR example; third-party engines load via --allow-external-plugins.

Verified with Docling v2.129.0 · Last checked 2026-09-22 · Official source