# OCR Image to Text: Extract Text from Images & PDFs (`ucchiii/ocr-image-text`) Actor

OCR for image URLs (PNG, JPEG, WebP, TIFF, GIF) and scanned PDFs, with built-in Tesseract. 8 languages incl. English, German, Japanese, Chinese. Text, confidence and line boxes. Empty input = free demo. $0.004 per image.

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

## Pricing

from $2.80 / 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

## OCR Image to Text — extract text from images and scanned PDFs

**For developers, analysts and AI/RAG pipelines that need the text inside images.** Give it public image URLs (PNG, JPEG, WebP, TIFF, GIF)
and optionally scanned PDF URLs, and get **one row per image** with the recognized text, language, confidence, word count and image size.
Runs the open-source **Tesseract OCR** engine inside the Actor: **no external OCR API, no API key, nothing to upload.**
**$0.004 per image read.** Leave the input empty for a free demo.

### Use cases

- Turn screenshots, photos of signs, receipts, invoices and slides into searchable text
- Read scanned PDFs (each page is rasterized and read as an image) before indexing them for search or RAG
- Add alt-text or keyword data to image libraries and product catalogs
- Get line-level bounding boxes to locate text in an image (`lines` layout)
- Pre-process a batch of image links from a scraper before sending the text to an LLM

### How it works

- Each URL is downloaded once. Images are converted to grayscale with contrast stretching and small images are upscaled (both can be turned off), then read with Tesseract.
- **Languages**: English, German, French, Spanish, Portuguese, Italian, Japanese and Simplified Chinese. Combine up to 4 (for example English + German). Fewer languages are faster and more accurate.
- **Scanned PDFs**: pages are rendered at 200 dpi and read one by one, up to `maxPdfPages` (default 5, max 50). Each page is one row with its `page` number and counts as one image for pricing.
- **Output layout**: `text` (plain text, paragraphs separated by a blank line) or `lines` (the same plus each line's text, bounding box and confidence).
- **Pay only for results**: an image or PDF page is charged only when at least one word was recognized. Failed downloads, unreadable files, password-protected PDFs and images without text are free. The free demo (empty input, two built-in sample images) is not charged.
- Safe by design: URLs that resolve to internal addresses (localhost, private ranges, link-local such as 169.254.169.254) are never contacted, including redirect targets (`blocked_private_address`). Only `http` and `https`, max 5 redirects, 30 s per download, size cap (default 10 MB, max 25 MB), images above 40 megapixels are skipped.

### Input

```json
{
  "urls": ["https://example.com/receipt.jpg", "https://example.com/scan.pdf"],
  "languages": ["eng", "deu"],
  "outputLayout": "text",
  "maxImageSizeMB": 10,
  "maxPdfPages": 5,
  "grayscale": true,
  "upscaleSmall": true
}
```

### Output

```json
{
  "url": "https://example.com/receipt.jpg",
  "page": null,
  "text": "Invoice No. 2026-0042\nTotal due: USD 1,234.50",
  "language": "eng+deu",
  "confidence": 93.4,
  "wordCount": 8,
  "width": 1000,
  "height": 220,
  "error": null
}
```

`confidence` is the mean word confidence from 0 to 100. `page` is `null` for images and the 1-based page number for PDFs.
With `"outputLayout": "lines"` each row also has `lines`: `[{"text": "Invoice No. 2026-0042", "left": 40, "top": 40, "width": 520, "height": 44, "confidence": 95.1}]`
(pixels of the original image).
`error` is e.g. `http_404`, `not_an_image`, `file_too_large`, `timeout`, `too_many_redirects`, `unreadable_image`, `image_dimensions_too_large`,
`unreadable_pdf`, `encrypted`, `ocr_timeout`, `blocked_private_address`, `invalid_url`. A failed file produces one row with empty text.
A `SUMMARY` record in the key-value store has the counts (rows, ok, errors, imagesCharged, words).

### Pricing

$0.004 per image read (pay per event, `image`). A scanned PDF costs $0.004 per page read. Example: 100 images cost $0.40, a 5-page scanned PDF $0.02.
Images without any recognized text and failed files are free. For comparison, other OCR Actors in the Apify Store charge roughly $0.003 to $0.005 per image or page.

### Limits and notes

- **Printed text works best.** Clean, horizontal, high-contrast text (documents, screenshots, signs, receipts) is read well. **Handwriting is not supported**, and stylized fonts, curved text, very low resolution and heavy noise give poor results. Check `confidence`.
- Tables and multi-column layouts are returned as lines in reading order, not as a structured table.
- Japanese and Chinese text is slower than Latin scripts. Pick only the languages you need.
- Only the files you list are downloaded; links inside them are not followed. Files behind a login return `http_401` or `http_403`.
- Only process images you are allowed to download. The text belongs to the rights holder of the image.

### More tools from the same developer

- [PDF Extractor](https://apify.com/ucchiii/pdf-extractor) — PDF to text, tables and metadata from public PDF URLs, page by page
- [RAG Chunker](https://apify.com/ucchiii/rag-chunker) — split scraped pages into chunks for RAG and vector stores
- [Website Screenshot API](https://apify.com/ucchiii/website-screenshot) — screenshots and PDFs of web pages: full page, mobile, element, no cookie banners
- [Google Sheets Export](https://apify.com/ucchiii/google-sheets-export) — export an Apify dataset to Google Sheets
- [Bulk URL Status Checker](https://apify.com/ucchiii/url-status-checker) — bulk HTTP status and redirect-chain checker for URL lists

# Actor input Schema

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

Public image URLs (http:// or https://; PNG, JPEG, WebP, TIFF, GIF first frame) and optionally scanned PDF URLs, for example 'https://example.com/scan.png'. Each file is downloaded once (size cap below, 30 s, up to 5 redirects). Up to 500 URLs per run. Leave empty to run a free demo on two built-in sample images (not charged).

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

Languages expected in the images (up to 4 are combined, for example English + German). Pick only the languages you need: fewer languages are faster and more accurate. Default: English.

## `outputLayout` (type: `string`):

'text' (default): the recognized text with line breaks and blank lines between paragraphs. 'lines': the same text plus a 'lines' array with the text, bounding box (left, top, width, height in pixels of the original image) and confidence of each line. Charging is the same in both modes.

## `maxImageSizeMB` (type: `number`):

Files larger than this are skipped with error 'file_too_large' (allowed 0.1 to 25, default 10). Images above 40 megapixels are also skipped.

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

Scanned PDFs are rasterized at 200 dpi and each page is read as one image. Only the first N pages of each PDF are processed (allowed 1 to 50, default 5). Each page read counts as one image for pricing.

## `grayscale` (type: `boolean`):

Convert to grayscale and stretch the contrast before reading. Helps with most photos and scans; turn off for very clean screenshots if results look worse.

## `upscaleSmall` (type: `boolean`):

Enlarge images whose longer side is under 1200 px (up to 3x) before reading. Small text is recognized much better after upscaling. Huge images are always scaled down to 5000 px.

## Actor input object example

```json
{
  "languages": [
    "eng"
  ],
  "outputLayout": "text",
  "maxImageSizeMB": 10,
  "maxPdfPages": 5,
  "grayscale": true,
  "upscaleSmall": true
}
```

# Actor output Schema

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

One item per image (and per PDF page): url, page, text, language, confidence, wordCount, width, height, error (and 'lines' with bounding boxes in 'lines' layout).

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

Record SUMMARY: rows, ok, errors, imagesCharged, words and whether this was the free demo.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("ucchiii/ocr-image-text").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("ucchiii/ocr-image-text").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 '{}' |
apify call ucchiii/ocr-image-text --silent --output-dataset

```

## MCP server setup

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

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/gjmniOk8nbMx3XMNV/builds/SNbraqDUhstX22Rd1/openapi.json
