Somewhere in the last seven days, a Rust crate with a boring name jumped from roughly 7,700 stars to 16,300. That's not a viral tweet spike from a demo GIF — pdf-inspector is a document-processing library, the least glamorous category of infrastructure there is. It doesn't generate images, write code, or answer questions. It looks at a PDF and decides, in about ten milliseconds, whether the thing needs OCR at all.
That's the whole pitch, and it's a better one than it sounds. Every team building a RAG pipeline, a document-search product, or an agent that reads uploaded files has hit the same wall: PDFs are not one file format, they're at least four (clean text, scanned images, embedded images, and messy hybrids of all three), and most extraction tools treat them as if they're all the same problem. Firecrawl, the web-scraping-for-LLMs company behind firecrawl, built pdf-inspector to stop paying OCR prices for PDFs that never needed OCR in the first place.
PDF ingestion has been one of the quietly expensive corners of the AI-tooling stack for a couple of years now. Every RAG framework tutorial eventually runs into a PDF that breaks the naive text extractor — a two-column layout that gets read left-to-right straight across both columns, a scanned invoice with zero embedded text, a contract where half the pages are native and half are faxed exhibits stapled in. The industry's default answer has been to reach for the heaviest tool available — OCR everything, or route everything through a vision-language model — because that's the one approach guaranteed to at least attempt every document. It's also the approach that turns a large batch of uploaded PDFs into a needlessly large API bill and a slow processing queue, most of it spent OCR'ing documents that were never scanned in the first place.
What it actually does
pdf-inspector is a Rust library — with official bindings for Python, Node.js/Bun, and WebAssembly — that does three things in sequence:
-
Classifies a PDF as
TextBased,Scanned,ImageBased, orMixedby sampling its content streams for text operators (Tj/TJ) versus image operators (Do), without rendering a single page. - Extracts text with position awareness — font metadata, X/Y coordinates, multi-column reading order, hyphenation rejoining, CID font and ToUnicode CMap decoding, RTL text support.
- Converts the result to clean Markdown: heading levels inferred from font-size ratios, bullet/numbered/lettered lists, monospace-triggered code blocks, table detection via both rectangle geometry and heuristic alignment, bold/italic from font names, and URLs turned into links.
None of that requires a model. The core Rust and WASM builds have a single dependency, lopdf, for low-level PDF parsing — no bundled ML weights, no GPU, no network call. That's the detail that makes the growth curve make sense: this is infrastructure you can vendor into an offline pipeline or a browser tab and trust to behave the same way every time.
The classifier itself is cheap because it never rasterizes anything. Rendering a page to an image — the first step almost every OCR or VLM pipeline takes — is the expensive part of document processing; pdf-inspector's detection phase skips it entirely by reading the PDF's own content stream operators directly. A page made of Tj/TJ text-drawing operators is text. A page that's mostly a single Do operator pointing at an embedded image is scanned. A page with both, in roughly balanced proportion, is Mixed. That's a few hundred microseconds of stream parsing per page instead of a rasterize-then-classify pass, which is why the whole 200-document corpus clears in under half a second.
Table detection gets two independent passes rather than one: a rectangle-based method that looks for the geometric grid lines PDF generators draw explicitly, and a heuristic alignment method that infers table structure from columns of text that line up even when no visible border was ever drawn. Running both and reconciling them is a large part of why the TEDS (table structure) score comes in at 0.814 against a corpus that presumably includes both bordered and borderless tables — a category where naive text-position extraction usually falls apart completely.
How it works: routing, not replacing, OCR
The interesting architectural decision isn't the Markdown converter — every PDF-to-Markdown tool has one of those — it's what the library calls selective OCR, and it only ships in the Python and Node builds (the pure Rust/WASM core stays OCR-free by design).
The flow looks like this:
- A document goes through the classifier first.
TextBasedpages get extracted natively and never touch an OCR path — the docs describe this as capable of running in well under 200ms locally. - Pages flagged
ScannedorImageBasedget routed to OCR, but only those pages, not the whole document. The classifier supports four scan strategies, and which one you pick is really a decision about where you want to spend your error budget:EarlyExit(the default) stops the moment it hits a non-text page, which is fast but can misclassify a mostly-text document with one scanned exhibit page buried in the middle;Fullscans every page for a definitive answer at the cost of scanning the whole document up front;Sample(n)checks evenly spaced pages, a middle ground for long documents where you're willing to trade a small miss-rate for speed; andPages(vec)lets you target specific pages directly when you already know, say, that exhibits always land at the end of a filing. - Each page's result carries a
provenancefield —native,ocr, orfused— plus a confidence score, so downstream code (or a human reviewer) can tell exactly how a given block of text was produced instead of treating extraction as a black box. - OCR itself is pluggable through PDFium and ONNX Runtime, loaded lazily and only when a page actually needs them — a default
autorequest that never encounters a scanned page never pulls those dependencies into memory at all.
This is the part competitors mostly skip. Tools built around vision-language models treat every PDF as a scanned document by default, because it's the simplest thing to build and it works acceptably on everything. pdf-inspector's bet is that "acceptable on everything" is the wrong target when a meaningful fraction of the PDFs flowing through a typical ingestion pipeline (bank statements, contracts, generated reports, exported invoices) are already perfectly parseable text — and running an OCR/VLM pass on them anyway is pure wasted latency and API spend.
It's also a familiar shape if you've watched the rest of the AI infrastructure stack mature. LLM gateways added routing so cheap requests don't hit the most expensive model. Vector databases added hybrid search so semantic lookups don't run on queries a keyword match would answer instantly. pdf-inspector is the same move applied one layer earlier: don't send a document through the most expensive path in the pipeline until you've confirmed it actually needs it. Classification-as-a-gate, rather than classification-as-an-afterthought, is a pattern that's been under-applied specifically in document ingestion, where "just OCR everything" has been the default for long enough that teams stopped questioning whether the majority of their documents needed it.
The benchmark numbers
Firecrawl published results against the opendataloader-bench corpus — 200 PDFs scored on reading-order accuracy, table structure (TEDS), and heading detection, rolled into a composite score:
| Engine | Composite score | Reading order | Table TEDS | Heading detection |
|---|---|---|---|---|
| pdf-inspector | 0.875 | 0.915 | 0.814 | 0.788 |
| LiteParse | 0.873 | — | — | — |
| OpenDataLoader | 0.831 | — | — | — |
| PyMuPDF4LLM | 0.735 | — | — | — |
| MarkItDown | 0.589 | — | — | — |
Processing the full 200-PDF corpus took 0.470 seconds (median of five runs) — for comparison, a single call to a hosted OCR/VLM API for one moderately complex PDF commonly takes longer than that on its own. The margin over LiteParse is thin enough that it reads more like "competitive with the best rule-based parser available" than "categorically better," but the gap over PyMuPDF4LLM and MarkItDown — both widely used defaults in RAG tutorials — is large enough to matter in production.
Worth being precise about what this benchmark does and doesn't show: it's a text-based-PDF corpus, testing extraction quality, not OCR accuracy on scanned documents. pdf-inspector isn't claiming to out-OCR anything — it's claiming that a lot of documents currently getting OCR'd don't need to be, and it can prove it wins on the ones that don't.
Why this matters beyond the star count
Cost. OCR and VLM-based extraction are priced per page or per document through most hosted providers. A pipeline that classifies first and only pays for OCR on the subset of documents that actually require it turns a linear cost curve into something much flatter — the savings scale with how text-heavy your document mix already is.
Latency. Sub-200ms local extraction versus a network round trip to an OCR service is not a marginal difference in a synchronous upload-and-preview flow. It's the difference between showing a user their document instantly and making them wait.
Lock-in. Because the core library ships with zero bundled models and a single PDF-parsing dependency, it doesn't tie you to a specific OCR vendor. The OcrPageProvenance and confidence-score design means you can swap the OCR backend behind the force/auto/off routing modes without touching the rest of the pipeline — the documentation doesn't yet enumerate which external OCR providers plug in cleanly, which is a real gap if you're evaluating this today rather than reading the source.
Security and maintainability. A parser with one dependency and no ML weights has a much smaller attack surface and audit burden than one that ships a bundled model file or requires trusting a third-party inference API with every uploaded document — a nontrivial point for anyone processing PDFs that contain PII or financial data.
DX. Four language bindings from one Rust core means the classification logic — the actual hard-won part — doesn't get reimplemented and drift across a Python service, a Node API, and a browser-side preview. That kind of single-source-of-truth binding strategy is table stakes for infra libraries in 2026, but it's still not universal, and it's worth crediting here.
License. The whole thing ships under MIT. That matters more than it might look for a project maintained by a venture-backed company whose paid product (Firecrawl's hosted API) competes directly with what a well-tuned self-hosted pipeline could replace. There's no source-available clause, no field-of-use restriction, no clock on a future re-license — you can fork it, vendor it, and never touch Firecrawl's paid endpoints, and that promise is enforceable rather than aspirational. It's the same trust-building move other infra-adjacent companies (Unstructured, LangChain) have made with their own core libraries: give away the component that would otherwise be a wedge for lock-in, and compete on the hosted convenience layer instead.
Practical use cases
- RAG ingestion pipelines that need to decide, per-document and per-page, whether to hit an expensive OCR/VLM endpoint or extract locally for free.
- Document upload previews where sub-200ms local extraction beats a network call to render a first-pass view before a slower, higher-fidelity pass finishes.
-
Compliance and audit tooling, where the
provenancefield's native/OCR/fused labeling gives a defensible answer to "how was this text produced" for every extracted block — useful anywhere extraction accuracy needs to be traceable, not just plausible. - Browser-based tools — the WASM build with embedded CMaps means PDF classification and text-based extraction can run entirely client-side, with no document ever leaving the user's machine unless it actually needs OCR.
-
Bulk reprocessing of large document archives where the
Sample(n)andEarlyExitscan strategies let you tune the cost/thoroughness tradeoff at corpus scale rather than per-file.
What the docs don't spell out
A few gaps are worth flagging before adopting this in production:
-
OCR provider integration is underdocumented. The Python docs describe the routing contract (
auto/force/off, provenance, confidence) in detail but don't name which external OCR services are supported out of the box — you're expected to wire this up yourself against PDFium/ONNX Runtime. -
Confidence scoring is opaque. The
PdfResultand OCR page results both expose a 0.0–1.0 confidence value, but the public docs don't explain how it's calculated, which matters if you're planning to threshold on it for automated routing decisions rather than just logging it. - The benchmark is a best-case scenario for this design. opendataloader-bench is a general-purpose extraction corpus, not a stress test of pathological PDFs — heavily nested tables, rotated scans mixed with live text, forms with overlapping layers. Classification accuracy on genuinely ambiguous "mixed" documents (which the library does define as a category) isn't broken out separately in what's been published.
- Heading detection is the weakest of the four scored dimensions (0.788), which tracks with font-size heuristics being inherently fragile against PDFs that don't follow conventional heading styling — a real risk for structured-document use cases like legal or academic text.
-
"Flags broken font encodings automatically" is doing a lot of quiet work. The library documents that it detects malformed CID font mappings and encoding mismatches rather than silently emitting garbled text, which is the right instinct — but it also means a nontrivial slice of real-world PDFs (older documents from unusual generators, some scanned-then-OCR'd-elsewhere hybrids) will come back flagged rather than cleanly extracted, and a pipeline built assuming every
TextBasedclassification yields clean output needs to handle that flag as a real branch, not an edge case to ignore.
One adoption signal worth weighing alongside the star count: roughly 1,100 forks against 16,300 stars is a comparatively high fork ratio for a library this new, which tends to indicate people are actually pulling the code to build bindings, patch OCR integrations, or adapt the classifier for their own corpus — not just bookmarking a GitHub trending entry.
How it stacks up
| Tool | Approach | OCR required | Bindings | Notable strength |
|---|---|---|---|---|
| pdf-inspector | Classify then route, rule-based extraction | Optional, selective | Rust, Python, Node, WASM | Speed + zero-dependency core |
| PyMuPDF4LLM | Rule-based extraction via PyMuPDF | No | Python | Mature, widely deployed |
| MarkItDown | Format-agnostic conversion (Microsoft) | Optional | Python | Broad file-type coverage beyond PDF |
| Docling | ML layout models + OCR | Often | Python | Strong on complex layouts, tables |
| Unstructured | Hybrid rule-based + ML partitioning | Often | Python | Wide format support, mature ecosystem |
| LlamaParse | Hosted VLM-based parsing | Always (hosted) | API | High fidelity on hard documents, no self-hosting |
The honest framing: pdf-inspector isn't competing with Docling, Unstructured, or LlamaParse on documents that genuinely need heavy-duty layout understanding — scanned forms, rotated pages, dense multi-column academic PDFs with figures, documents where a vision model's ability to look at the page is doing real work. It's competing with the assumption that you need those tools' overhead for the sizable share of real-world PDFs that are just... text, correctly encoded, standard layout, nothing a VLM's visual understanding adds value to. The routing model means it can sit in front of one of those heavier tools rather than replacing it — classify first, send only the hard cases downstream, and let the expensive model earn its cost on documents where it's actually needed.
That framing also explains why "beats PyMuPDF4LLM and MarkItDown" is the more meaningful comparison than "beats LlamaParse." PyMuPDF4LLM and MarkItDown occupy the same niche pdf-inspector does — free, local, rule-based, no OCR by default — and are the tools most RAG tutorials reach for first specifically because they're the path of least resistance, not because anyone benchmarked them. Docling and Unstructured sit a tier up in capability and cost; comparing pdf-inspector against them on a text-only corpus would be comparing a router against a full parsing engine, which isn't a fair fight in either direction.
An independent read
The growth number is real and the benchmark is credible, but it's also a first-party benchmark against a corpus Firecrawl didn't design and against competitors on a single axis (text-based extraction quality). It says nothing about how pdf-inspector's classifier behaves on adversarial or edge-case documents at scale, and the OCR-integration story is still thin enough that "selective OCR" is more of a well-designed interface than a finished product today — the routing contract is there, but which OCR providers you're expected to bring is left as an exercise for the integrator.
There's also a survivorship-bias risk worth naming directly: a week of explosive star growth measures how many developers found the pitch compelling enough to click a button, not how many put it into a production pipeline and kept it there. GitHub Trending has burned people before on tools that looked transformative in week one and quietly stalled once the edge cases showed up — worth remembering before treating a star count as a maturity signal rather than an interest signal.
What's genuinely well done, independent of the hype cycle, is the architecture: parsing the document once and sharing it across classification and extraction instead of re-reading the file per stage, exposing provenance and confidence per page instead of returning a flat string that hides how each block of text was produced, and keeping the core dependency-free so it can run in a browser tab with no server round trip at all. Those are the kinds of design decisions that tend to age well regardless of whether this specific crate is still the default people reach for in a year — they're the right shape for the problem, and a competitor would have to make similar choices to catch up.
Who should try it, who should wait
Try it now if you're building or maintaining a document-ingestion pipeline and can measure what fraction of your PDFs are currently getting OCR'd unnecessarily — that's a number you can go check before writing any code, and it directly predicts your savings. Also worth a look if you want fast, dependency-free PDF classification as a preprocessing step in front of whatever heavier extraction tool you already use: even teams committed to Docling or Unstructured for the hard cases can drop pdf-inspector in purely as the routing gate and keep everything downstream unchanged. The WASM build is a genuinely distinct option, too — client-side classification with no document ever touching a server is hard to get elsewhere.
Wait if your documents are predominantly scanned, rotated, or layout-heavy (medical records, historical archives, faxed contracts, forms with overlapping handwritten and printed layers) — you're not the audience this library optimizes for, and Docling or a hosted VLM parser will likely serve you better today. Also wait if you need a documented, supported OCR integration out of the box rather than wiring PDFium and ONNX Runtime yourself; that's currently a build-it-yourself step, not a configuration flag.
Ignore if you're already happy with an existing pipeline's accuracy and cost profile, or if your document volume is small enough that OCR cost was never the bottleneck to begin with. A 16.3k-star jump in a week is a signal to evaluate, not a mandate to migrate — and migrating a working extraction pipeline for a library that's still filling in its OCR-provider documentation is a bet on the roadmap, not just the code that exists today.
Discussion: if you're running a document-ingestion pipeline today, do you actually know what fraction of your PDFs are text-based versus scanned — or are you paying OCR/VLM prices for all of them by default because nobody built the classification step first?
Sources:
Top comments (0)