# PDF & Image OCR Text Extractor (Scanned PDF to Text) (`cyuli/pdf-ocr-extractor`) Actor

Extract text from PDFs and images. Reads the text layer of digital PDFs and runs OCR on scanned pages, photos and screenshots in 20 languages. Per-page text, confidence scores, page ranges, Google Drive and Dropbox links. From $0.001 per page.

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

## Pricing

from $4.00 / 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.

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

### What does PDF & Image OCR Text Extractor do?

**PDF & Image OCR Text Extractor** pulls the text out of **PDF files, scanned documents, photos and screenshots**. Give it one or many file URLs and it returns clean text for every page, ready for spreadsheets, search, LLMs and RAG pipelines.

It's smart about cost and accuracy:

- 📄 **Digital PDFs** (exported from Word, invoices, reports): the embedded text layer is read directly. It's exact and costs only **$0.001 per page**.
- 🖨️ **Scanned PDFs, images and photos**: pages without a text layer go through **OCR (Tesseract 5)** in **19 languages**, for **$0.004 per page**.
- 🔀 **Mixed documents** are handled page by page automatically, so you never pay OCR prices for pages that already have text.

Supports **PDF, PNG, JPG/JPEG, TIFF (multi-page), WEBP, BMP and GIF**. Public **Google Drive, Dropbox and OneDrive** share links are converted to direct downloads automatically. No API keys or setup needed.

### Why use this PDF to text converter?

- 💸 **Cheap**: $0.001 per digital page, $0.004 per OCR page, platform usage included. 1,000 scanned pages cost $4.
- 🎯 **Confidence scores** for every OCR page, so you can flag low-quality scans automatically.
- ✂️ **Page ranges** like `1-3, 7, 10-` and a per-file page limit to keep costs under control.
- 🧾 **No charge for failures**: broken links, web pages and unreadable files are free.
- 🔒 **Private**: documents are processed inside your Apify run, never sent to a third-party OCR API.
- 🔁 **Automation-ready**: API, schedules, webhooks, **n8n, Make, Zapier**, and AI agents through the Apify MCP server.

### Use cases

- **Invoice, receipt and contract processing**: get the text, then parse fields with an LLM or regex
- **Digitize scanned archives** and make them searchable
- **Feed documents into ChatGPT, Claude or a RAG / vector database** (use "One dataset item per page" for easy chunking)
- **Extract text from screenshots and photos** of whiteboards, menus, labels and signs
- **Bulk-convert PDF reports** into text or CSV for analysis

### How much does it cost?

| Page type | What happens | Price per page |
|---|---|---|
| PDF page with a text layer | Text read directly, exact | **$0.001** |
| Scanned PDF page or image | OCR with Tesseract 5 | **$0.004** |

You're billed only for pages that are processed. Apify's free plan includes monthly credits, enough for hundreds of OCR pages for free.

### How to extract text from a PDF or image

1. Click **Try for free** / **Start**.
2. Paste your file links into **PDF or image URLs**.
3. Pick the **OCR languages** used in your documents (e.g. English + Spanish).
4. Optionally set **Pages** (e.g. `1-5`) and the **OCR mode**.
5. Click **Start** and download the results as **JSON, CSV, Excel or HTML**, or grab the `.txt` file of each document from the run's key-value store.

#### OCR modes

- **Auto** (recommended): text layer when available, OCR only for scanned or image-only pages.
- **Always**: OCR every page, even if it has a text layer (useful when the embedded text is garbled).
- **Never**: text layer only, the cheapest option for digital PDFs.

### Input

```json
{
    "fileUrls": [
        "https://example.com/invoice-2026-001.pdf",
        "https://www.dropbox.com/s/abc123/scan.jpg?dl=0"
    ],
    "ocrMode": "auto",
    "languages": ["eng", "spa"],
    "pages": "1-3",
    "maxPagesPerFile": 500,
    "outputOnePagePerItem": false
}
```

### Output

One item per file (or per page if **One dataset item per page** is on):

```json
{
    "url": "https://example.com/invoice-2026-001.pdf",
    "status": "succeeded",
    "fileType": "pdf",
    "pageCount": 3,
    "processedPages": 3,
    "ocrPages": 1,
    "textLayerPages": 2,
    "averageOcrConfidence": 94.6,
    "wordCount": 812,
    "text": "INVOICE No. 2026-001\nBill to: ...",
    "textUrl": "https://api.apify.com/v2/key-value-stores/.../records/text-1.txt",
    "pages": [
        { "page": 1, "method": "text-layer", "ocrConfidence": null, "charCount": 2310, "text": "INVOICE No. 2026-001 ..." },
        { "page": 2, "method": "ocr", "ocrConfidence": 94.6, "charCount": 1804, "text": "..." }
    ]
}
```

Failed files come back with `"status": "failed"` and a clear `error` message, so one bad link never breaks a batch.

### Supported OCR languages

English, Spanish, Portuguese, French, German, Italian, Dutch, Polish, Russian, Ukrainian, Turkish, Arabic, Hindi, Chinese (Simplified and Traditional), Japanese, Korean, Vietnamese and Indonesian. Text-layer extraction works for any language.

### Use it from code

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("cyuli/pdf-ocr-extractor").call(run_input={
    "fileUrls": ["https://example.com/scan.pdf"],
    "languages": ["eng"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["text"])
```

### FAQ

**Does it keep the layout or tables?**
It returns reading-order text with line breaks and paragraphs. Tables come out as text rows; it does not rebuild table structure.

**Does it read handwriting?**
Tesseract is designed for printed text. Neat block handwriting sometimes works, cursive usually doesn't.

**What about password-protected PDFs?**
Encrypted PDFs that need a password to open are reported as failed and not charged.

**How fast is it?**
Digital PDF pages take milliseconds. OCR takes a few seconds per page; give the run more memory to speed up large batches.

**My scan is sideways. What should I do?**
Enable **Detect rotated pages**.

### Feedback

Need another language, table extraction or a different output format? Open an issue in the **Issues** tab.

# Actor input Schema

## `fileUrls` (type: `array`):

Direct links to PDF files or images (PNG, JPG, TIFF, WEBP, BMP, GIF). Multi-page TIFFs are supported. Public Google Drive, Dropbox and OneDrive share links are converted to direct downloads automatically.

## `ocrMode` (type: `string`):

"auto" reads the embedded text of digital PDFs (exact and cheap) and runs OCR only on scanned or image-only pages. Images are always OCRed.

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

Languages present in the documents. Pick all that appear (e.g. English + Spanish). Fewer languages is faster and more accurate.

## `pages` (type: `string`):

Optional page selection, 1-based, e.g. "1-3, 7, 10-". Leave empty for all pages.

## `maxPagesPerFile` (type: `integer`):

Safety limit: only the first N selected pages of each file are processed and billed.

## `ocrDpi` (type: `integer`):

Resolution used to render scanned PDF pages for OCR. 300 is the best balance; use 400 for tiny print.

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

Detect page orientation and script before OCR. Enable for sideways or upside-down scans. Slightly slower.

## `includePages` (type: `boolean`):

Add a "pages" array with the text, method and OCR confidence of every page.

## `outputOnePagePerItem` (type: `boolean`):

Output each page as a separate dataset item instead of one item per file. Handy for spreadsheets and RAG chunking.

## `maxFileSizeMb` (type: `integer`):

Files larger than this are skipped without charge.

## Actor input object example

```json
{
  "fileUrls": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ],
  "ocrMode": "auto",
  "languages": [
    "eng"
  ],
  "pages": "",
  "maxPagesPerFile": 500,
  "ocrDpi": 300,
  "autoRotate": false,
  "includePages": true,
  "outputOnePagePerItem": false,
  "maxFileSizeMb": 200
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `files` (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 = {
    "fileUrls": [
        "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cyuli/pdf-ocr-extractor").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 = { "fileUrls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("cyuli/pdf-ocr-extractor").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 '{
  "fileUrls": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ]
}' |
apify call cyuli/pdf-ocr-extractor --silent --output-dataset

```

## MCP server setup

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

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/oMNoSlCQHrwZiQkMg/builds/JqFYk3mP3juf8btzo/openapi.json
