# Image to Text OCR – Bulk Text Extraction, 100+ Languages (`gazidev/image-ocr`) Actor

Extract text from images in bulk with Tesseract 5 OCR: PNG, JPG, WebP, TIFF (multi-page), GIF, BMP, HEIC. 120+ languages, auto-rotation, dark-mode screenshots, small-text upscaling. Text, confidence, lines and words with bounding boxes, hOCR. $0.0025 per image.

- **URL**: https://apify.com/gazidev/image-ocr.md
- **Developed by:** [Cemal Atakli](https://apify.com/gazidev) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 5 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 image processeds

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 – Bulk Extract Text from Images (100+ languages)

Extract text from images in bulk: screenshots, receipts, scanned documents, photos of signs and labels, book pages, multi-page TIFF scans. Paste a list of image URLs and get back clean text for each image. You also get a **confidence score**, the **detected orientation**, word and line counts, and optionally **every line and word with its bounding box**, plus **hOCR**.

The Actor uses the open-source **Tesseract 5** OCR engine and its LSTM models. It reads **120+ languages**, including English, German, French, Spanish, Italian, Portuguese, Dutch, Turkish, Polish, Russian, Ukrainian, Arabic, Hindi, Chinese (Simplified and Traditional), Japanese and Korean. There is no browser and no third-party OCR API, so your images go to no one else, and the price is **$0.0025 per image ($2.50 per 1,000)**.

### What it does

- **Bulk image OCR from URLs:** PNG, JPEG, WebP, TIFF (also **multi-page TIFF**, one result per page), GIF, BMP, **HEIC/HEIF** (iPhone photos) and AVIF. `data:image/...;base64,` URIs work too.
- **120+ languages.** 17 languages are preinstalled. Any other Tesseract language (`ell`, `heb`, `tha`, `vie`, `swe`, `ces`...) is fetched automatically on first use. You can combine languages (`["eng","deu"]`), use ISO codes (`en`, `de`, `zh`, `ja`), or set `auto` to detect the script of each image.
- **Smart preprocessing that improves accuracy:**
  - **Auto-rotation.** Sideways and upside-down pages and photos are detected and fixed (90°/180°/270°), and EXIF orientation from phones is applied.
  - **Adaptive scaling.** The text height is measured first. Small text (1080p UI screenshots, low-resolution scans, thumbnails) is enlarged up to 3×, and huge photos with very large text are reduced.
  - **Dark-mode screenshots** (light text on a dark background) are inverted automatically.
  - Grayscale, contrast stretch, transparent backgrounds flattened to white, and optional black/white thresholding (Otsu) for noisy scans.
  - **Receipt-aware layout.** If the automatic layout skips a large region (typical for receipt prices next to a dark border), the image is re-read as one block and the better result is kept.
- **Quality signals for every image:** mean word confidence, character-weighted confidence, number of low-confidence words, rotation fixed, detected script, and the preprocessing steps that were applied.
- **Three output levels:**

  - `text`: the full text,
  - `lines`: also every line with its bounding box and confidence,
  - `words`: also every word with its box and confidence.

  Boxes are in pixels of the original image. Optional **hOCR** output is available for searchable-PDF or layout tools.
- **Robust bulk processing.** Downloads and OCR run in parallel, with size limits, retries with backoff, and timeouts. A broken URL, a non-image file or an OCR timeout becomes an error row (not charged) and never crashes the run.

### Use cases

- **Receipts and invoices:** turn photos of receipts into text for expense tools, bookkeeping or an LLM that extracts the totals. For PDFs and structured invoice fields (vendor, totals, VAT, line items), use [Document & Invoice to JSON](https://apify.com/gazidev/document-invoice-to-json).
- **Screenshots:** make app, chat, dashboard and social media screenshots searchable, or feed them to AI agents. Dark mode and small UI text are handled.
- **Scanned documents and archives:** digitize typewritten letters, book pages, old newspapers and multi-page TIFF scans from libraries and archives. You get text plus line boxes to build search indexes or searchable PDFs (hOCR).
- **E-commerce and marketing:** read text in product images, banners, packaging and labels (ingredients, lot numbers, sizes) at scale.
- **Compliance and moderation:** detect text in user-uploaded images, such as phone numbers, URLs, spam or prohibited words.
- **Data pipelines and RAG:** convert image folders (by URL) into text for embedding, classification or translation.

### Input example

```json
{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/5/55/A_text-book_of_agricultural_entomology_%28Page_192%29_BHL9798403.jpg",
    "https://example.com/receipts/IMG_0412.HEIC",
    "https://example.com/screenshots/settings-dark.png"
  ],
  "languages": ["eng", "deu"],
  "outputLevel": "lines",
  "includeHocr": false,
  "pageSegmentationMode": "auto",
  "autoRotate": true,
  "preprocessing": "auto",
  "upscaleSmallImages": true,
  "minWordConfidence": 0
}
```

The default input reads one public-domain book page from Wikimedia Commons in about 2 seconds.

| Field | Default | Notes |
|---|---|---|
| `imageUrls` | 1 sample page | Image URLs or `data:` URIs, one per line |
| `languages` | `["eng"]` | Tesseract codes (`eng`, `deu`, `chi_sim`...), ISO codes (`en`, `de`, `zh`), names, or `auto` |
| `outputLevel` | `text` | `text` / `lines` / `words` (bounding boxes + confidence) |
| `includeHocr` | false | Raw hOCR per image or page |
| `pageSegmentationMode` | `auto` | Or force Tesseract mode `3`, `4`, `6` (receipts, forms), `11` (sparse text), `7` (single line), `1` |
| `autoRotate` | true | Fix 90/180/270° rotation |
| `preprocessing` | `auto` | `threshold` adds black/white binarization; `none` uses the image as is |
| `upscaleSmallImages` | true | Adaptive scaling based on the measured text height |
| `minWordConfidence` | 0 | Drop words below this confidence (0–100) |
| `preserveInterwordSpaces` | false | Keep runs of spaces (column alignment) |
| `maxPagesPerImage` | 10 | Multi-page TIFF limit |
| `ocrAllAnimationFrames` | false | OCR every frame of animated GIF/WebP |
| `maxImageSizeMb` | 25 | Larger files are skipped (free) |
| `maxConcurrency` | 0 (auto) | Parallel OCR workers; auto = 1 per 4 GB of memory |

### Output example

One dataset row per image URL (multi-page TIFF: one row with a `pages` array). Real output (lines trimmed):

```json
{
  "url": "https://upload.wikimedia.org/wikipedia/commons/e/e2/Typewritten_letter_from_Dr_Claude_H_Organ_Jr_MD_FACS_to_Dr_Leonidas_Berry_dated_October_5_1965.jpg",
  "index": 0,
  "status": "ok",
  "text": "...October 5, 1965\n\nDear Doctor Berry:\n\nThanks very kindly fer your letter of\nSeptember 13th. I shall be en reute to the American\nCollege of Surgeons meeting in Atlantic City on\nOctober 17th. ...",
  "meanConfidence": 88.6,
  "weightedConfidence": 89.6,
  "wordCount": 106,
  "lineCount": 23,
  "charCount": 590,
  "lowConfidenceWords": 8,
  "languages": ["eng", "deu"],
  "rotation": 0,
  "imageFormat": "JPEG",
  "contentType": "image/jpeg",
  "width": 656,
  "height": 860,
  "fileSizeBytes": 52789,
  "pageCount": 1,
  "pagesProcessed": 1,
  "chargedEvents": 1,
  "preprocessing": ["grayscale", "autocontrast", "small text (~11 px lines): scaled x2.00"],
  "warnings": null,
  "processingSeconds": 2.23,
  "error": null,
  "lines": [
    {"text": "Dear Doctor Berry:", "confidence": 86.1, "bbox": {"x": 162, "y": 272, "width": 120, "height": 12}, "wordCount": 3, "block": 8}
  ]
}
```

- `meanConfidence` is the average Tesseract word confidence (0–100). `weightedConfidence` weights it by word length. Above 90 is usually near-perfect text. Below 60 means a hard image (handwriting, a heavy background, very low resolution).
- `rotation` is how many degrees (counter-clockwise) the text was turned. It was corrected automatically.
- With `outputLevel: "words"`, each word has `text`, `confidence`, `bbox` and `line` (an index into `lines`).
- Failed images have `"status": "failed"` and an `error` such as `HTTP 404 when downloading the image`, `Not a supported image... It is a PDF: use the Document & Invoice to JSON Actor` or `Image is 31.2 MB, above the 25 MB limit`. They are not charged.
- The key-value store record `OUTPUT` holds a run summary: images OK and failed, events charged, OCR seconds, and any URLs not processed because of the max-charge limit.

The Output tab has three views: **Extracted text** (with thumbnails), **OCR details** and **Failed images**. See `SAMPLE_OUTPUT.json` for full rows: a typewritten letter, a Swiss restaurant receipt photo, an article page and a 404 error.

### Pricing

Pay per event. You pay only for images that were OCRed.

| Event | Price |
|---|---|
| Image processed (per image, or per page of a multi-page TIFF) | **$0.0025** ($2.50 / 1,000) |
| Actor start | $0.00005 |

Very text-dense pages count once per started 1,000 recognized words, because OCR time grows with the amount of text. A full dense A4 page of about 1,100 words costs 2 × $0.0025. Screenshots, receipts, photos and normal document pages are under 1,000 words. An image where OCR found no text is still charged, because the OCR ran. Failed downloads, non-images and errors are free.

Compared with other Apify Store OCR Actors (public Store prices, 2026-10):

| Actor | Engine | Price per 1,000 images | Extra per run | Word boxes + confidence | Languages |
|---|---|---|---|---|---|
| **Image to Text OCR (this Actor)** | Tesseract 5 LSTM | **$2.50** | $0.00005 | Yes (lines, words, hOCR) | 120+ (17 preinstalled) |
| zenomastro/image-ocr-text-extractor | – | $5.00 | – | – | – |
| borderline/google-lens | Google Lens (browser) | $2.50 | $0.01 | No | Lens |
| zen-studio/google-lens-ocr | Google Lens | – | – | No | Lens |

Set **Maximum cost per run** in the run options to cap spending. The Actor reserves budget before each OCR, stops cleanly at the limit, never OCRs an image it cannot charge for, and lists the skipped URLs in `OUTPUT`.

**Speed tip:** at the default 1 GB of memory, one image is OCRed at a time (about 1–4 s per image). For thousands of images, run with 4–8 GB: that gives 1–2 parallel OCR workers per CPU core. The price per image does not change.

### FAQ

**How accurate is it?**
On clean printed text (screenshots, scans at 200–300 DPI, receipts photographed straight), nearly all words come out right. In our tests, such images scored a `meanConfidence` of 93–97, a 1899 book scan scored 94, and a 1965 typewritten letter scored 89. Phone photos with perspective or shadows, decorative fonts and very old documents are harder. Check `meanConfidence` and `lowConfidenceWords` per image, or filter with `minWordConfidence`. **Handwriting is not supported**: Tesseract is built for printed text.

**Which languages should I choose?**
Use the language or languages in your images, for example `["deu"]` for German receipts, because accents and umlauts (ä, ß, é, ğ, ş) are read correctly only with the right model. Mixed documents can use 2–3 languages (`["eng","fra"]`). `auto` detects the script of each image (Latin, Cyrillic, Arabic, Han, Japanese, Hangul, Devanagari, Greek, Hebrew, Thai...) and picks one model per script, with English for Latin. Set the exact language for the best results on accented Latin text.

**Does it OCR PDFs?**
No, this Actor reads images. For PDF, DOCX and scanned PDF pages (including OCR), plus invoice and receipt field extraction, use [Document & Invoice to JSON](https://apify.com/gazidev/document-invoice-to-json).

**Can it read text in photos, such as signs, packaging and memes?**
Yes, if the text is reasonably large and straight. For scattered text, set `pageSegmentationMode` to `11` (sparse text). Text that is strongly curved or perspective-distorted is hard for any OCR engine.

**How do I keep receipt columns aligned?**
Use `pageSegmentationMode: "6"` and `preserveInterwordSpaces: true`. The default `auto` mode already switches to single-block reading when it detects that amounts were skipped.

**Are my images stored or sent anywhere?**
Images are downloaded into the run container, OCRed locally with Tesseract, and discarded. Only the text results are saved to your dataset. No external OCR API is used.

**Why was an image charged as 2?**
It had more than 1,000 recognized words (see `chargedEvents`). Very dense pages take several times longer to OCR.

### Use with AI agents / Apify MCP

- **Apify MCP server:** add the Actor to Claude Desktop, Cursor, VS Code or any MCP client via `https://mcp.apify.com?actors=gazidev/image-ocr`. An agent can call it with `{"imageUrls":["https://.../screenshot.png"],"languages":["eng"]}` and get back the text and its confidence, so the agent can "read" images and screenshots even when it has no vision model or when vision tokens are expensive.
- **`data:` URIs:** agents that hold an image in memory can pass `data:image/png;base64,...` directly, with no upload needed.
- **API:** `POST https://api.apify.com/v2/acts/gazidev~image-ocr/run-sync-get-dataset-items?token=...` with the input JSON returns the rows directly (good for one or a few images).
- **Pipelines:** use `outputLevel: "lines"` to give LLMs layout context (line boxes), or pass the text to [Document & Invoice to JSON](https://apify.com/gazidev/document-invoice-to-json) for structured invoice fields.

### Limitations

- Printed text only. Handwriting gives low-confidence noise.
- Strong perspective, curved text and very stylized fonts reduce accuracy. No deskew beyond small angles.
- Images need a public URL (or a `data:` URI). URLs behind a login or anti-bot protection fail with a clear error (not charged).

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to images: PNG, JPEG, WebP, TIFF (multi-page too), GIF, BMP, HEIC/HEIF (iPhone photos) or AVIF. One per line. `data:image/...;base64,` URIs also work (handy for AI agents). PDFs are not images: use [Document & Invoice to JSON](https://apify.com/gazidev/document-invoice-to-json) for those.

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

Tesseract language codes of the text, e.g. `eng`, `deu`, `fra`, `spa`, `ita`, `por`, `nld`, `tur`, `pol`, `rus`, `ukr`, `ara`, `hin`, `chi_sim`, `chi_tra`, `jpn`, `kor` (preinstalled). ISO codes (`en`, `de`, `zh`, `ja`) and names (`German`) work too. Any other of the 120+ Tesseract languages (`ell`, `heb`, `tha`, `vie`, `swe`...) is downloaded automatically on first use. Use 1–3 languages that actually appear in the images. `auto` detects the script per image (Latin → English, Cyrillic → Russian, Arabic, Han → Chinese, Japanese, Korean, Devanagari → Hindi, Greek, Hebrew, Thai...).

## `outputLevel` (type: `string`):

`text`: the full text plus confidence and counts. `lines`: also every line with its bounding box and confidence. `words`: also every word with bounding box and confidence (largest output). Bounding boxes are in pixels of the original image.

## `includeHocr` (type: `boolean`):

Add the raw hOCR (HTML with layout and word boxes) produced by Tesseract, e.g. to build searchable PDFs or for layout tools. Coordinates in hOCR refer to the processed image (see `preprocessing`).

## `pageSegmentationMode` (type: `string`):

`auto` (recommended): automatic layout with orientation detection; if a large region was skipped (typical on receipts), it re-reads the image as one block and keeps the better result. Or force a Tesseract mode: `3` automatic, `4` single column of varying sizes, `6` one uniform block (receipts, forms, tables), `11` sparse text in no particular order (screenshots, signs, product photos), `7` a single text line, `1` automatic + orientation.

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

Detect and fix sideways or upside-down pages and photos. EXIF orientation from phones is always applied.

## `preprocessing` (type: `string`):

`auto`: grayscale, transparent background flattened to white, dark-mode screenshots inverted, contrast stretched. `threshold`: `auto` plus black/white binarization (Otsu), sometimes better for noisy or unevenly lit scans. `none`: the image as is.

## `upscaleSmallImages` (type: `boolean`):

Measure the text height first and enlarge small text (thumbnails, 1080p screenshots, low-resolution scans) up to 3x, or shrink huge photos with very large text, so Tesseract sees ~20–40 px lines. Usually raises accuracy a lot on screenshots.

## `minWordConfidence` (type: `integer`):

Drop words recognized with lower confidence from text, lines and words (0 = keep all). 50–60 removes most noise from photos and borders.

## `preserveInterwordSpaces` (type: `boolean`):

Keep runs of spaces in the text (helps keep receipt and table columns aligned).

## `maxPagesPerImage` (type: `integer`):

For multi-page TIFF files: OCR at most this many pages per file. Each page is billed as one image.

## `ocrAllAnimationFrames` (type: `boolean`):

By default only the first frame of an animation is read. On: each frame (up to the page limit) is OCRed and billed like a page.

## `maxImageSizeMb` (type: `integer`):

Larger downloads are stopped and reported as errors (not charged).

## `requestTimeoutSecs` (type: `integer`):

Per download attempt. Failed downloads are retried 3 times with backoff.

## `ocrTimeoutSecs` (type: `integer`):

A page that takes longer is reported as an error (not charged).

## `maxConcurrency` (type: `integer`):

0 = automatic: one worker per CPU core you get (Apify gives 1 core per 4 GB of memory). For big batches, run with 4–8 GB memory: it is several times faster for the same price per image.

## Actor input object example

```json
{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/5/55/A_text-book_of_agricultural_entomology_%28Page_192%29_BHL9798403.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/e/e2/Typewritten_letter_from_Dr_Claude_H_Organ_Jr_MD_FACS_to_Dr_Leonidas_Berry_dated_October_5_1965.jpg"
  ],
  "languages": [
    "eng"
  ],
  "outputLevel": "text",
  "includeHocr": false,
  "pageSegmentationMode": "auto",
  "autoRotate": true,
  "preprocessing": "auto",
  "upscaleSmallImages": true,
  "minWordConfidence": 0,
  "preserveInterwordSpaces": false,
  "maxPagesPerImage": 10,
  "ocrAllAnimationFrames": false,
  "maxImageSizeMb": 25,
  "requestTimeoutSecs": 45,
  "ocrTimeoutSecs": 180,
  "maxConcurrency": 0
}
```

# Actor output Schema

## `text` (type: `string`):

No description

## `details` (type: `string`):

No description

## `errors` (type: `string`):

No description

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

No description

## `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 = {
    "imageUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/5/55/A_text-book_of_agricultural_entomology_%28Page_192%29_BHL9798403.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/e/e2/Typewritten_letter_from_Dr_Claude_H_Organ_Jr_MD_FACS_to_Dr_Leonidas_Berry_dated_October_5_1965.jpg"
    ],
    "languages": [
        "eng"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gazidev/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 = {
    "imageUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/5/55/A_text-book_of_agricultural_entomology_%28Page_192%29_BHL9798403.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/e/e2/Typewritten_letter_from_Dr_Claude_H_Organ_Jr_MD_FACS_to_Dr_Leonidas_Berry_dated_October_5_1965.jpg",
    ],
    "languages": ["eng"],
}

# Run the Actor and wait for it to finish
run = client.actor("gazidev/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 '{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/5/55/A_text-book_of_agricultural_entomology_%28Page_192%29_BHL9798403.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/e/e2/Typewritten_letter_from_Dr_Claude_H_Organ_Jr_MD_FACS_to_Dr_Leonidas_Berry_dated_October_5_1965.jpg"
  ],
  "languages": [
    "eng"
  ]
}' |
apify call gazidev/image-ocr --silent --output-dataset

```

## MCP server setup

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