Make a PDF Searchable, Fill PDF Form Fields, and Extract Field Values in Python

14 Minutes Read

This tutorial contains two independent PDF.co examples:

  • Example 1 applies OCR to a scanned PDF so its text becomes searchable.
  • Example 2 fills and reads existing interactive form fields in a different PDF.

Important: These examples use different source documents and are not sequential. Making a scanned PDF searchable adds a searchable text layer, but it does not create interactive form fields. To fill or extract form fields, the source PDF must already contain those fields.

Requirements

Install the Requests library:

pip install requests

Store your PDF.co API key in an environment variable named PDFCO_API_KEY.

On macOS or Linux:

export PDFCO_API_KEY="YOUR_PDFCO_API_KEY"

On Windows PowerShell:

$env:PDFCO_API_KEY="YOUR_PDFCO_API_KEY"

The examples use public sample files. Replace their URLs with your own directly accessible files when adapting the code.

Step 1: Example 1: Make a Scanned PDF Searchable

This example uses the PDF.co Make Searchable endpoint to apply OCR to a scanned PDF.

OCR recognizes text contained in the page image and adds a searchable text layer. It does not detect or create fillable text boxes, checkboxes, radio buttons, or other form controls.

The sample uses this stable PDF.co test file:

https://pdfco-test-files.s3.us-west-2.amazonaws.com/pdf-make-searchable/sample.pdf

Complete Python Script

Save the following code as make_searchable.py:

import os
import requests

API_KEY = os.environ["PDFCO_API_KEY"]
BASE_URL = "https://api.pdf.co/v1"

SOURCE_FILE_URL = (
    "https://pdfco-test-files.s3.us-west-2.amazonaws.com/"
    "pdf-make-searchable/sample.pdf"
)
OUTPUT_FILE = "searchable-output.pdf"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json",
}

payload = {
    "url": SOURCE_FILE_URL,
    "name": OUTPUT_FILE,
    "lang": "eng",
    "pages": "",
    "async": False,
}

response = requests.post(
    f"{BASE_URL}/pdf/makesearchable",
    json=payload,
    headers=headers,
    timeout=120,
)
response.raise_for_status()

result = response.json()

if result.get("error"):
    raise RuntimeError(result.get("message", "PDF.co processing failed."))

result_url = result["url"]

file_response = requests.get(result_url, timeout=120)
file_response.raise_for_status()

with open(OUTPUT_FILE, "wb") as output:
    output.write(file_response.content)

print(f"Searchable PDF saved as {OUTPUT_FILE}")

Run the script:

python make_searchable.py

The generated searchable-output.pdf should allow text selection and searching. It will not contain interactive form fields unless the source PDF already had them.

For larger documents, use asynchronous processing and monitor the returned jobId with the Job Check endpoint. See the PDF.co Make Searchable documentation.

Step 2: Example 2: Fill and Extract Existing PDF Form Fields

This is a separate demonstration using an IRS Form 1040 PDF that already contains interactive form fields.

The source file is:

https://pdfco-test-files.s3.us-west-2.amazonaws.com/pdf-form/f1040.pdf

This example performs two related operations:

  1. Fill selected fields in the existing form.
  2. Pass the resulting PDF URL to the PDF Forms Info Reader and print its field names and values.

The output of the fill request is used as the input for field extraction.

Complete Python Script

Save the following code as fill_and_extract_fields.py:

import os
import requests

API_KEY = os.environ["PDFCO_API_KEY"]
BASE_URL = "https://api.pdf.co/v1"

SOURCE_FORM_URL = (
    "https://pdfco-test-files.s3.us-west-2.amazonaws.com/"
    "pdf-form/f1040.pdf"
)
OUTPUT_FILE = "filled-f1040.pdf"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json",
}

fields_string = (
    "1;topmostSubform[0].Page1[0].f1_02[0];John A. Doe|"
    "1;topmostSubform[0].Page1[0].FilingStatus[0].c1_01[1];true|"
    "1;topmostSubform[0].Page1[0].YourSocial_ReadOrderControl[0]."
    "f1_04[0];123456789"
)

fill_payload = {
    "url": SOURCE_FORM_URL,
    "name": OUTPUT_FILE,
    "fieldsString": fields_string,
    "async": False,
}

fill_response = requests.post(
    f"{BASE_URL}/pdf/edit/add",
    json=fill_payload,
    headers=headers,
    timeout=120,
)
fill_response.raise_for_status()

fill_result = fill_response.json()

if fill_result.get("error"):
    raise RuntimeError(
        fill_result.get("message", "PDF.co could not fill the form.")
    )

filled_pdf_url = fill_result["url"]

file_response = requests.get(filled_pdf_url, timeout=120)
file_response.raise_for_status()

with open(OUTPUT_FILE, "wb") as output:
    output.write(file_response.content)

print(f"Filled PDF saved as {OUTPUT_FILE}")

info_payload = {
    "url": filled_pdf_url,
    "async": False,
}

info_response = requests.post(
    f"{BASE_URL}/pdf/info/fields",
    json=info_payload,
    headers=headers,
    timeout=120,
)
info_response.raise_for_status()

info_result = info_response.json()

if info_result.get("error"):
    raise RuntimeError(
        info_result.get("message", "PDF.co could not read the form fields.")
    )

fields = (
    info_result
    .get("info", {})
    .get("FieldsInfo", {})
    .get("Fields", [])
)

if not fields:
    print("No interactive form fields were found.")
else:
    print("\nForm fields and values:")

    for field in fields:
        field_name = field.get("FieldName", "")
        field_value = field.get("Value", "")
        field_type = field.get("Type", "")
        page_index = field.get("PageIndex", "")

        print(
            f"Page {page_index} | "
            f"{field_type} | "
            f"{field_name} => {field_value}"
        )

Run the script:

python fill_and_extract_fields.py

The script creates filled-f1040.pdf and prints the interactive fields and their current values.

Understanding fieldsString

The fieldsString parameter uses this format:

page;fieldName;value

Separate multiple fields with a vertical bar:

page;fieldName;value|page;fieldName;value

For example:

1;CustomerName;John Doe|1;Approved;true

The correct page number, field name, and accepted value depend on the source form. Use the PDF Forms Info Reader or the PDF.co PDF Edit Add Helper to inspect the available fields before filling them.

The PDF Add endpoint supports fieldsString as well as structured field objects.

Step 3: Important Differences Between the Examples

Searchable Text

A searchable PDF contains a text layer. Users can search for, select, and copy recognized text.

Interactive Form Fields

Interactive form fields are separate PDF objects with names, types, values, and coordinates. Examples include:

  • Text boxes
  • Checkboxes
  • Radio buttons
  • List boxes
  • Combo boxes

OCR does not create these objects. A scanned form can become searchable while still having no fillable fields.

If you need to add new interactive fields to a scanned form, that requires a separate form-field creation operation after OCR.

Temporary Output URLs

PDF.co returns temporary URLs for generated files. Download or transfer the output to permanent storage before the link expires.

Conclusion

You completed two PDF.co workflows in Python:

  • Applying OCR to make a scanned PDF searchable
  • Filling and extracting existing interactive form fields

Related Tutorials

See Related Tutorials