# PDF OCR: Scanned PDF & Image to Text, Searchable PDF (`tamatama/image-pdf-ocr`) Actor

PDF OCR for scanned PDFs and images: text per page, RAG chunks with page numbers, word boxes and a searchable PDF. Pages that already have text are read without OCR at a lower price; blank pages are free. Tesseract runs inside the Actor. From $1.20 per 1,000 OCR pages ($2 on Free).

- **URL**: https://apify.com/tamatama/image-pdf-ocr.md
- **Developed by:** [Otama Labs](https://apify.com/tamatama) (community)
- **Categories:** AI, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 ocr pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PDF OCR: Scanned PDF & Image to Text, Searchable PDF

**PDF OCR** and image OCR in one Actor, for developers building RAG and AI-agent pipelines, and for anyone who has to dig text out of scans: give this Actor links to **images or scanned PDFs** (PNG, JPEG, TIFF incl. multi-page, WebP, GIF, BMP, PDF) and it returns the **text of every page**, **RAG-ready chunks with page numbers**, optional **word boxes with confidence**, and an optional **searchable PDF** (grayscale page images with an invisible text layer).

**From $1.20 per 1,000 OCR pages** ($2 on the Free plan, less on paid plans). PDF pages that **already have text are read without OCR for $0.30 per 1,000**, and **blank pages and failures are free**. OCR runs with Tesseract inside the Actor: your files are not sent to a third-party OCR API.

### What you can use it for

- **RAG and AI agents**: scanned contracts, letters, receipts and old reports become text with page numbers, ready for a vector database.
- **Searchable archives**: turn a folder of scans into searchable PDFs that open in any PDF viewer.
- **Mixed PDFs**: a PDF where only some pages are scans is handled in one run; text pages are copied exactly and charged at the lower price.
- **Data entry**: word boxes (position and confidence) let you pick out fields such as totals and dates.

### Output example

The prefilled example (`phototest.tif` from the Tesseract test set), **Output format = Text** (one row per file):

```json
{
  "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif",
  "fileName": "phototest.tif",
  "fileType": "tiff",
  "pageCount": 1,
  "pagesProcessed": 1,
  "pagesOcr": 1,
  "pagesTextLayer": 0,
  "pagesBlank": [],
  "pagesFailed": [],
  "languages": "eng",
  "meanConfidence": 96.4,
  "text": "This is a lot of 12 point text to test the\nocr code and see if it works on all types\nof file format.\n\nThe quick brown dog jumped over the\nlazy fox. ...",
  "charCount": 285,
  "pages": [
    { "page": 1, "method": "ocr", "confidence": 96.4, "rotation": 0, "text": "This is a lot of 12 point text to test the\n..." }
  ],
  "searchablePdfUrl": null,
  "error": null,
  "processedAt": "2026-10-21T03:49:28.376303+00:00"
}
```

The same page turned sideways (`phototest-rotated-L.png`) comes back with the same text and `"rotation": 90`. A two-page PDF that already has text comes back with `"method": "text-layer"` on both pages and is charged as two `text-page` events.

With **Include word boxes**, each page also has `words`, e.g. `{ "text": "quick", "confidence": 95.9, "left": 102, "top": 194, "width": 75, "height": 30, "block": 1, "line": 1 }`. Positions are in pixels of the original image (for PDF pages: pixels at 300 DPI), measured on the page after its orientation was fixed.

### How to use

1. Put the files somewhere the Actor can download them (a public link, a pre-signed S3 or Cloud Storage URL, a direct Dropbox link, an Apify key-value store record) and list the links under **Image or PDF URLs**.
2. Pick the **Languages** of the text (English by default, up to 3 at once).
3. Optionally turn on **Create a searchable PDF** or **Include word boxes**, or choose **RAG chunks** as the output format.
4. Press **Start** and wait for the run to finish (seconds for a few images). Each file is one row in the run's dataset, which you can export in several formats or fetch over the API.

The prefilled example reads `phototest.tif`, a test image from the Tesseract project, and finishes in under a minute.

### Input

| Field | What it does |
|---|---|
| **Image or PDF URLs** | Links to images (PNG, JPEG, TIFF, WebP, GIF, BMP) or PDFs. The type is detected from the file content. Up to 50 MB per file. You can also link a text file that lists URLs (up to 1,000). |
| Languages | `eng` (default), `deu`, `fra`, `spa`, `por`, `ita`, `nld`, `pol`, `tur`, `rus`, `ukr`, `jpn`, `chi_sim`, `kor`. Up to 3 at once. |
| Output format | `text` (one row per file with a `pages` list) or `chunks` (one row per RAG chunk with `pageStart` / `pageEnd`). |
| Create a searchable PDF | Saves one PDF per file in the run's key-value store; the link is in `searchablePdfUrl`. No extra charge. |
| Include word boxes | Adds every word with its confidence (0-100) and pixel position to each page. |
| Fix page orientation | On by default: pages that are sideways or upside down are turned before OCR. |
| OCR pages that already have text | Off by default. Turn on if a PDF's existing text layer is wrong. |
| Max pages per file | 0 = all, up to 500. |
| Chunk size / Chunk overlap | For RAG chunks: maximum characters per chunk (default 2,000) and characters repeated from the previous chunk (default 200). |

### How it works

1. Each file is downloaded (at most one request per second to the same host; busy servers are retried twice).
2. PDF pages with a usable text layer are read directly. Other pages are rendered at 300 DPI; images are converted to grayscale, and small images (screenshots, thumbnails) are enlarged so small letters can be read.
3. Tesseract detects the orientation, then recognizes the text (LSTM engine). Each page gets a `method`: `ocr`, `text-layer`, `blank` or `failed`.
4. With a searchable PDF, OCR'd pages are rebuilt as image + invisible text and other pages are copied as they are, in the original order.

### Pricing

Pay per event:

| Event | Free plan | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| `ocr-page`: a page read by OCR that has text | $0.002 | $0.0018 | $0.0015 | $0.0012 |
| `text-page`: a PDF page read from its own text layer | $0.0003 | $0.0003 | $0.0003 | $0.0003 |

Plus Apify's tiny start fee of $0.00005 per GB of memory per run (the default 2 GB counts as two). Platform usage is included.

Examples on the Free plan: a 10-page scanned PDF costs $0.02. A 30-page PDF where 3 pages are scans costs 3 × $0.002 + 27 × $0.0003 = $0.0141. 1,000 receipts photographed with a phone cost $2.

Blank pages, pages OCR cannot process and files that cannot be downloaded are reported and **not charged**. If you give the run a spending limit, the Actor reads only as many pages as the limit covers and skips the remaining files.

### Limits

- OCR quality depends on the scan: clear printed text at 200-300 DPI works best. **Handwriting is not supported.** Low-contrast photos, decorative fonts and very small text give lower confidence (see `meanConfidence` and the per-word confidence).
- Layout is returned as text lines and paragraphs; tables come out as text lines, not Markdown tables.
- Up to 50 MB per file, 500 pages per file and about 100 megapixels per image (larger images are reported as an error). For very long documents the row keeps the full text and the per-page methods; the per-page texts are dropped (`pageTextsOmitted`) so the row fits the 9 MB dataset limit. OCR takes roughly a few seconds per page with the default 2 GB of memory; give the run more memory (4 GB = one full CPU core, 8 GB = two) to process pages in parallel.
- Password-protected PDFs are not supported. Vertical Japanese and Chinese text is not supported (horizontal only).
- The searchable PDF is built from grayscale page images, so colors are not kept. Keep the original if you need it.
- A PDF page that has only a short text layer (under 200 characters) on top of a picture, such as a scan with a watermark, is OCR'd rather than trusted.

### Data and privacy

OCR happens in the Actor's own container with Tesseract; no file, page image or text leaves your run for an outside OCR service. Nothing is fetched besides the links you list, and the text, word boxes and searchable PDFs are written only to your run's storage. Please OCR only files you are allowed to process.

### FAQ

**Why is a page empty?** OCR found no text on it (a blank or photo-only page). It is listed in `pagesBlank` and not charged.

**What does `meanConfidence` mean?** The average confidence Tesseract gives the words on the OCR pages (0-100). Values above 85 usually mean clean text; below 60, check the scan.

**How do I call it from code, an agent or a no-code tool?** Start a run through the Apify API with `{"urls": [...], "outputFormat": "chunks"}` and read the dataset; `run-sync-get-dataset-items` does both in one request for small batches. LangChain and LlamaIndex have Apify loaders that take the dataset rows directly. Make, n8n and Zapier have Apify modules, and AI agents can find and run the Actor through the Apify MCP server.

**Why did I get a `wordsUrl` instead of words in the row?** A dataset row is limited to about 9 MB. When a long document with word boxes would exceed that, the words are saved as a JSON record in the run's key-value store and the row links to it.

**Which OCR engine is used?** [Tesseract](https://github.com/tesseract-ocr/tesseract) (Apache-2.0) with the language data packaged by Debian.

### Related Actors by the same author

| Actor | What it does |
|---|---|
| [PDF to Markdown](https://apify.com/tamatama/doc-to-markdown) | Digital documents to Markdown and RAG chunks with headings and tables. Use it for PDFs that have text; use this Actor for scans. |
| [Website Change Monitor](https://apify.com/tamatama/website-change-monitor) | See what changed on a list of web pages since the last run. |
| [ATS Jobs](https://apify.com/tamatama/ats-jobs) | Every open job of chosen companies from their Greenhouse, Lever, Ashby and other job boards. |
| [RemoteOK & Jobicy Remote Jobs API](https://apify.com/tamatama/remote-jobs) | Remote jobs from two official APIs, with salary and source credit. |

### For AI Agents

An agent that meets a scan, a photo of a receipt or a PDF without a text layer can hand it to this Actor and get text back. There is no login and no API key of a third-party OCR service; the run is paid per page through Apify (pay per event) and uses limited permissions.

**Connect through the Apify MCP server** and expose just this Actor:

```json
{
  "mcpServers": {
    "pdf-ocr": {
      "url": "https://mcp.apify.com?tools=tamatama/image-pdf-ocr"
    }
  }
}
```

Sign in with OAuth when the client asks, or add the header `Authorization: Bearer <APIFY_TOKEN>`. The Actor then shows up as its own tool, `tamatama--image-pdf-ocr`, and the server adds `get-dataset-items` for paging through long results. Input an agent usually sends:

```json
{ "urls": [{ "url": "https://example.com/scan.pdf" }], "languages": ["eng", "deu"], "outputFormat": "text" }
```

Tips for agents: in the default text format each file row has `meanConfidence` (check it before trusting the text) and `pagesFailed` / `error` (read them when a row looks empty). Chunk rows (`outputFormat: "chunks"`) carry only the text and page range; page counts and `pagesFailed` per file are then in the `SUMMARY` record of the run's key-value store (`meanConfidence` is only in text rows). Set `searchablePdf: true` when the user wants a file back; the row then has a `searchablePdfUrl`.

**OpenAPI** for tool importers: `https://api.apify.com/v2/acts/tamatama~image-pdf-ocr/builds/default/openapi.json`. **One-request REST call**: `POST https://api.apify.com/v2/acts/tamatama~image-pdf-ocr/run-sync-get-dataset-items` with the JSON input.

# Actor input Schema

## `urls` (type: `array`):

Links to images (PNG, JPEG, TIFF incl. multi-page, WebP, GIF, BMP) or PDF files (scanned or mixed). The type is detected from the content, so links without an extension work. Up to 50 MB per file. You can also link a text file that lists URLs (up to 1,000), e.g. https://example.com/scans.txt.

## `languages` (type: `array`):

Languages of the text, up to 3 (more languages make OCR slower). English is used if empty.

## `outputFormat` (type: `string`):

Text: one dataset row per file with the full text and a list of pages (method, confidence, text). RAG chunks: one row per chunk with page numbers, ready for a vector database.

## `searchablePdf` (type: `boolean`):

Save one PDF per file with an invisible text layer over the page images (select and search the text in any PDF viewer). The link is in searchablePdfUrl. No extra charge.

## `includeWords` (type: `boolean`):

Add every recognized word with its confidence (0-100) and position (left, top, width, height in pixels of the original image; for PDF pages, pixels at 300 DPI; measured after the page orientation is fixed) to each page. Makes the output much larger. Text format only.

## `autoRotate` (type: `boolean`):

Detect pages that are upside down or sideways and turn them before OCR.

## `ocrAllPages` (type: `boolean`):

By default, PDF pages that already have a text layer are read directly (cheaper and exact). Turn on to OCR every page anyway, e.g. when the existing text layer is garbage.

## `maxPagesPerDocument` (type: `integer`):

Process only the first N pages of each PDF or multi-page TIFF. 0 = all (up to 500).

## `chunkSize` (type: `integer`):

Maximum characters per chunk (RAG chunks only). Chunks break at paragraphs first, then lines and sentences.

## `chunkOverlap` (type: `integer`):

Characters repeated from the end of the previous chunk (RAG chunks only). At most half of the chunk size.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
    }
  ],
  "languages": [
    "eng"
  ],
  "outputFormat": "text",
  "searchablePdf": false,
  "includeWords": false,
  "autoRotate": true,
  "ocrAllPages": false,
  "maxPagesPerDocument": 0,
  "chunkSize": 2000,
  "chunkOverlap": 200
}
```

# Actor output Schema

## `documents` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        {
            "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
        }
    ],
    "languages": [
        "eng"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tamatama/image-pdf-ocr").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": [{ "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif" }],
    "languages": ["eng"],
}

# Run the Actor and wait for it to finish
run = client.actor("tamatama/image-pdf-ocr").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    {
      "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
    }
  ],
  "languages": [
    "eng"
  ]
}' |
apify call tamatama/image-pdf-ocr --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tamatama/image-pdf-ocr"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/IYJQkEivcRKxq0idn/builds/9shfir8zLLyquWNhA/openapi.json
