Why PDF extraction is a judgment problem
Firecrawl's pdf-inspector is a Rust project for classifying PDFs, extracting their native text, reconstructing layout, and optionally using OCR. The important question is not simply how to turn a PDF into a string. It is how much of the document can be recovered from its own structure, how trustworthy that recovery is, and when a page needs a more expensive visual path. This series follows that question so that a newcomer can understand both what pdf-inspector does and where its results stop being proof of completeness.
That distinction matters because a PDF has two faces. To a person, it is a page that appears to have words, headings, tables, and pictures. To software, it may be a collection of positioned glyphs, font-specific codes, drawing operations, images, and annotations. The visible page can look perfect while its text layer is empty, its characters are decoded incorrectly, or its reading order is interleaved. A useful parser must therefore make a judgment before it makes a polished output.
The page that looks readable but is not yet evidence
Consider a report whose pages contain selectable text except for a scanned appendix. A plain converter may return a convincing string for the report and nothing for the appendix. Now consider a harder case: the appendix contains a text layer, but the font mapping turns character codes into meaningless symbols. The result is not obviously empty. It is worse: it looks like extraction succeeded unless someone compares it with the page image.
A third case is a page with a large background image and a small native overlay. The overlay might be a date, label, or stamp. A text-only test can find real characters and still miss most of the page's essential content. Conversely, a page can contain many drawing rectangles that belong to a chart or decorative template, not a table. The same surface clues can support different interpretations depending on their relationships.
These cases expose the weakness of the usual mental model: “Does this PDF contain text?” pdf-inspector asks a more useful sequence of questions. Does the page expose meaningful text operators? Are the characters decodable? Do the positions and page coordinates line up with the visible page? Does the arrangement look like a coherent text layout, a table, or a scan? If native evidence is insufficient, which pages—not necessarily the whole document—should receive OCR?
The project calls the first result a classification, not a promise. It can distinguish text-based, scanned, image-based, and mixed PDFs; report a confidence score; and identify pages needing OCR with reasons such as scanned content, vectorized text, or suspected garbled text. Those labels are routing evidence. They tell a pipeline where to spend more work, not that a page's final meaning has already been verified.
This page-level view changes what “the document was processed” should mean. A long PDF may contain a clean cover, text-heavy body pages, a chart-rich section, and a scanned signature page. Treating the whole file as one state hides those differences and encourages an all-or-nothing choice. Treating each page as an evidence-bearing unit allows the pipeline to preserve native output where it is strong while marking, replacing, or escalating only the weak portion. The result is not less coherent; it is more honest about where coherence came from.
It also gives an application a place to make its own policy explicit. One system may accept native Markdown with a warning when a page is unusual. Another may require OCR for every page containing a scan background. A third may send unresolved pages to a hosted parser because missing coverage is more costly than added latency. pdf-inspector supplies the observations and routing hooks; it does not pretend that one threshold fits every downstream use.
pdf-inspector is a routing system, not an OCR wrapper
The repository's subject is easy to misidentify. It is not just a fast text extractor with OCR bolted on, and it is not an OCR service that happens to accept PDFs. Its default path is a native Rust parser. That parser classifies pages, reads PDF structure, preserves positions, analyzes layout, and converts the result to Markdown. The optional vision path begins only when page evidence says that native recovery is missing, unreliable, or incomplete.
This design makes native work valuable even when OCR exists. If a PDF already carries a usable text layer, rasterizing every page adds latency and requires external runtime components that contribute nothing to the clean case. If only three pages in a long document are scanned, sending every page to OCR spends resources where the document has already supplied better evidence. The quality-aware route instead treats the document as a set of page-level decisions.
The route also has an important asymmetry. Native parsing can often preserve exact text and geometry from the PDF's own representation. OCR can recover words that are visible in pixels but absent from that representation, yet it introduces recognition confidence and a model-dependent hypothesis. Neither path automatically dominates the other. The right choice depends on what evidence the page contains and what the downstream system is willing to treat as authoritative.
That is why pdf-inspector exposes more than a Markdown string. Its results can carry the detected PDF type, page count, confidence, pages needing OCR, reasons for those pages, layout complexity, table and column information, and encoding-issue status. The optional OCR result adds page-level source, model, confidence, timings, warnings, and hosted-fallback recommendations. These fields make uncertainty part of the interface instead of hiding it behind a successful function call.
For a downstream application, this is a useful separation of responsibilities. pdf-inspector can say that a page was classified as mixed, that a particular page was routed for suspected garbling, or that the completed local OCR result remains weak. The application can then decide whether to display the page, request a retry, preserve the warning beside the extracted text, or hand the page to a hosted service. Without those distinctions, every successful return value would look equally trustworthy and every failure would look equally mysterious.
The approach is especially relevant when extracted Markdown will feed search, summarization, indexing, or other automated work. A missing paragraph may reduce recall; a wrongly decoded paragraph can create a confident false fact. A table flattened into an interleaved paragraph can change relationships between labels and values. The structure-first route does not eliminate those risks, but it makes them visible at the point where a system can still choose a different path.
Why the decision is economically and operationally important
OCR is not free in the practical sense. It may require rendering pages, loading an inference runtime, resolving model artifacts, and holding image data in memory. A hosted document pipeline adds a network boundary and a different operational dependency. Native extraction avoids those costs for pages whose structure is already sufficient. The repository describes this as a smart-routing use case: classify quickly, extract locally when the page is text-based and credible, and escalate only where the local path cannot carry the document.
The benefit is not merely speed. Selective routing also preserves a clearer failure boundary. If a page is flagged because its text layer is garbled, that is a statement about page evidence. If PDFium or the OCR runtime cannot load, that is a deployment failure. If OCR completes but produces empty or weak text, that is a page-quality judgment. Keeping those cases distinct helps a downstream system decide whether to retry, use a hosted parser, alert an operator, or publish a result with a warning.
The repository reports strong native benchmark results on a named 200-PDF OpenDataLoader corpus with OCR disabled, including an overall score of 0.875, a reading-order score of 0.915, a table score of 0.814, and a complete-run time of 0.470 seconds. Those figures are useful context for the native path, but they belong to a particular run on particular hardware, versions, and evaluation rules. They do not establish OCR quality, universal accuracy, or performance for every PDF. A responsible reader should treat them as scoped evidence, not as the definition of the project.
Several boundaries are already visible. Classification confidence is heuristic rather than a calibrated probability. A page that passes native quality checks can still contain a layout that is difficult to interpret. OCR can fail because its external runtime or model is unavailable, or can complete with insufficient coverage. Resource limits can make a malformed or unusually large page fail cleanly rather than finish. In each case, the honest result is more useful than an unsupported claim that the page is complete.
The cognitive model for understanding the project
A practical way to understand pdf-inspector is to follow five linked questions.
First, what is present? Classification samples PDF structure for text, images, and other signals. This is the triage layer. Second, what does it mean? Native extraction must decode font-local characters and preserve the state that placed them on the page. Third, where does it belong? Coordinates, lines, columns, tables, and other layout relationships turn isolated runs into document structure. Fourth, what can be trusted? Quality checks look for empty, garbled, vectorized, or visually incomplete pages. Finally, what should happen next? A page can stay on the native path, enter selective OCR, be fused from both sources, or be recommended for a hosted pipeline.
The order matters. It would be premature to discuss Markdown quality before understanding the geometry that supports it. It would be unsafe to discuss OCR as a universal cure before separating missing text from incorrectly decoded text. And it would be misleading to quote a benchmark before knowing which path was measured and which cases were excluded.
The rest of this series develops that model from the inside out. It begins with the PDF representation that pdf-inspector reads, then examines the fonts and quality signals that determine whether native text deserves trust. It follows geometry into reading order, tables, and Markdown, and then traces selective OCR through routing, runtime dependencies, model verification, and page-level contracts. Finally, it examines how native and OCR evidence are reconciled and how a production system can preserve provenance while deciding when to stop locally.
The central lesson is modest but consequential: a readable page is an observation, not a guarantee about the representation available to software. pdf-inspector's value lies in making that gap explicit. It tries to recover as much structure as the PDF can support, measures the strength of the recovery, and spends visual or hosted resources where the native evidence runs out. To see why that requires more than a string API, the next step is to look at what a PDF actually contains for a parser to inspect.
References
- pdf-inspector repository
- Rust API guide
- Detector implementation
- Repository README
- Python API guide
- Vision contracts
- OCR routing
- OCR pipeline
- Node OCR API
- Published benchmark in README
- Benchmarking guide
- Benchmark harness
- Benchmark results branch
- Content-stream safeguards
- Rectangle clustering safeguards
- OCR runtime boundaries
- OCR fusion fallback behavior
- Library entry points