Install: PaddlePaddle first, then pip install "paddleocr[all]". For NVIDIA GPUs use the PaddlePaddle CUDA index, not PyPI.
Use:PaddleOCR for text lines, PPStructureV3 for Markdown/JSON, PaddleOCRVL for the most accurate document parsing on GPU.
2.x code broke?use_gpu became device, ocr() became predict(). See migration.
Overview: what PaddleOCR is and which pipeline to use
PaddleOCR is an open-source OCR and document-parsing toolkit from Baidu's PaddlePaddle team, released under the Apache License 2.0. This page is a practical guide to the current 3.7 API. Every code sample on it was written against the 3.x API, and the install, API and CLI facts were checked against the official docs and the released packages on the date shown below.
Independent site. paddleocr.dev is not run by Baidu or the PaddleOCR maintainers. For authoritative references use the GitHub repository and the official documentation. Last reviewed: October 2026 against PaddleOCR 3.7.0. See our editorial policy.
Installation
PaddleOCR needs an inference engine (PaddlePaddle) plus the paddleocr package. Install the engine first, then PaddleOCR. Use a virtual environment.
Requirements
Python 3.9–3.13 in practice. The paddleocr package declares >=3.8, but PaddlePaddle 3.x wheels target 3.9–3.13, and document parsing needs 3.9+.
OS: Linux, Windows or macOS (Apple Silicon runs on CPU).
NVIDIA GPU (optional): a driver that supports the CUDA build you install (CUDA 12.6 below; a CUDA 11.8 build is also published).
Do not run pip install paddlepaddle-gpu from PyPI. The newest GPU build on PyPI is 2.6.2, which PaddleOCR 3.x does not support. Always use the -i index above. Pick the matching CUDA index (for example cu118) from the official PaddlePaddle install selector.
Extras
Install
Gives you
paddleocr
Basic text recognition (the PaddleOCR class)
"paddleocr[doc-parser]"
Document parsing: PP-StructureV3, PaddleOCR-VL
"paddleocr[ie]"
Information extraction (PP-ChatOCRv4, PP-DocTranslation)
"paddleocr[trans]"
Document translation
"paddleocr[all]"
All of the above
Verify
verify.py
import paddle
paddle.utils.run_check()
from paddleocr import PaddleOCR
print("PaddleOCR import OK")
The first real run downloads model weights (from Hugging Face by default), so it needs network access once. To use pre-downloaded models, pass text_detection_model_dir and text_recognition_model_dir.
Quick start: first OCR in five lines
PaddleOCR 3.x returns result objects. Call predict() and read fields such as rec_texts, rec_scores and rec_boxes.
first_ocr.py
from paddleocr import PaddleOCR
ocr = PaddleOCR(lang="en") # default model for "en" is PP-OCRv6 (medium)
result = ocr.predict("invoice.jpg") # a path, URL, numpy array or PDF
for res in result:
for text, score, box in zip(res["rec_texts"], res["rec_scores"], res["rec_boxes"]):
if score >= 0.8:
print(f"{score:.2f} {box.tolist()} {text}")
res.save_to_img("output") # annotated image
res.save_to_json("output") # structured result
Command line
Terminal
paddleocr ocr -i invoice.jpg --lang en --save_path ./output
Result fields
Field
Meaning
rec_texts
Recognized text, one string per detected line
rec_scores
Confidence per line, 0.0–1.0
rec_boxes
Axis-aligned box per line: [x1, y1, x2, y2]
rec_polys / dt_polys
Four-point polygons (follow rotated or skewed text)
doc_preprocessor_res
Orientation / unwarping info when those modules are on
Want to try options visually? Use the code generator on the homepage, which outputs a runnable snippet and CLI command for your setup.
Migrating from PaddleOCR 2.x
PaddleOCR 3.x is not backward compatible. Most old tutorials (and old AI-generated answers) still show the 2.x API. These are the changes that break code:
2.x
3.x
PaddleOCR(use_gpu=True)
PaddleOCR(device="gpu") (or "gpu:0"). use_gpu now raises ValueError: Unknown argument: use_gpu.
ocr.ocr(img, cls=True)
ocr.predict(img). Orientation handling is configured when you create the object.
use_angle_cls=True
use_textline_orientation=True
show_log=...
Removed; control logging with the standard logging module.
text_det_thresh, text_det_box_thresh, text_det_unclip_ratio (old names are deprecated and cannot be mixed with the new ones)
rec_batch_num
text_recognition_batch_size
PPStructure
PPStructureV3
Nested lists: [[box, (text, score)], ...]
Result objects with print(), save_to_json(), save_to_img(), and dict-style fields
migrate.py
# 2.x
# ocr = PaddleOCR(use_angle_cls=True, lang="en", use_gpu=True)
# result = ocr.ocr("img.jpg", cls=True)
# 3.x
from paddleocr import PaddleOCR
ocr = PaddleOCR(lang="en", device="gpu", use_textline_orientation=True)
result = ocr.predict("img.jpg")
for res in result:
print(res["rec_texts"])
PP-OCRv6: text detection and recognition
PP-OCRv6 shipped with PaddleOCR 3.7.0 (June 11, 2026) and is the default model for the PaddleOCR class. Figures below are Baidu's own reporting; we have not independently benchmarked them.
Tier
Parameters
Model names (examples)
Use for
Tiny
1.5M
PP-OCRv6_tiny_det, PP-OCRv6_tiny_rec
Edge devices, browsers, very low latency
Small
7.7M
PP-OCRv6_small_det, PP-OCRv6_small_rec
Mobile and CPU services
Medium
34.5M
PP-OCRv6_medium (default for lang="en")
Best accuracy on server hardware
Languages: one recognition model covers 50 languages: Chinese, English, Japanese and 46 Latin-script languages. Other scripts (Korean, Arabic, Russian, Thai, Greek and more) use PP-OCRv5 multilingual models; lang="korean" loads korean_PP-OCRv5_mobile_rec.
Reported gains: the medium tier improves detection by 4.6% and recognition by 5.1% over PP-OCRv5_server; Baidu reports a 5.2× end-to-end CPU speedup with OpenVINO (6.1× on Apple M4 for tiny).
Choose a tier
tiers.py
from paddleocr import PaddleOCR
# Default (medium)
ocr = PaddleOCR(lang="en")
# Small / tiny: pass both model names
ocr_small = PaddleOCR(
text_detection_model_name="PP-OCRv6_small_det",
text_recognition_model_name="PP-OCRv6_small_rec",
)
# Stay on the previous generation
ocr_v5 = PaddleOCR(lang="en", ocr_version="PP-OCRv5")
PP-OCRv5 vs PP-OCRv6
ocr_version accepts "PP-OCRv6", "PP-OCRv5", "PP-OCRv4" and "PP-OCRv3", but not every language exists in every version. If a lang is missing for the version you request, choose another version or pass explicit model names. Pin ocr_version if you need reproducible output across upgrades.
Fix whole-page rotation (0/90/180/270°). Turn off for clean, upright inputs to save time.
use_doc_unwarpingboolTrue
Flatten curved or photographed pages. Turn off for scans and screenshots.
use_textline_orientationboolTrue
Correct upside-down individual lines.
text_det_threshfloat0.3
Pixel threshold on the detection probability map. Lower finds more faint text, with more noise.
text_det_box_threshfloat0.6
Average score a region needs to be kept as a text box.
text_det_unclip_ratiofloat2.0
How much detected regions are expanded. Larger values give looser boxes.
text_rec_score_threshfloat0.0
Drop recognized lines below this confidence.
return_word_boxboolFalse
Also return word-level boxes.
text_recognition_batch_sizeint1
Lines recognized per batch. Raise on GPU.
Defaults are from the official OCR pipeline reference; check the pipeline page for your installed version because defaults and tier names evolve.
PP-StructureV3: documents to Markdown and JSON
PP-StructureV3 combines layout detection, OCR, table recognition, formula recognition, seal recognition and reading-order recovery. It is the right choice when you want a PDF or page image turned into Markdown or JSON rather than a flat list of text lines. It runs on CPU, but is much faster on GPU.
structure.py
from paddleocr import PPStructureV3
pipeline = PPStructureV3(lang="en") # add device="gpu" if available
output = pipeline.predict("report.pdf")
for res in output:
res.print()
res.save_to_json(save_path="output")
res.save_to_markdown(save_path="output")
Terminal
paddleocr pp_structurev3 -i report.pdf --device cpu --save_path ./output
Install the extra first: python -m pip install "paddleocr[doc-parser]". Useful switches on the constructor and the CLI: use_doc_orientation_classify, use_doc_unwarping, use_textline_orientation, and per-module toggles for tables, formulas, seals and charts. Disable what you do not need for speed.
Practical tips
Render PDFs at around 150–200 DPI if you rasterize them yourself; very high DPI slows everything without improving accuracy much.
Multi-page PDFs return one result per page. Concatenate the Markdown yourself or use the pipeline's page-merging helpers if your version provides them.
Always spot-check tables. Merged cells and borderless tables are where every table-recognition model makes mistakes.
PaddleOCR-VL: vision-language document parsing
PaddleOCR-VL is a compact vision-language model for document parsing (text, tables, formulas, charts) with multilingual support. PaddleOCR-VL-1.6 arrived in PaddleOCR 3.6.0 (May 28, 2026) and is reported by Baidu at 96.33% on OmniDocBench v1.6 (self-reported). It is the most accurate option here but needs a capable GPU or a dedicated inference server; CPU works but the official docs do not recommend it for production.
from paddleocr import PaddleOCRVL
pipeline = PaddleOCRVL() # or PaddleOCRVL(device="cpu") for a slow trial run
output = pipeline.predict("page.png")
for res in output:
res.print()
res.save_to_json(save_path="output")
res.save_to_markdown(save_path="output")
from paddleocr import PaddleOCRVL
pipeline = PaddleOCRVL()
pages = list(pipeline.predict("contract.pdf"))
merged = pipeline.restructure_pages(pages, merge_tables=True, relevel_titles=True, concatenate_pages=True)
for res in merged:
res.save_to_markdown(save_path="output")
Inference engines
PaddleOCRVL(engine="transformers") runs the model through Hugging Face Transformers instead of the Paddle engine. For throughput, the docs describe running the VLM behind a dedicated inference server (such as vLLM or SGLang) and pointing PaddleOCR-VL at it via vl_rec_backend; follow the official PaddleOCR-VL page for the exact settings of your version.
HPD-Parsing: high-throughput parsing
HPD-Parsing was announced by the PaddleOCR team on July 22, 2026 as a high-throughput document-parsing model aimed at large batch workloads on GPUs. It is newer and less documented than the other pipelines, so we deliberately do not repeat throughput numbers here. Read the release notes and the official docs for model download, supported hardware and benchmark methodology before planning capacity around it, and benchmark on your own documents.
Performance tuning
Measure first. These are the levers that usually matter, roughly in order of payoff:
Turn off modules you do not need. For clean scans: use_doc_orientation_classify=False, use_doc_unwarping=False, use_textline_orientation=False.
Pick a smaller tier (small or tiny) when accuracy on your documents is already sufficient.
Reuse the object. Create PaddleOCR(...) once; model loading dominates a single call.
Raise batch sizes on GPU (text_recognition_batch_size).
Resize big inputs. Lower text_det_limit_side_len or downscale huge photos before OCR.
CPU: keep enable_mkldnn on and tune cpu_threads; consider the OpenVINO engine on Intel CPUs.
High-performance inference:enable_hpi=True picks an optimized backend automatically. It currently supports Python 3.8–3.12 on Linux x86-64 and needs extra plugins; see the official guide.
Set device: "gpu"/"gpu:0" for NVIDIA, and "npu:0", "xpu:0", "mlu:0" and others on supported Chinese accelerators (these need the matching PaddlePaddle build). On macOS use CPU. If the GPU is not used, paddle.device.get_device() should print gpu:0; if it prints cpu you installed the CPU wheel.
Batch processing
batch.py
from pathlib import Path
from paddleocr import PaddleOCR
ocr = PaddleOCR(lang="en", use_doc_orientation_classify=False, use_doc_unwarping=False)
files = sorted(str(p) for p in Path("scans").glob("*.jpg"))
# predict() accepts a list and returns one result per input
for res in ocr.predict(files):
name = Path(res["input_path"]).stem
res.save_to_json(f"output/{name}")
Custom models
Use your own trained or exported models by directory: PaddleOCR(text_detection_model_dir="./my_det", text_recognition_model_dir="./my_rec"), optionally with text_detection_model_name / text_recognition_model_name. Training and fine-tuning are covered in the official docs; for most printed text, tuning thresholds and preprocessing is a cheaper first step than training.
RAG and LLM pipelines
For retrieval-augmented generation, parse documents to Markdown, split by headings, and embed the chunks. PP-StructureV3 and PaddleOCR-VL already emit heading-aware Markdown, which makes chunking far cleaner than splitting raw OCR lines.
rag_chunks.py
from pathlib import Path
from paddleocr import PPStructureV3
pipeline = PPStructureV3(lang="en")
md_parts = []
for res in pipeline.predict("handbook.pdf"):
res.save_to_markdown(save_path="md")
text = "\n\n".join(p.read_text(encoding="utf-8") for p in sorted(Path("md").glob("*.md")))
# split on level-2 headings; replace with your splitter of choice
chunks = [c.strip() for c in text.split("\n## ") if c.strip()]
print(len(chunks), "chunks")
Keep page numbers and source file in chunk metadata so answers can cite.
Store the OCR confidence for low-quality scans and flag low-confidence chunks.
Never assume extracted numbers are correct; for invoices and finance, validate (totals, dates, checksums).
Dify, RAGFlow and other platforms
Most no-code platforms call OCR over HTTP. Run PaddleOCR as a service (see Docker and the serving API below) and call it from the platform's HTTP/tool node, or use the platform's own PaddleOCR connector if it ships one. Check the platform's current docs, because connector names and options change often.
Serving over HTTP
Terminal
paddlex --install serving
paddlex --serve --pipeline OCR # listens on port 8080 by default
client.py
import base64, requests
with open("demo.jpg", "rb") as f:
payload = {"file": base64.b64encode(f.read()).decode("ascii"), "fileType": 1} # 1 = image, 0 = PDF
r = requests.post("http://localhost:8080/ocr", json=payload, timeout=120)
r.raise_for_status()
for res in r.json()["result"]["ocrResults"]:
print(res["prunedResult"])
Details, authentication and scaling options are in the official serving guide. Do not expose this port to the internet without your own authentication layer.
MCP server for AI agents
The official paddleocr-mcp package (0.8.5 at the time of writing, Python 3.10+) exposes OCR, PP-StructureV3 or PaddleOCR-VL as a Model Context Protocol tool, so a host such as Claude Desktop can read images and PDFs.
Terminal
python -m pip install "paddleocr-mcp[local-cpu]" # local CPU inference
# or: python -m pip install paddleocr-mcp # use a hosted / self-hosted backend only
Choose the model with --model (or PADDLEOCR_MCP_MODEL): PP-OCRv6 (default), PP-OCRv5, PP-OCRv5-latin, PP-StructureV3, PaddleOCR-VL, PaddleOCR-VL-1.5, PaddleOCR-VL-1.6. Choose where inference runs with --ppocr_source: local (default), aistudio, qianfan, or self_hosted. Use --http for Streamable HTTP instead of stdio (binds 127.0.0.1:8000 by default).
Privacy: with local, files stay on your machine. With aistudio or qianfan, your documents are uploaded to those services. Pick deliberately.
JavaScript and browser OCR
@paddleocr/paddleocr-js (0.4.2 at the time of writing, Apache-2.0) runs PaddleOCR models in the browser using ONNX Runtime Web and OpenCV.js. Images never leave the user's device. It is a young package (version 0.x), so pin the version and expect API changes.
Terminal
npm install @paddleocr/paddleocr-js
ocr.js
import { PaddleOCR } from "@paddleocr/paddleocr-js";
const ocr = await PaddleOCR.create({
lang: "ch",
ocrVersion: "PP-OCRv5",
ortOptions: { backend: "auto" },
});
const [result] = await ocr.predict(fileOrBlob); // predict() returns an array, one entry per image
console.log(result.items);
With ocrVersion: "PP-OCRv6" the SDK uses the PP-OCRv6 small pair; for tiny, pass textDetectionModelName: "PP-OCRv6_tiny_det" and textRecognitionModelName: "PP-OCRv6_tiny_rec". Self-hosting model archives and WASM files is supported; see the package README. Model download size and first-load time matter on mobile networks, so show a loading state.
Docker
A minimal CPU container. This is an example recipe, not an official image; test it on your own base image and hardware.
Dockerfile
FROM python:3.12-slim
# OpenCV runtime libraries (needed if you see "libGL.so.1" or "libgthread" errors)
RUN apt-get update && apt-get install -y --no-install-recommends libgl1 libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
RUN python -m pip install --no-cache-dir paddlepaddle==3.2.1 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/ \
&& python -m pip install --no-cache-dir "paddleocr[all]"
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]
Cache models. Mount a volume for ~/.paddlex (where models are cached) so containers do not re-download weights on every start.
GPU: use a CUDA base image, install the paddlepaddle-gpu wheel from the CUDA index, and run with --gpus all (needs the NVIDIA Container Toolkit on the host).
Air-gapped: pre-download models and pass the *_model_dir arguments.
Python API reference
Class
Import
Use
PaddleOCR
from paddleocr import PaddleOCR
Text detection + recognition
PPStructureV3
from paddleocr import PPStructureV3
Layout, tables, formulas to Markdown/JSON
PaddleOCRVL
from paddleocr import PaddleOCRVL
Vision-language document parsing
PPChatOCRv4Doc
from paddleocr import PPChatOCRv4Doc
Key information extraction with an LLM (needs paddleocr[ie])
Methods on every pipeline
predict(input, **kwargs)generator/list
Run inference. input may be a path, URL, numpy array, directory or a list of those; PDFs are supported. Call-time keyword arguments override constructor defaults for that call.
Flags mirror the Python constructor arguments: -i/--input, --lang, --ocr_version, --device, --save_path, and the --use_* toggles. Run paddleocr ocr --help for the list your version supports. The old 2.x flags --image_dir, --use_gpu and --use_angle_cls no longer work.
Language codes
Pass a code through lang. Common values:
Code
Language
Model family
en
English
PP-OCRv6 (50-language model)
ch
Chinese (Simplified) + English
PP-OCRv6
chinese_cht
Chinese (Traditional)
PP-OCRv5
japan
Japanese
PP-OCRv6
korean
Korean
PP-OCRv5 (korean_PP-OCRv5_mobile_rec)
latin, fr, de, es, it, pt …
Latin-script languages
PP-OCRv6 / PP-OCRv5 latin
cyrillic, ru
Russian and Cyrillic
PP-OCRv5
arabic, th, el, devanagari, ta, te …
Other scripts
PP-OCRv5
The full, version-specific mapping is the table in the appendix of the official OCR pipeline page. Treat it as the source of truth, since language coverage changes between releases.
Troubleshooting
ValueError: Unknown argument: use_gpu
You are using a 2.x tutorial with 3.x. Use PaddleOCR(device="gpu"). See migration.
pip cannot find a matching paddlepaddle-gpu
PyPI only has an old 2.6.2 GPU build. Install from the PaddlePaddle index with -i https://www.paddlepaddle.org.cn/packages/stable/cu126/ (or the CUDA version you need).
It runs on CPU even though I have a GPU
You probably installed the CPU wheel, or pass device="cpu". Check python -c "import paddle; print(paddle.device.get_device())" and nvidia-smi.
Very slow first run
Models are being downloaded and initialized. Later runs reuse the cache. Reuse a single PaddleOCR object in services.
Empty or garbled results
Wrong lang for the script: Korean, Arabic and Russian are not in the 50-language PP-OCRv6 model.
Tiny text: upscale the image or raise text_det_limit_side_len.
Faint text: lower text_det_thresh and text_det_box_thresh slightly.
Photographed pages: enable use_doc_unwarping; scans and screenshots: disable it.
ImportError: libGL.so.1 (Linux / Docker)
Install the OpenCV runtime libraries: apt-get install -y libgl1 libglib2.0-0.
Out of GPU memory
Lower batch sizes, process one page at a time, use a smaller tier, or run PaddleOCR-VL behind a dedicated inference server.
Still stuck? Search the official issue tracker and include your PaddleOCR and PaddlePaddle versions.
Release history
Dates are PyPI upload dates for the paddleocr package. Full notes are on the GitHub releases page.
Version
Date
Notable
3.7.0
June 11, 2026
PP-OCRv6 (tiny / small / medium) becomes the default OCR model
3.6.0
May 28, 2026
PaddleOCR-VL-1.6
3.5.0
April 21, 2026
Earlier 3.x feature release
3.4.1
April 14, 2026
Patch release
3.4.0
January 29, 2026
Earlier 3.x feature release
3.3.3
January 20, 2026
Patch release
HPD-Parsing was announced on July 22, 2026 (a model announcement, not a PyPI release).