# Image to Text OCR: Images & Scanned PDFs, 80+ Languages (`4b47/image-pdf-ocr`) Actor

Extract text from images and PDFs in bulk: JPG, PNG, WebP, TIFF, screenshots, receipts and scanned PDF pages, in 80+ languages. PDF pages with a text layer are read exactly. Confidence and line boxes included. $2 per 1,000 images; failed files and images without text are free.

- **URL**: https://apify.com/4b47/image-pdf-ocr.md
- **Developed by:** [Kacper Gumieniuk](https://apify.com/4b47) (community)
- **Categories:** AI, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 image or scanned page ocr'ds

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

**Image to Text OCR extracts text from images and PDFs in bulk.** Give it URLs of JPG, PNG, WebP, TIFF, GIF, BMP or
AVIF images and PDF files. You get the text of each file with line breaks and paragraphs kept, a confidence score,
and optionally every line with its bounding box. **Scanned PDF pages are OCR'd; pages that already contain text are
read exactly** (no OCR errors, 7x cheaper). **80+ languages.**

**Try it now:** press **Start**. The prefilled input reads 3 files (a scan, a receipt photo and a scanned PDF) in under
a minute for about one cent. Price: **$2 per 1,000 images**, $0.30 per 1,000 text PDF pages. **Failed files and images
without text are free.** Apify's free plan ($5 of monthly credit) covers about **2,400 images a month**.

OCR runs on Tesseract 5's LSTM engine inside the actor. Your files go to no third-party OCR API and no Google service,
and nothing is kept after the run except your own dataset.

### Use cases

- **Receipts and invoices:** turn photos and scans into text for expense tools, bookkeeping or an LLM that extracts
  totals, dates and VAT (example and a ready n8n node below).
- **Scanned PDFs and archives:** make old letters, contracts, reports and books searchable; feed them to RAG pipelines.
- **Screenshots:** pull text out of app and website screenshots, error dialogs, slides, charts and memes.
- **Product images and labels:** read text from packaging, labels, menus and signs (use the *Sparse text* layout).
- **Mixed document dumps:** one run handles images, scanned PDFs and digital PDFs and charges each correctly.

### How to use Image to Text OCR

1. Paste file URLs into **Image or PDF URLs**, one per line (direct links to the file, not to a web page that shows
   it). Base64 `data:` URLs work too.
2. Set **Languages** to the languages in the text (English is the default; each extra language slows OCR down).
3. Press **Start**. Each file becomes one dataset item with its text.
4. Export to JSON, CSV or Excel, or read the dataset with the API. For big batches give the run more memory (8 GB = 4
   parallel OCR workers).

### Input

```json
{
  "urls": [
    "https://tesseract.projectnaptha.com/img/eng_bw.png",
    "https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg",
    "https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/main/tests/resources/skew.pdf",
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ],
  "languages": ["eng", "deu"]
}
```

| Field | What it does |
| --- | --- |
| `urls` | Up to 10,000 image or PDF URLs (25 MB each), or base64 `data:` URLs. |
| `languages` | Up to 5 languages present in the text, e.g. `eng`, `deu`, `fra`, `spa`, `pol`, `rus`, `ara`, `hin`, `jpn`, `kor`, `chi_sim`. Two-letter codes (`de`) work too. English, German, French, Spanish, Italian, Portuguese, Polish and Dutch are preinstalled. |
| `pdfMode` | `auto` (default): text layer where a page has one, OCR for scanned pages. `ocr`: OCR every page (for PDFs with a broken text layer). |
| `maxPdfPages` | Default 50 per PDF; later pages are skipped and not charged. |
| `includeLines` | Every line with confidence and `[x, y, width, height]` box in original pixels. |
| `minConfidence` | Results below this mean confidence count as "no text" (empty and free). |
| `pageSegmentation` | `auto`, `single-block` (one paragraph or a cropped region) or `sparse` (scattered text: signs, labels). |

### Output

One item per file. A real result:

```json
{
  "url": "https://raw.githubusercontent.com/naptha/tesseract.js/master/tests/assets/images/testocr.png",
  "type": "image",
  "format": "png",
  "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. ...",
  "wordCount": 60,
  "confidence": 95,
  "languages": ["eng", "deu"],
  "width": 640,
  "height": 480,
  "noTextFound": false,
  "bytes": 23359,
  "ms": 1510,
  "charged": { "ocr-page": 1 }
}
```

PDFs give one item with the whole text (pages marked `<!-- page N -->`) and a `pages` array:

```json
{
  "type": "pdf",
  "pageCount": 6,
  "pagesProcessed": 6,
  "confidence": 85,
  "pages": [
    { "page": 1, "method": "ocr", "text": "ELL, I got a good going-over in the morning, ...", "wordCount": 292, "confidence": 93 },
    { "page": 4, "method": "text-layer", "text": "...", "wordCount": 22 }
  ],
  "charged": { "ocr-page": 5, "pdf-text-page": 1 }
}
```

Failed files return `{ "url", "error": { "code", "message" } }` and are not charged. Codes: `unsupported_type` (e.g.
a link to an HTML page instead of the file), `bad_image`, `bad_pdf`, `too_large`, `target_http_404`,
`robots_disallowed`, `target_timeout`. The dataset has two views (**Text**, **Details**).

### Invoices and receipts in n8n, Make or Zapier

OCR gives you the text; a language model in your workflow turns it into fields. That split keeps the price at $0.002
per page and lets you use your own LLM key and prompt. Real result for a photographed Swiss restaurant receipt
(`https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg`, languages `deu` + `eng`, 1.5 s):

```json
{
  "type": "image",
  "confidence": 80,
  "text": "Berghotel\n\nGrosse Scheidegg\n5818 Grindelwald\n\nFamilie R. Müller\n\nRech. Nr. 4572 30.07. 2007/13 :29: 17\nBar Tisch 7/01\n\n2xLatte Macchiato 4,50\n1xGloki 5.00\n1xSchweinschnitzel 22. 00\n1xChässpätzli 18.50\n\nTotal; = CHE\n\nIncl, 68% Must 54.00 CHF! 32.88\n\nEntspricht in Euro 36.33 EUR\nEs bediente Sie: Ursula\n\nMwSt Nr. : 430 234\n..."
}
```

The text has typical OCR noise (`22. 00`, `CHE` for CHF). An LLM step repairs that easily when you ask for a fixed
JSON shape, e.g. `{ "vendor", "invoiceNumber", "date", "currency", "lineItems": [{ "quantity", "description",
"amount" }], "total", "vatId" }` with the instruction "use only values present in the text; null if missing".

**n8n template (n8n Cloud works, no Execute Command needed):** copy this JSON and paste it into the n8n canvas
(Ctrl/Cmd+V). It reads the file URL from the incoming item (`invoiceUrl`), waits for the OCR result and returns one
item with `text`. Put your Apify API token into the Authorization header (better: an n8n *Header Auth* credential),
then add your LLM node (OpenAI, Anthropic, Gemini, or n8n's *Information Extractor*) with the prompt above.

```json
{
  "nodes": [
    {
      "name": "OCR invoice (Apify)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [0, 0],
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/4b47~image-pdf-ocr/run-sync-get-dataset-items",
        "sendHeaders": true,
        "headerParameters": { "parameters": [{ "name": "Authorization", "value": "Bearer YOUR_APIFY_TOKEN" }] },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ urls: [$json.invoiceUrl], languages: ['eng', 'deu'] }) }}",
        "options": { "timeout": 300000 }
      }
    }
  ],
  "connections": {}
}
```

**Make:** module *Apify → Run an Actor* (actor `image-pdf-ocr`, *Run synchronously* on, input
`{"urls": ["{{1.invoiceUrl}}"]}`), then *Apify → Get Dataset Items* with the run's default dataset, then your LLM
module. **Zapier:** the Apify app's run-actor action with the same input, then read the run's dataset items.

PDF invoices from accounting tools usually have a text layer: those pages are read exactly (no OCR errors) for
$0.0003 per page.

### How much does OCR cost?

| Event | Price | Example |
| --- | --- | --- |
| Image or scanned PDF page OCR'd with text found | **$0.002** | 1,000 images = **$2** |
| PDF page read from its text layer | **$0.0003** | a 20-page digital PDF = $0.006 |
| Actor start (per GB of run memory) | $0.001 | default 4 GB run = $0.004 |
| Failed file, unsupported file, image without text, page over the limit | free | |

No per-file or per-PDF fees, and platform usage is included. Set a **maximum cost per run** and the actor stops there.

### Accuracy: what to expect

Tesseract is excellent on **scans, screenshots, printed documents and receipts photographed flat** (90-95% confidence
on clean scans in our tests). Photos are harder: the actor fixes EXIF rotation, converts to grayscale, stretches
contrast and resizes to an OCR-friendly size, and if a photo yields nothing it retries with sparse-text layout and
keeps only confident lines. Handwriting, heavy perspective, curved labels and stylized fonts are weak spots of every
Tesseract-based tool; check `confidence` and use `minConfidence` to drop low-quality results for free.

### FAQ

#### Which languages are supported?

80+: Latin, Cyrillic, Greek, Arabic, Hebrew, Devanagari and other Indic scripts, Thai, Chinese (simplified and
traditional), Japanese, Korean and more. Give only the languages present: each extra one slows OCR.

#### Is my data private?

Files are downloaded by the actor, processed in memory and not stored anywhere except the dataset in your Apify
account. No external OCR service is called. The actor respects robots.txt of the file's host.

#### Why did I get `unsupported_type`?

The URL returned a web page, not the file. Open the image or PDF itself in the browser and copy that address (it
usually ends in .jpg, .png or .pdf). Such errors are free.

#### Why is a PDF page empty?

It has no text layer and no image big enough to contain text (or OCR found nothing reliable). Empty pages are free.

#### How fast is it?

About 1-2 seconds per typical image per worker. Workers scale with memory (one per 2 GB, up to 4): give the run 8 GB
for 4 parallel workers on large batches.

#### Can I call it from code or an AI agent?

Yes: the Apify API (`run-sync-get-dataset-items` returns the text in one request), the JavaScript and Python clients,
or the Apify MCP server.

### Integrations and API

Export to JSON, CSV, Excel or HTML; connect Google Sheets, Make, Zapier, n8n or webhooks; schedule runs; call the actor
through the Apify API or the Apify MCP server.

### Related actors

- [URL to Markdown for LLM & RAG](https://apify.com/4b47/llm-ready-markdown): web pages and digital PDFs as
  clean Markdown with token counts.
- [Career Site Jobs Scraper](https://apify.com/4b47/career-site-jobs): jobs from Greenhouse, Lever, Workday
  and more.
- [Email Domain Validator](https://apify.com/4b47/domain-trust-checker): MX, disposable, SPF/DMARC and
  domain age checks.

# Actor input Schema

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

One per line, up to 10,000. Images: JPG, PNG, WebP, TIFF, GIF, BMP, AVIF (up to 25 MB). PDFs: pages with a text layer are read directly, scanned pages are OCR'd. base64 data: URLs work too. Files you can't reach without logging in won't work.

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

Languages of the text, most likely first (up to 5). Tesseract codes (eng, deu, fra, spa, ita, por, pol, nld, rus, ukr, ara, hin, jpn, kor, chi_sim, chi_tra, ...) or two-letter codes (en, de). Each extra language makes OCR slower; pick only the ones present. English, German, French, Spanish, Italian, Portuguese, Polish and Dutch are preinstalled; others download in a few seconds.

## `pdfMode` (type: `string`):

Auto: read the text layer where a page has one (exact, $0.0003/page) and OCR only scanned pages. OCR all: always OCR the page images (for PDFs with a broken or garbage text layer).

## `maxPdfPages` (type: `integer`):

Pages after this are skipped (and not charged).

## `includeLines` (type: `boolean`):

Add every text line with its confidence and box \[x, y, width, height] in original image pixels (for layout work, redaction, highlighting).

## `minConfidence` (type: `integer`):

Treat results below this mean confidence (0-100) as no text: the text is left empty and the image is not charged. 0 = keep everything.

## `pageSegmentation` (type: `string`):

Auto suits documents, receipts and screenshots. Single block helps with one paragraph or a cropped text region. Sparse finds scattered text (signs, labels, product photos, memes).

## `workers` (type: `integer`):

Parallel OCR engines. Default: one per 2 GB of run memory (max 4). Give the run more memory for more speed.

## Actor input object example

```json
{
  "urls": [
    "https://tesseract.projectnaptha.com/img/eng_bw.png",
    "https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg",
    "https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/main/tests/resources/skew.pdf"
  ],
  "languages": [
    "eng"
  ],
  "pdfMode": "auto",
  "maxPdfPages": 50,
  "includeLines": false,
  "minConfidence": 0,
  "pageSegmentation": "auto"
}
```

# Actor output Schema

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

One item per image or PDF: the text, confidence, and per-page details for PDFs. Failed files have an error field and are not charged.

# 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": [
        "https://tesseract.projectnaptha.com/img/eng_bw.png",
        "https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg",
        "https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/main/tests/resources/skew.pdf"
    ],
    "languages": [
        "eng"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("4b47/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": [
        "https://tesseract.projectnaptha.com/img/eng_bw.png",
        "https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg",
        "https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/main/tests/resources/skew.pdf",
    ],
    "languages": ["eng"],
}

# Run the Actor and wait for it to finish
run = client.actor("4b47/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": [
    "https://tesseract.projectnaptha.com/img/eng_bw.png",
    "https://upload.wikimedia.org/wikipedia/commons/0/0b/ReceiptSwiss.jpg",
    "https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/main/tests/resources/skew.pdf"
  ],
  "languages": [
    "eng"
  ]
}' |
apify call 4b47/image-pdf-ocr --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,4b47/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/O0ntVvqTxZzXEzEHL/builds/Ptigv5ArySqFRza7W/openapi.json
