Skip to main content
Back to Blog
Engineering•Archiving & Compliance•September 2026

Creating Searchable PDFs from Scanned Document Archives at Scale

How text layer overlays preserve original signatures, stamps, and paper texture while enabling full-text search and e-discovery across thousands of files.

What is a searchable PDF and how does FastOCR generate it?

A searchable PDF (also called a sandwich PDF) consists of two synchronized layers: the original high-resolution scanned image on the visual surface, and an invisible, selectable OCR text layer positioned directly beneath each word. FastOCR generates searchable PDFs via its asynchronous REST API: you submit the PDF, trigger processing, and retrieve the file using format=pdf. The resulting document retains 100% of original visual elements—such as signatures, physical stamps, and margin notes—while enabling Adobe Acrobat search, copy-paste, and enterprise indexing systems to find keywords instantly across 100+ languages.

Visual Preservation vs. Pure Text Extraction

In legal, medical, and banking compliance, modifying the visual layout of a signed document is strictly prohibited. You cannot simply discard the scanned image and replace it with re-rendered text.

A searchable PDF solves this constraint by maintaining the exact bitmap of the scan while embedding an invisible vector font layer mapped to identical coordinates. When a user highlights text or presses Ctrl+F, the PDF reader references the invisible coordinate layer.

Automating Batch Conversions with Python

With the REST API, processing an entire folder of scanned documents into searchable PDFs takes one helper built on the FastOCR Python SDK and a short loop. The API accepts PDF files up to 1 GiB, and PNG, JPG, JPEG, GIF, WebP and BMP images up to 20 MiB. An image counts as one page, and an image comes back as a one-page searchable PDF. By default no more than 2 documents per account process at once.

import io

from fastocr_sdk import FastOCR

client = FastOCR()  # reads FASTOCR_API_KEY
WAIT_SECONDS = 3600


def ocr_pdf(path, output_format="text"):
    if output_format == "pdf":
        job = client.documents.process(path, timeout=WAIT_SECONDS)
        buffer = io.BytesIO()
        client.documents.download_searchable_pdf(job.id, buffer)
        return buffer.getvalue()
    text = client.extract_text(path, timeout=WAIT_SECONDS, allow_partial=True)
    return text.encode("utf-8")
from pathlib import Path

input_folder = Path("./incoming_scans")
output_folder = Path("./searchable_archive")
output_folder.mkdir(exist_ok=True)

for scan_path in input_folder.glob("*.pdf"):
    print(f"Processing {scan_path.name}...")
    target_path = output_folder / f"searchable_{scan_path.name}"
    target_path.write_bytes(ocr_pdf(str(scan_path), output_format="pdf"))
    print(f"Archived {target_path.name}")

Scale your document processing

Explore the full REST API documentation and start converting documents today.