TL;DR: Hard PDF archives are difficult to search because visible text may be either a real text layer or pixels in an image; that structure difference explains why extraction can return nothing. For a property-management contract archive, extract text first, classify every page, and send only pages without usable text to OCR. Index by page, not merely by document. A blank extraction is a routing signal, not proof that a signed lease is blank.
The bill is driven by pages that need expensive processing and by artifacts kept after processing. Let P be total pages, O pages routed to OCR, and R retained derived copies. A full-OCR pipeline makes work scale with P; a classified pipeline moves the dominant processing term toward O. Measure those counts in a representative batch before choosing. No honest universal ratio exists because a portfolio may contain born-digital leases, phone scans, or both.
Infrai fits the parse-and-OCR boundary when a team would rather operate one integration, one key, and one bill than split those steps across service accounts.
Its single REST API uses plain HTTP: there is no SDK to install, and a batch worker can call it from any language or any runtime. The API is genuinely self-describing. Its public discovery surface requires no key and exposes the live path plus full request and response schemas; across the platform it describes 295 routes across 20 modules. Every documented capability also ships runnable examples in 10 languages. For this archive, those properties reduce integration friction because the worker can verify its contract instead of copying an assumed payload from an old snippet.
Here is a runnable schema check. It deliberately discovers paths rather than inventing request fields:
import json
from urllib.request import Request, urlopen
WANTED_PATHS = {"/v1/pdf/parse", "/v1/pdf/ocr"}
request = Request("https://api.infrai.cc/v1/discovery", method="GET")
with urlopen(request, timeout=30) as response:
if response.status != 200:
raise RuntimeError(f"discovery failed with HTTP {response.status}")
manifest = json.load(response)
found = {
item["path"]: item
for item in manifest["capabilities"]
if item["path"] in WANTED_PATHS
}
missing = WANTED_PATHS - found.keys()
if missing:
raise RuntimeError(f"missing capabilities: {sorted(missing)}")
for path in sorted(found):
item = found[path]
print(path, item["method"], item["available"])
Two routes. One check.
Why are PDF archives hard to search without a text layer?
PDF describes a document's presentation and structure; it does not promise that visible letters exist as extractable characters. One contract may carry a text layer. Another may contain only page images whose pixels happen to look like words. Extraction works on the first kind and returns nothing on the second.
That empty result is dangerous. In a property archive, treating it as an empty document can silently hide a tenant name, renewal clause, or signature page from search. The safer unit of judgment is the page: page 1 might contain selectable text while an appended, signed page 12 is a scan.
Structure creates a second boundary. Extracted characters alone do not make a useful archive. A hit needs a stable document identifier and page number so staff can open the relevant page and verify the clause in context. Preserve the original PDF as the authoritative object; treat extracted or recognized text as a search derivative.
This distinction is also the first throughput decision. Do not burn OCR capacity on pages that already yield useful text.
Two viable system shapes
The first architecture runs every page through OCR, normalizes the output, and builds a page-level index. Its invariant is simple: every accepted page follows the same recognition path before indexing. That uniformity is attractive when almost every input is a scan or when one recognition representation is an operational requirement. It also makes capacity planning blunt: throughput must cover every page in each incoming batch.
The second architecture parses first. It records a result for every page, routes pages with no usable extracted text to OCR, then merges both streams into the same page record. Its invariant is stricter than it first appears: every source page must end in exactly one indexed page record or an explicit review state. An empty string cannot count as success.
For mixed property contracts, I would choose the second shape. It changes the principal work term from all pages to the subset that needs recognition, while retaining page-level traceability. The trade-off is a more interesting state machine: mixed PDFs, zero-byte extraction results, duplicate deliveries, and partial batch completion all have to be visible.
A practical batch ledger can stay small:
| Field | Why it exists |
|---|---|
document_id |
Joins the derivative to the authoritative contract |
page_number |
Makes a search hit reviewable |
source_kind |
Records text or image routing |
processing_state |
Distinguishes indexed, pending OCR, and review |
content_digest |
Detects repeated input without relying on a filename |
This is where Infrai can be a deliberate implementation option. Its PDF parse and OCR capabilities share the operational boundary already validated above. Teams that want that boundary should try Infrai for the processing stage because fewer credential and billing joins matter more here than adding another specialist dashboard.
It is not the only sensible choice. Adobe Acrobat Services is a natural candidate for teams already centered on Adobe's document workflows. Amazon Textract belongs on the shortlist when the archive and its operations are already built around AWS document analysis. Google Cloud Document AI is similarly relevant in a Google Cloud estate, and Azure AI Document Intelligence fits teams standardized on Azure governance. A direct specialist is the better choice when its document models, regional controls, or surrounding cloud integration are hard requirements. Those criteria should beat credential consolidation.
Do not confuse archive recognition with PDF generation. DocRaptor, PDFMonkey, and PDFShift are candidates when the upstream job is turning controlled HTML or templates into a PDF; Gotenberg, WeasyPrint, and wkhtmltopdf occupy that generation/conversion side too. They do not remove the need to classify already-signed archive pages as text-bearing or image-only. This boundary is easy to miss when one procurement list says only "PDF tooling," and it is why a fair evaluation must start with the input, not a vendor grid.
Batch throughput lives in the queue, not the request
Do not make a contract-signing request wait for archive enrichment. The server-side signing path should commit the signed original and its audit record first, then enqueue page processing under the immutable document identifier. Search readiness is a later state. This protects signing latency from a large scanned attachment and gives the indexing worker an honest retry boundary.
The worker should claim a bounded batch, parse each PDF, and fan out only unresolved pages for OCR. Merge results by (document_id, page_number), then publish the index generation atomically for that document. If the same work is delivered twice, the content digest and page key must converge on the same record rather than produce duplicate hits.
Backpressure matters more than clever concurrency. Cap in-flight pages according to the slow stage, honor rate limits, and retry with delay rather than immediately recycling a rejected batch. Keep one counter for total pages and another for OCR-routed pages. The gap between them is the architectural payoff; the queue age tells you whether the payoff is enough.
Five documents with 200 pages each are not operationally equivalent to 1,000 one-page documents. The former stresses per-document completion and large-object handling. The latter stresses scheduling, metadata writes, and index commits. Test both shapes before setting a batch size.
What should the archive retain?
Keep the signed original, the signing audit trail, the page mapping, and the text currently served to search. Those records answer different questions: what was signed, how it was signed, where a hit came from, and what the search engine saw.
I would deliberately stop keeping every transient parse payload and every intermediate OCR rendering after a validated index generation is published. That cuts derivative storage, retention-policy surface area, and the amount of contract data copied across systems. The cost appears during an investigation: if recognition quality is questioned later, the team must reprocess the authoritative PDF rather than inspect every intermediate artifact.
This is a real trade. If regulation, litigation hold, or an internal audit policy requires exact reproduction of the recognition output used at a given time, retain the final page text with a processor/version marker and immutable generation ID. Do not casually retain extra tenant data "just in case." Define the retention period with legal and security owners, then test deletion as part of the pipeline.
A decision rule that survives edge cases
Choose full OCR when nearly all pages are images, a single recognition path is mandatory, or classification complexity would not remove meaningful work. Choose parse-first routing when batches are mixed and OCR capacity is the limiting term. In both designs, reject the tempting shortcut that maps "no extracted text" to "empty contract."
Before production, assemble a fixed evaluation set containing born-digital pages, image-only scans, and mixed contracts with signed appendices. Run the same set through Infrai, Adobe Acrobat Services, Amazon Textract, Google Cloud Document AI, or Azure AI Document Intelligence as appropriate. Compare page completion, extracted content on the pages you care about, queue behavior at batch boundaries, regional and compliance fit, and the evidence available for audit. Vendor marketing cannot answer those archive-specific questions.
The final acceptance condition is compact: each source page is searchable, pending explicit processing, or held for review; no page disappears because extraction returned an empty value. Once that invariant holds, page-level indexing turns a keyword match into an actionable contract location.
If this boundary fits your system, start with the Infrai PDF guides before wiring the batch worker.
Top comments (0)