A fast Rust library that tells text-based PDFs from scanned ones, then extracts position-aware text and clean Markdown — locally, in milliseconds. Skip the OCR bill for the ~54% of PDFs that never needed it.
TextBased, Scanned, ImageBased, or Mixed in ~10–50ms by sampling content streams. Returns a confidence score and per-page OCR routing.
Extraction with font info, X/Y coordinates, and automatic multi-column reading order.
Headings, bullet/numbered lists, code blocks, tables, bold/italic, URL linking, and page breaks.
Rectangle-based detection from drawing ops plus heuristic alignment detection. Financial tables, footnotes, and cross-page continuations.
ToUnicode CMap decoding for Type0/Identity-H fonts, with UTF-16BE, UTF-8, and Latin-1 encodings.
Newspaper-style column detection, sequential reading order, and right-to-left text support.
Flags broken font encodings automatically so callers can fall back to OCR only when it's actually needed.
Pure Rust. No ML models, no external services. A single parse shared between detection and extraction.
Evaluated on the opendataloader-bench corpus (200 PDFs). Direct text-extraction engines only — no OCR, no ML. Higher is better.
| Engine | Overall | Reading order | Tables | Headings | 200 docs |
|---|---|---|---|---|---|
| pdf-inspector | 0.83 | 0.88 | 0.66 | 0.74 | 4s |
| opendataloader | 0.84 | 0.91 | 0.49 | 0.74 | 11s |
| pymupdf4llm | 0.73 | 0.89 | 0.40 | 0.41 | 18s |
| markitdown | 0.58 | 0.88 | 0.00 | 0.00 | 8s |
Fastest engine measured, the best table detection of any engine here, and heading quality now on par with opendataloader — at ~2.5× its speed.
Reading order still trails opendataloader slightly, and tables that need the visual structure only an OCR engine can see.
use pdf_inspector::process_pdf; let result = process_pdf("document.pdf")?; println!("Type: {:?}", result.pdf_type); if let Some(markdown) = &result.markdown { println!("{}", markdown); } // full reference → docs/rust-api.md
import pdf_inspector result = pdf_inspector.process_pdf("document.pdf") print(result.pdf_type) # "text_based" | "scanned" | "image_based" | "mixed" print(result.markdown) # Markdown string or None # full reference → docs/python.md
import { readFileSync } from 'fs'; import { processPdf } from '@firecrawl/pdf-inspector'; const result = processPdf(readFileSync('document.pdf')); console.log(result.pdfType); // "TextBased" | "Scanned" | ... console.log(result.markdown); // Markdown string or null // full reference → napi/README.md
# install the CLI tools cargo install pdf-inspector # convert a PDF to Markdown pdf2md document.pdf # classify only — is it scanned? detect-pdf document.pdf --analyze --json # structured output for pipelines pdf2md document.pdf --json
Run the classifier locally for text-based PDFs; hand the scanned, OCR, and at-scale work to Firecrawl.
Pure-Rust library and CLI. Classify and extract text-based PDFs on your own machine in milliseconds — no external calls, no OCR bill, MIT licensed.
Scanned documents, OCR, DOCX / XLSX / HTML, and parsing at scale — clean, LLM-ready Markdown from one API call. The downstream route for everything local parsing can't reach.