# OCR Image to Text - Bulk Images, Screenshots & Scanned PDFs (`afterstar/image-ocr`) Actor

Reads the printed text in images, screenshots and scanned PDFs (every page) in 31 languages: clean text, confidence, and optionally every word with its box.

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

## Pricing

from $1.40 / 1,000 page reads

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

**Bulk OCR in your browser: paste links to images or PDFs (or upload a file), press Start, and download the text as CSV, Excel or JSON. $2.00 per 1,000 images or PDF pages read. Files that fail and pages without any text are free.**

### What you get back

One row per image or PDF page. Below is the tool's own example input (two test images from the Tesseract project, six languages picked), run on 13 October 2026, as returned:

| inputUrl | wordCount | meanConfidence | text (first lines) |
|---|---|---|---|
| .../tesseract-ocr/test/main/testing/phototest.tif | 60 | 96.1 | This is a lot of 12 point text to test the / ocr code and see if it works on all types / of file format. |
| .../tesseract-ocr/tessdoc/main/images/eurotext.png | 66 | 93.7 | The (quick) \[brown] {fox} jumps! / Over the $43,456.78 \<lazy> #90 dog / & duck/goose, as 12.5% of E-mail / from aspammer@website.com is spam. / Der „schnelle” braune Fuchs springt / über den faulen Hund. ... |

Both images took 7.8 seconds together. Languages matter: in the same run the Spanish "marrón rápido" came back as "marrön räpido" (the German letters mixed in), and a run with only English picked read the German "über" as "iiber". **Pick only the languages that are in your files** (31 are built in).

### How to OCR many images at once (no code)

1. Open the tool on Apify and sign in (a free Apify account; Google sign-in works).
2. In **Image or PDF links**, paste your links, one per line. Or give one link to a text file with a link per line (a Google Sheet published as CSV works), or upload one file from your computer.
3. Pick the **Languages** in your images.
4. Press **Start**. Rows appear file by file: an image as soon as it's read, a PDF's pages together when the PDF is done.
5. In the run's **Output**, click **Export** and choose **CSV** or **Excel** (also JSON, XML or HTML). You get one row per image or page, with its link, text, word count and confidence.

The links must be files anyone can download (not a Google Drive or Dropbox *preview* page). For files on your own computer, upload them one at a time, or put them somewhere public first.

### How to turn a scanned PDF into text, page by page

Paste the PDF's link like any image. Every page is rendered at 300 dpi and read, and each page becomes its own row with `page` and `pages` (page 3 of 6). Pages without any text are skipped and not charged. **Max pages per PDF** is 50 by default; raise it for longer documents. A scanned page takes about 5-15 seconds: a 6-page scanned newsletter and a 1-page scanned letter took 83 seconds together (see "Real runs" below).

If your PDF already has selectable text (it wasn't scanned), our [PDF Text Extractor](https://apify.com/afterstar/pdf-to-text) reads the text that's already in the file (with tables) instead of reading it from the page's pixels.

### Get the text into Excel, Google Sheets or a CSV

Export the run's output as **CSV** or **Excel** (step 5 above). In Google Sheets: File > Import > Upload the CSV. Each image or page is one row and its text is one cell. The tool reads text; it doesn't rebuild a table in an image into separate columns.

### Use it as an OCR API, or from n8n, Make and Zapier

Every run can also be started over Apify's API. This call reads an image and a PDF and returns the rows as JSON when it's done (put your own Apify API token in place of `YOUR_TOKEN`):

```bash
curl -X POST "https://api.apify.com/v2/acts/afterstar~image-ocr/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": [{"url": "https://example.com/scan1.png"}, {"url": "https://example.com/scan2.pdf"}], "languages": ["eng"]}'
```

Add `&format=csv` to the address to get CSV instead of JSON. A synchronous call waits at most 5 minutes; for big batches, start a run (`/runs` instead of `/run-sync-get-dataset-items`) and read its dataset when it finishes. Apify's n8n, Make and Zapier integrations run the tool the same way.

### What does OCR Image to Text do?

It reads the **printed text** in your images, screenshots and scanned PDFs with Tesseract 5 OCR and gives you clean text: lines and paragraphs kept, plus the word count and the mean confidence (0-100) for each image or page. Optionally you also get **every word with its confidence and its position** (a box in pixels), for highlighting, redaction or layout work.

Give it direct links (PNG, JPEG, WebP, TIFF including multi-page TIFF, BMP, GIF, PDF) or upload your own file. Scanned PDFs are read page by page at 300 dpi. 31 languages are built in.

### What you get

|  |  |
|---|---|
| **Reads** | Printed text in PNG, JPEG, WebP, TIFF (multi-page too), BMP, GIF and scanned PDFs, page by page at 300 dpi |
| **Input** | Direct links to files, or one file uploaded from your computer |
| **Per image or page** | The text with lines and paragraphs kept, word count, mean confidence (0-100), image size; optionally every word with its confidence and box |
| **Languages** | 31 built in, from English, German and Finnish to Russian, Arabic, Hindi, Japanese, Korean and Chinese |
| **Schedule** | 'Only new' mode skips links it has read before: they aren't downloaded or charged again |
| **Price** | $2.00 per 1,000 images or PDF pages read; failed files and pages without text are free |

### Real runs: what came back

These are our own test runs (5 October 2026) on public files. The numbers are what the tool returned, not picked or edited.

| File | What came back | Confidence | Time |
|---|---|---|---|
| A 6-page scanned 1985 USDA newsletter (PDF, [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Farm_broadcasters_letter_\(IA_CAT82764458066\).pdf)) plus Bill Gates' 1976 "Open Letter to Hobbyists" (1-page scanned PDF) | 6 rows, one per page with text: page 1 (a cover) 14 words, pages 3-6 386-498 words, 482 on the letter; the nearly blank page 2 was skipped and not charged | 94.4-96.3 | 83 s for all 7 pages |
| A screenshot of a Ukrainian government website (PNG, Ukrainian + English, "scattered text" layout) | 51 words: the menu and headings ("Написати звернення", "Подати петицію", "ПРЕЗИДЕНТ УКРАЇНИ"...) | 88 | 5 s |
| A Hindi test page (Tesseract's own test image) | 154 words of Devanagari | 86.3 | 7 s for both |
| A Hebrew text with vowel points | 60 words, many misread | 45.8 | (same run) |
| Three phone photos of shop receipts (Vienna, UK, Indonesia) | Vienna: 107 words, mostly garbled; UK: no text found (free row); Indonesia: card type and total read ("CARD TYPE DEBIT", "TOTAL Rp. 79,80…"), the date and header partly | 73.2 / - / 58.2 | 15 s for 3 |

What this tells you before you spend anything: **sharp scans and screenshots read well** (confidence 85-96), **phone photos
of receipts read only in part**, and text with diacritics or vowel marks (Hebrew niqqud) reads poorly. Check `meanConfidence`
in each row: below about 70, treat the text as a rough draft.

One row from the newsletter (page 3 of 6), as returned:

```json
{
  "inputUrl": "https://upload.wikimedia.org/wikipedia/commons/2/2a/Farm_broadcasters_letter_%28IA_CAT82764458066%29.pdf",
  "changeType": "new",
  "page": 3,
  "pages": 6,
  "text": "Letter No. 2239\n\nDAIRY PRICE\nSUPPORT\nEXTENDED\n\nWORLD WHEAT\n\nTRADE\n…\nSec'y of Agriculture John Block announced that the dairy price\nsupport provisions …",
  "wordCount": 445,
  "meanConfidence": 94.4,
  "width": 2475,
  "height": 3246,
  "words": null
}
```

### Use cases

- Turn scanned invoices, letters and contracts into text for search, accounting or an AI assistant.
- Read the text in screenshots, slides and product images.
- Make old scanned PDFs searchable, page by page.
- Feed a document pipeline: OCR in Apify, then Google Sheets, Make, Zapier or n8n.

### Input

| Field | What it does |
|---|---|
| Image or PDF links | Direct links to image files or PDFs, or a link to a text file with one link per line (a sheet published as CSV works too) |
| Or upload your own file | One image or PDF from your computer (stored in your own Apify account) |
| Languages | The languages in your images (default English). Pick only the ones you need: each one makes reading slower |
| Page layout | Automatic (documents, columns), one block, scattered text (screenshots, signs, labels) or a single line |
| Include every word with its box | Adds `words`: text, confidence and \[left, top, width, height] per word |
| Max pages per PDF | Default 50 (from the first page) |
| Max pages in total | Default 1,000 per run |

Languages: English, German, French, Spanish, Italian, Portuguese, Dutch, Polish, Czech, Swedish, Danish, Norwegian,
Finnish, Estonian, Latvian, Lithuanian, Hungarian, Romanian, Turkish, Russian, Ukrainian, Greek, Arabic, Hebrew, Hindi,
Japanese, Korean, Chinese (simplified and traditional), Vietnamese, Indonesian.

### Output

One row per image or PDF page (example above). `page` and `pages` are set for PDFs and multi-page TIFFs. Every row has
every key (`null` when there's no value). A file that can't be downloaded or opened gives a free row with
`changeType: "status"` and the reason (`file_failed`, `robots_disallowed`, `ocr_timeout`, `bad_input` for local or private addresses, `list_failed` / `list_empty` for a link list that can't be read or has no links); a file with no text at all gives
a free `no_text` row. With "Include every word with its box" on, `words` looks like this (from a real run):

```json
[{"box": [0, 9, 45, 9], "confidence": 92.6, "text": "nauris"}, {"box": [51, 6, 35, 12], "confidence": 96.8, "text": "vitae"}]
```

### How much does it cost?

- **$2.00 per 1,000 images or PDF pages read** (on paid Apify plans 10-30% less). A 20-page scanned PDF costs $0.04.
- Plus Apify's start fee: $0.00005 per run.
- Files that fail, pages without any text and status rows are free. Set a spending limit on the run and the tool stops there.
- You pay only this price, no separate Apify platform usage. Apify's free plan includes $5 of credit a month, enough for about 2,500 images or pages here.

### Run it on a schedule

Set **Output mode** to **Only new results** and give the same list of links each time (for example a list your own
system keeps adding to): links read before aren't downloaded or charged again. Each saved task keeps its own memory.

### Good to know

- How well OCR works depends on the image: sharp, straight scans at 200-300 dpi read best (confidence 90+). Photos at an
  angle, handwriting, tiny or decorative fonts read badly; Tesseract is made for printed text, not handwriting.
- Pick only the languages in your files. With several languages that share letters, accents can mix (Spanish
  'marrón' read as 'marrön' when German is also picked).
- A scanned page takes about 5-15 seconds; a screenshot or a short text, a second or two. Images larger than 6,000 px are
  scaled down; small screenshots are scaled up.
- Files up to 50 MB. The tool obeys robots.txt of the file hosts and refuses local or private network addresses.
- Text that's already in a PDF (not scanned) is read better by a PDF text extractor; this tool reads what it *sees*.
- The text comes back as it is in your file, so read only files you're allowed to process. The tool has no ID-card,
  passport or face features.

### How it compares

The three OCR tools people use most on the Store, from their own pages (read 9 October 2026). We haven't run them
side by side, so this is about what each one says it does and costs, not about accuracy.

|  | This tool | Google Lens OCR (zen-studio) | PDF Text Extractor (memo23) | Bulk OCR (nerolabs) |
|---|---|---|---|---|
| Engine | Tesseract 5, inside the tool | Google Lens (Google's service) | the PDF's own text, OCR for scanned pages (23 languages) | Tesseract, inside the tool |
| Price | $2.00 per 1,000 images or pages | $4.99 per 1,000 images | from $5.00 per 1,000 PDFs, $15.00 per 1,000 OCR pages | $5.00 per 1,000 OCR pages, $1.00 per 1,000 text pages |
| Reads | images, multi-page TIFF, scanned PDFs | images | PDFs (also password-protected) | images and PDFs |
| Input | links, a text file of links, or one upload | image links, HTTP API mode | links, upload, base64 | an Apify dataset, CSV, Excel or Google Sheet, keeping your columns |
| Uses the text already in a PDF | no, reads what it sees | - | yes | yes |
| Word boxes | yes (optional) | yes | - | - |
| Failed files | free | - | - | - |

Pick this tool for cheap, private OCR of images and scanned pages with word boxes. Pick memo23 or nerolabs if most of
your PDFs already contain text, or nerolabs if your links sit in a spreadsheet you want back with the text added.

### FAQ

**Which files can it read?** PNG, JPEG, WebP, TIFF (including multi-page TIFF), BMP, GIF and PDF. PDFs are read page by page at 300 dpi, and each page is one row.

**Does it read handwriting?** No. Tesseract is made for printed text. Handwriting, photos taken at an angle and decorative fonts read badly.

**How accurate is it?** Sharp, straight scans at 200-300 dpi read best, at a mean confidence of 90 or more, and every row gives its confidence. See "Real runs" above for what phone photos of receipts and Hebrew with vowel marks look like.

**My file failed with "403" or "file_failed". Why?** The site holding the file refused the download, or the link needs a login. The tool doesn't use proxies or log in anywhere, and it obeys robots.txt. You get a free status row with the reason; upload the file instead, or put it somewhere public.

**Am I charged when a file fails or can't be reached?** No. Files that can't be downloaded or opened, and pages with no readable text, give free rows. A nearly blank scanned page that reads as a stray mark or two is treated as no text, so it's free too.

**It's taking long. Will it finish?** A scanned page takes 5-15 seconds, so a 100-page PDF takes several minutes. The run keeps going until "Max pages in total" (default 1,000) and saves each file's rows when that file is done, so a stopped run keeps the files it already finished. A run with 7 scanned pages took 83 seconds.

**Should I use it for PDFs that already contain text?** No: text that's already in a PDF is read better by a PDF text extractor. This tool reads what it sees on the page.

**Can I give it a spreadsheet of links?** Paste the links, one per line, or link a text file of links (a Google Sheet published as CSV works too). Each link in it is read like a pasted one. A list that can't be read, or a web page instead of a list (like a sheet's normal edit link), gives a free status row saying so.

**Who sees my files?** The OCR runs inside the tool; no outside AI service sees your files. The text is stored in the run's dataset in your Apify account, under Apify's data retention.

**Source:** the files you provide. OCR by Tesseract 5 (Apache 2.0), run inside the tool; no outside AI service sees your files.

### More Afterstar tools

- [Website Screenshots - Bulk, Full Page & Visual Change Alerts](https://apify.com/afterstar/website-screenshots): Screenshots of many web pages (desktop or mobile, full page), and alerts when a page visually changes.
- [Audio Transcription & Speech to Text - Video, Podcasts, SRT](https://apify.com/afterstar/audio-transcriber): Turns audio and video files (your own uploads, direct file links, public podcast feeds) into text and subtitles (SRT/VTT) in ~99 languages, on the open-source Whisper model, run inside the tool (no API key).

Found a problem or need a language? Open an issue on the Issues tab.

# Actor input Schema

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

Direct links to images (PNG, JPEG, WebP, TIFF, BMP, GIF) or PDFs, or a link to a text file with one link per line (a sheet published as CSV works too). Scanned PDFs are read page by page.

## `file` (type: `string`):

Upload one of your own images or PDFs (it goes to a key-value store in your account).

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

The languages in your images. Pick only the ones you need: each extra language makes reading slower.

## `layout` (type: `string`):

How the text sits on the image. Automatic suits documents; 'scattered text' suits screenshots and photos.

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

Also list each word with its confidence (0-100) and position \[left, top, width, height] in pixels.

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

Read at most this many pages of each PDF (from the first page).

## `maxItems` (type: `integer`):

The most images and PDF pages read in one run.

## `outputMode` (type: `string`):

'All' lists everything found now. 'Only new' lists results never seen in earlier runs. 'New, changed and removed' also lists results that changed or disappeared. The first scheduled run counts everything as new; use 'Baseline only' to start cheaply.

## `stateKey` (type: `string`):

Leave empty: each saved task keeps its own memory. Set a name to share one memory between tasks, or a new name to start over.

## `resetState` (type: `boolean`):

Starts from an empty memory: every result counts as new again.

## `webhookUrl` (type: `string`):

We POST a summary plus up to 100 new, changed or removed results here when something changed. Works with Slack incoming webhooks (choose the Slack format), Zapier, Make and n8n.

## `webhookFormat` (type: `string`):

JSON for automation tools; 'Slack message' sends one line of text.

## `webhookAlways` (type: `boolean`):

By default the webhook is called only when something changed or a source failed.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
    },
    {
      "url": "https://raw.githubusercontent.com/tesseract-ocr/tessdoc/main/images/eurotext.png"
    }
  ],
  "languages": [
    "eng",
    "deu",
    "fra",
    "spa",
    "por",
    "ita"
  ],
  "layout": "auto",
  "includeWords": false,
  "maxPdfPages": 50,
  "maxItems": 1000,
  "outputMode": "all",
  "stateKey": "",
  "resetState": false,
  "webhookUrl": "",
  "webhookFormat": "json",
  "webhookAlways": false
}
```

# Actor output Schema

## `results` (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"
        },
        {
            "url": "https://raw.githubusercontent.com/tesseract-ocr/tessdoc/main/images/eurotext.png"
        }
    ],
    "languages": [
        "eng",
        "deu",
        "fra",
        "spa",
        "por",
        "ita"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("afterstar/image-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" },
        { "url": "https://raw.githubusercontent.com/tesseract-ocr/tessdoc/main/images/eurotext.png" },
    ],
    "languages": [
        "eng",
        "deu",
        "fra",
        "spa",
        "por",
        "ita",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("afterstar/image-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"
    },
    {
      "url": "https://raw.githubusercontent.com/tesseract-ocr/tessdoc/main/images/eurotext.png"
    }
  ],
  "languages": [
    "eng",
    "deu",
    "fra",
    "spa",
    "por",
    "ita"
  ]
}' |
apify call afterstar/image-ocr --silent --output-dataset

```

## MCP server setup

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