# Image OCR: Image to Text, Arabic and 120 Languages (`maliksaid/image-ocr-text-extractor`) Actor

OCR for images: extract text from photos, screenshots and scanned pages with Tesseract. Bulk input from URLs or another Actor's dataset. Returns text, confidence, lines and optional word boxes or hOCR. Arabic right-to-left, English and 120 more languages. No outside OCR API.

- **URL**: https://apify.com/maliksaid/image-ocr-text-extractor.md
- **Developed by:** [Malik Said](https://apify.com/maliksaid) (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 $2.40 / 1,000 image 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

## Image OCR: Image to Text, Arabic and 120 Languages

Extract text from images and PDF files with Tesseract OCR. You give image or PDF URLs, a CSV or Google Sheets list of links, a dataset or a key-value store. You get one row per image or PDF page with the text, a confidence score and the text lines. Word boxes, hOCR and Markdown are optional.

Arabic, English and about 120 more languages work. Arabic and other right-to-left text comes out in reading order. OCR runs inside the Actor. Images never leave the run: no image is sent to an outside OCR service.

### What you get

Each row holds:

- `text`: all text in the image, line by line.
- `confidence`: mean word confidence from 0 to 100. `lowConfidence` is true when it is under 60.
- `droppedWordCount`: words left out by **Minimum word confidence**.
- `lines`: each line with its text, confidence, reading direction (`ltr` or `rtl`) and bounding box.
- `words` (optional): each word with its confidence and bounding box in pixels.
- `paragraphs` (optional): each paragraph with its text, confidence, reading direction and bounding box.
- `hocr` (optional): hOCR HTML with the full layout.
- `markdown` (optional): paragraphs in reading order, ready for an AI model or a search index. PDF pages start with `## Page N`.
- `preprocess`: the cleaning step used before OCR.
- PDF pages: `pageNumber`, `pageCount` and `textSource` (`ocr`, or `text_layer` when the page's own text was copied).
- `sourceItem` (optional): the dataset row or list row the image came from, so the text lines up with your own columns.
- `mainScript` and `direction`: the main writing system found (for example Latin or Arabic) and whether the page reads left to right, right to left or mixed.
- Image facts: format, width, height and file size.
- `source`: `url`, `keyValueStore`, `dataset`, `base64` or `list`. Rows from a list file carry `listRowIndex`. Rows from a dataset also carry `datasetId` and `datasetItemIndex` (the row's position, from 0). Base64 rows carry `base64Index`.
- `status` and `error`: images that cannot be read get a row with the reason. They are not charged.

### Use cases

- Read scanned letters, forms, receipts and invoices in bulk.
- Make screenshots and photos of signs searchable.
- Read Arabic and English documents from the Gulf and the Middle East.
- Feed image text into search, translation or an AI pipeline.

### Input

| Field | What it does |
|---|---|
| Image URLs | Links to images or PDF files, one per line. PNG, JPEG, WebP, BMP, GIF, TIFF, PNM and PDF work |
| Image list file | A link to a CSV or text file with image links, for example a Google Sheets CSV export. Every cell that starts with http is one image |
| Key-value store with image files | Pick one of your stores. The Actor reads every image record, or only the keys you list. It only reads the store |
| Dataset with image links | Pick a dataset, for example the output of another scraper. The Actor reads the image link from each row. It only reads the dataset |
| Link field in the dataset | The field with the link, for example `imageUrl` or `images.0`. Empty: the first of `url`, `imageUrl`, `image`, `src`, `displayUrl`, `thumbnailUrl` with a link. A list of links gives one image each |
| Keep the source row | Copies the dataset or list row into `sourceItem` (up to 10 KB) |
| Images as base64 | Images as base64 text or data URLs, for images with no public link. Up to 8 MB of base64 text per run. Each row gets `base64Index` |
| Maximum PDF pages | Pages read per PDF. Default 10. Set 0 for every page |
| PDF render DPI | Resolution for scanned pages. Default 150 |
| Use the PDF's own text | Copies the text of digital pages as is, without OCR. Default on |
| Languages | Every language in the images. Use English and Arabic for bilingual documents. Default: English |
| Model | Fast (default) or Accurate. Accurate is a little better and about 1.6 times slower |
| Page layout | Automatic, single column, single block, single line, single word or sparse text |
| Keep spaces between words | Keeps table-like layouts aligned in each line |
| Clean images before OCR | Off, Auto, Grayscale or Black and white. Auto fixes transparent images and enlarges small text |
| Minimum word confidence | Drops weaker words from text, lines, words and paragraphs. Default 0 keeps every word |
| Include lines, word boxes, paragraphs, hOCR, Markdown | Choose how much layout data each row carries |
| Maximum image size | Skips files above this size. Default 20 MB |
| Maximum images | Stops after this many images. Default 100. Set 0 for no limit |

Example input:

```json
{
    "imageUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/5/50/Double_sentence-spaced_typewriter_text_vs._single-spaced_printed_text.jpg"
    ],
    "languages": ["eng", "ara"],
    "includeWords": false
}
```

Example input for an image you hold in memory, with cleaning and a word filter:

```json
{
    "imagesBase64": ["data:image/png;base64,iVBORw0KGgo..."],
    "preprocess": "auto",
    "minWordConfidence": 60,
    "includeParagraphs": true
}
```

Example input that reads images another Actor scraped:

```json
{
    "datasetId": "YOUR_DATASET_ID",
    "datasetUrlField": "imageUrl",
    "languages": ["eng"]
}
```

### Output example

This row comes from a test image with Arabic and English text, read with languages `ara` and `eng`. Lines and words are shortened.

```json
{
    "status": "ok",
    "source": "keyValueStore",
    "keyValueStoreKey": "ar-udhr",
    "format": "png",
    "imageWidth": 800,
    "imageHeight": 400,
    "languages": ["ara", "eng"],
    "model": "fast",
    "text": "يولد جميع الناس أحراراً متساوين في الكرامة والحقوق. وقد وهبوا عقلاً\nوضميراً وعليهم أن يعامل بعضهم بعضاً بروح الإخاء.\n\nفاتورة رقم 2048 بتاريخ 21 أكتوبر 2026. المبلغ الإجمالي 1,250 ريال.\n\nInvoice total: SAR 1,250. Thank you.",
    "confidence": 91,
    "lowConfidence": false,
    "droppedWordCount": 0,
    "mainScript": "Arabic",
    "direction": "mixed",
    "wordCount": 36,
    "lineCount": 4,
    "lines": [
        {
            "text": "فاتورة رقم 2048 بتاريخ 21 أكتوبر 2026. المبلغ الإجمالي 1,250 ريال.",
            "confidence": 93,
            "direction": "rtl",
            "bbox": { "x0": 85, "y0": 139, "x1": 770, "y1": 171 }
        }
    ],
    "words": [
        { "text": "يولد", "confidence": 92, "bbox": { "x0": 737, "y0": 37, "x1": 770, "y1": 62 }, "lineIndex": 0 }
    ]
}
```

### OCR images from a spreadsheet

Keep your image links in Google Sheets? Publish the sheet as CSV (File > Share > Publish to web > CSV) and paste the link in **Image list file**. Turn on **Keep the source row** to get each row's other columns, such as a SKU, next to its text.

```json
{
    "imageListUrl": "https://docs.google.com/spreadsheets/d/e/YOUR_SHEET/pub?output=csv",
    "keepSourceFields": true,
    "includeMarkdown": true
}
```

### Use it from the API or an AI agent

Send base64 images and get the text back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/maliksaid~image-ocr-text-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"imagesBase64": ["data:image/png;base64,iVBORw0KGgo..."], "includeMarkdown": true}'
```

AI agents can call this Actor through the Apify MCP server (mcp.apify.com) with the same input.

### Pricing

You pay per image read, plus a small fee per run.

Each PDF page counts as one image. The start fee is charged once per GB of memory (the default is 1 GB).

| Event | Free plan | GOLD plan and higher |
|---|---|---|
| Run start | $0.002 | $0.002 |
| Image read | $0.003 ($3.00 per 1,000) | $0.0024 ($2.40 per 1,000) |

| Images in one run | Free plan | GOLD plan and higher |
|---|---|---|
| 100 | $0.302 | $0.242 |
| 1,000 | $3.002 | $2.402 |

Costs include the run start fee.

- Images that fail (not found, not an image, blocked by robots.txt) are saved with the reason and not charged.

Platform usage is included in the price.

### Speed

One page-sized scan takes about 2 to 20 seconds at the default 1 GB of memory. Apify gives more CPU to more memory, so 2 GB should be about twice as fast. The price per image stays the same. The default timeout is one hour.

### Tips for good results

- List every language in the image. Tesseract does not guess the language. The `mainScript` field helps you pick the right one.
- More languages make OCR slower. Use only the ones you need.
- Text should be at least about 20 pixels high. Very small or blurred text gives low confidence.
- Use "Sparse text" for photos, signs and screenshots with scattered words.
- Transparent images, photos and small text read better with **Clean images before OCR** set to Auto.
- Every row has `lowConfidence`. Use it to find weak images fast, and **Minimum word confidence** to drop noise words.
- Handwriting is not supported well. Tesseract reads printed text.

### Responsible use

- The Actor only reads the images you list. It reads robots.txt on each host first and skips images that it does not allow.
- It does not log in anywhere and does not pass CAPTCHAs.
- Make sure you have the right to process the images you submit, especially images with personal data.

### Engine and licences

- OCR engine: Tesseract 5 through tesseract.js 7.0.0 (Apache-2.0).
- PDF reading: pdf.js 6.4.299 (Apache-2.0) and @napi-rs/canvas 1.0.10 (MIT).
- Language models: the official Tesseract repositories tessdata_fast and tessdata (Apache-2.0), at pinned versions.

### FAQ

**Can it read PDFs?** Yes. Scanned and digital PDFs are read page by page, one row per page, up to **Maximum PDF pages** (default 10). Digital pages are copied from the PDF's own text. Password-protected PDFs are skipped free.

**Is my image sent to another service?** No. Tesseract runs inside the Actor. Images and PDFs are read only inside your run.

**Can I OCR the images another Actor scraped?** Yes. Pick that run's dataset in "Dataset with image links". Name the link field, or leave it empty to detect it. Each row's `datasetItemIndex` points back to the source row.

**Which language codes can I use?** The Languages list in the input shows all of them, for example `eng` English, `ara` Arabic, `fas` Persian, `urd` Urdu, `fra` French and `chi_sim` Chinese.

**Why is a row's status "failed"?** The `error` field says why: for example HTTP 404, a file that is not an image, or a host whose robots.txt does not allow the URL.

# Actor input Schema

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

Links to the images to read, one per line. PNG, JPEG, WebP, BMP, GIF, TIFF and PNM work. The Actor reads robots.txt on each host and skips images it does not allow. Leave empty to read only the key-value store below.

## `imageListUrl` (type: `string`):

Optional. A link to a CSV or text file with image links, for example a Google Sheets CSV export link (File > Share > Publish to web > CSV). Every cell that starts with http is read as one image. Reading stops at Maximum results.

## `keyValueStoreId` (type: `string`):

Optional. Pick one of your key-value stores that holds uploaded image files. The Actor only reads this store.

## `keyValueStoreKeys` (type: `array`):

Optional. Read only these records of the store. Leave empty to read every image record in the store.

## `datasetId` (type: `string`):

Optional. Pick a dataset, for example the output of another scraper. The Actor reads the image link from each row. It only reads the dataset.

## `datasetUrlField` (type: `string`):

The field that holds the image link, for example imageUrl. Empty: the Actor uses the first of url, imageUrl, image, src, displayUrl, thumbnailUrl that holds a link. Arrays of links give one image each.

## `keepSourceFields` (type: `boolean`):

Copy the dataset row or list file row each image came from into the sourceItem field (up to 10 KB), so the text lines up with your own columns, such as a SKU.

## `imagesBase64` (type: `array`):

Optional. Images as base64 text or data URLs (data:image/png;base64,...). Use this when the image has no public link, for example from an API or an AI agent. Up to 8 MB of base64 text per run; entries after that get a free failed row. For larger batches, upload the images to a key-value store and pick it above.

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

PDF files are read page by page, one row per page. Each page is charged like one image. 0 reads every page.

## `pdfDpi` (type: `integer`):

Resolution for scanned PDF pages. Higher reads small text better but takes longer.

## `usePdfTextLayer` (type: `boolean`):

A digital PDF page with real text is copied as is, which is exact and fast. Turn off to OCR every page.

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

Languages in the images. Pick every language that appears, for example English and Arabic for bilingual documents. Each extra language makes OCR slower.

## `model` (type: `string`):

Fast uses the tessdata_fast models. Accurate uses the standard tessdata models, made from tessdata_best. They are a little more accurate and about 1.6 times slower.

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

How Tesseract splits the image into text areas. Automatic suits most pages. Sparse text finds scattered words in photos and screenshots.

## `preserveSpacing` (type: `boolean`):

Keep runs of spaces in the text. This keeps table-like layouts aligned in each line.

## `preprocess` (type: `string`):

Clean the image before OCR. Auto puts transparent images on a plain background, turns them grey and enlarges small text. Black and white also removes light noise. Off by default.

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

Drop words below this confidence (0 to 100) from text, lines, words and paragraphs. 0 keeps every word. The confidence field still reports the mean of all words.

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

Add each text line with its confidence, reading direction and bounding box.

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

Add each word with its confidence and bounding box in pixels. This makes rows much larger.

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

Add the hOCR (HTML with layout and boxes) for each image.

## `includeParagraphs` (type: `boolean`):

Add each paragraph with its text, confidence, reading direction and bounding box.

## `includeMarkdown` (type: `boolean`):

Add a markdown field: paragraphs in reading order, one blank line apart. PDF pages start with a ## Page N heading. Useful for AI and search.

## `maxImageMegabytes` (type: `integer`):

Skip images larger than this. Big photos need more memory.

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

Stop after this many images are read. Set 0 for no limit.

## Actor input object example

```json
{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/5/50/Double_sentence-spaced_typewriter_text_vs._single-spaced_printed_text.jpg"
  ],
  "keyValueStoreKeys": [],
  "datasetUrlField": "",
  "keepSourceFields": false,
  "imagesBase64": [],
  "maxPdfPages": 10,
  "pdfDpi": 150,
  "usePdfTextLayer": true,
  "languages": [
    "eng"
  ],
  "model": "fast",
  "pageSegmentation": "auto",
  "preserveSpacing": false,
  "preprocess": "none",
  "minWordConfidence": 0,
  "includeLines": true,
  "includeWords": false,
  "includeHocr": false,
  "includeParagraphs": false,
  "includeMarkdown": false,
  "maxImageMegabytes": 20,
  "maxItems": 100
}
```

# 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 = {
    "imageUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/5/50/Double_sentence-spaced_typewriter_text_vs._single-spaced_printed_text.jpg"
    ],
    "languages": [
        "eng"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("maliksaid/image-ocr-text-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 = {
    "imageUrls": ["https://upload.wikimedia.org/wikipedia/commons/5/50/Double_sentence-spaced_typewriter_text_vs._single-spaced_printed_text.jpg"],
    "languages": ["eng"],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("maliksaid/image-ocr-text-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 '{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/5/50/Double_sentence-spaced_typewriter_text_vs._single-spaced_printed_text.jpg"
  ],
  "languages": [
    "eng"
  ],
  "maxItems": 100
}' |
apify call maliksaid/image-ocr-text-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maliksaid/image-ocr-text-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/uk7efa4bctCcvihai/builds/8NVmUELD6AOIFHPC9/openapi.json
