# Hebrew PDF & OCR Text Extractor (RTL-correct, עברית) (`vantum/hebrew-document-reader`) Actor

Extract clean Hebrew & English text from PDFs, scans, DOCX, images and web pages. Correct RTL order, OCR (heb+eng), Markdown, per-page. Failed files free.

- **URL**: https://apify.com/vantum/hebrew-document-reader.md
- **Developed by:** [vantum](https://apify.com/vantum) (community)
- **Categories:** AI, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 text pages

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

## Hebrew PDF & OCR Text Extractor (RTL-correct)

**Turn Hebrew PDFs, scanned documents, Word files, images and web pages into clean, correctly ordered text, ready for search, spreadsheets, translation or an LLM.**

Most PDF and OCR tools were built for left-to-right languages. On Hebrew they quietly break things. Punctuation jumps to the wrong end of the line, brackets come out backwards, numbers and English words land in the wrong place, and sometimes the whole line is reversed. This Actor was built and tested on real Israeli documents (Bank of Israel reports and Tel Aviv University and Hebrew University regulations) to fix exactly those problems.

| | Typical extractor output | **This Actor** |
|---|---|---|
| Section number | `.2.3 תואר "דוקטור לפילוסופיה" ( ).Ph.D` | `2.3. תואר "דוקטור לפילוסופיה" (Ph.D.)` |
| English in brackets | `קידום תשלומים מיידיים (,)Faster Payments` | `קידום תשלומים מיידיים (Faster Payments),` |
| Mirrored brackets (Acrobat PDFMaker) | `חילופי סטודנטים )פטורים(` | `חילופי סטודנטים (פטורים)` |
| Percentages | `מע"מ (%17)` | `מע"מ (17%)` |
| Scanned line read left-to-right by OCR | `.2.0 בגרסה PDF-ב Microsoft Word המערכת` | `המערכת Microsoft Word PDF-ב בגרסה 2.0.` |
| Legacy Windows-1255 text | `äñëí ùéøåú` | `הסכם שירות` |
| Hidden bidi characters | invisible `U+202B…U+202C` everywhere | removed |

### What it does

- 📄 **PDF with a text layer** is read directly. It's fast, exact and costs the least.
- 🖨️ **Scanned PDFs and photos** are read with **Tesseract 5 OCR** using the official Hebrew and English models. It decides **page by page**, so a PDF that mixes typed and scanned pages just works.
- 📝 **DOCX** (Word) files keep their headings, numbered and bulleted lists, and tables.
- 🌐 **Web pages**: the main content only, without menus, footers or scripts. Old ISO-8859-8 "visual Hebrew" pages are reversed into logical order.
- 🔤 **Text files** in UTF-8, UTF-16 or Windows-1255, with automatic encoding repair.
- ↔️ **RTL repair**: bidi control characters are removed, punctuation and bracket order is repaired, mirrored brackets are detected per document, and reversed visual text is detected and flipped.
- 🧾 **Output** is plain text or **Markdown** (headings, lists, tables, re-joined paragraphs), with **one row per document or one row per page**, plus optional .txt / .md files.
- 🏷️ **Each row also has** the language (`he`, `en`, `he+en`, `ar`, `ru` …), the text direction, the share of each script, OCR confidence and a list of the fixes applied.
- 💸 **Safe by design**: a dry run shows the cost first, there is a max-pages cap, the max run cost is respected, and **failed documents are never charged**.

Other OCR languages are available too: Arabic, Russian, Yiddish, French, German, Spanish, Italian and Portuguese, and combinations such as `heb+eng+ara` or `heb+eng+rus`.

### How to use it

1. Paste one or more document links into **Document URLs**, upload files from your computer, or pick an Apify **key-value store** whose records should be read (for example, files saved by another Actor). Links from Google Drive, Google Docs, Dropbox and GitHub are converted to direct downloads automatically.
2. Keep **OCR languages** on *Hebrew + English* unless your documents need more.
3. Click **Start**. Each document becomes one dataset row (or one row per page), which you can export as JSON, CSV, Excel, or read through the API.

> 💡 Not sure how much a big batch will cost? Turn on **Dry run** first. It counts text pages and scanned pages for each file and gives an estimated price, and nothing is charged.

#### Input example

```json
{
  "documents": [
    { "url": "https://www.example.co.il/reports/annual-report-2026.pdf" },
    { "url": "https://drive.google.com/file/d/FILE_ID/view" }
  ],
  "ocrLanguages": "heb+eng",
  "ocrMode": "auto",
  "outputFormat": "markdown",
  "maxPagesPerDocument": 50,
  "oneItemPerPage": false
}
```

#### Output example

This is a real result (shortened) for a Bank of Israel report:

```json
{
  "url": "https://boi.org.il/media/flpbnbte/…במזומן.pdf",
  "status": "ok",
  "detectedType": "pdf",
  "method": "text-layer",
  "pageCount": 16,
  "pagesProcessed": 3,
  "textPages": 3,
  "ocrPages": 0,
  "chars": 4745,
  "words": 777,
  "language": "he",
  "direction": "rtl",
  "scripts": { "hebrew": 0.997, "latin": 0.003 },
  "fixesApplied": ["bidi-controls-removed", "rtl-punctuation-reordered"],
  "text": "<!-- page 1 -->\n\nסקירת ההתפתחויות\nבשימוש במזומן\n\nבנק ישראל\n…\n\n<!-- page 2 -->\n…\nפתח דבר\nמאת מנהלת מחלקת המטבע\nהתמורות הטכנולוגיות הרבות שנכנסו לחיינו בשנים האחרונות הרחיבו את מגוון האפשרויות העומדות בפני הציבור בכל הקשור להתנהלותו בעולמות התשלומים. …",
  "billedTextUnits": 3,
  "billedOcrPages": 0,
  "warnings": ["Only the first 3 of 16 pages were processed (maxPagesPerDocument)."],
  "error": null
}
```

A failed document still gets a row that explains what went wrong, and it costs nothing:

```json
{ "url": "https://example.com/missing.pdf", "status": "failed", "chars": 0,
  "error": { "code": "NOT_FOUND", "message": "The server returned 404 Not Found." } }
```

Error codes: `NOT_FOUND`, `ACCESS_DENIED`, `BLOCKED_OR_NOT_A_DOCUMENT`, `TIMEOUT`, `NETWORK_ERROR`, `HTTP_ERROR`, `FILE_TOO_LARGE`, `UNSUPPORTED_TYPE`, `PDF_PASSWORD_PROTECTED`, `PDF_DAMAGED`, `IMAGE_UNREADABLE`, `NO_TEXT`, `OCR_FAILED`, `BUDGET_EXHAUSTED`.

### Pricing

You pay only for pages that were actually read:

| Event | What counts as one |
|---|---|
| **Text page** | A PDF page read from its text layer, or each started 3,000 characters of a DOCX, web page or text file |
| **OCR page** | A scanned PDF page or one image (or one frame of a multi-page TIFF) read with OCR |
| **Proxy megabyte** | Only if you turn on a proxy: each MB downloaded through it |

The current prices are shown on the **Pricing** tab. There is no start fee. Failed documents, empty pages and dry runs are free. **Max pages per document** and the run's maximum cost limit are always respected. When the limit is reached, the Actor stops cleanly and tells you so.

### Israeli government websites (gov.il, knesset.gov.il)

Many Israeli government sites only serve visitors from Israel. Everyone else gets an "Unavailable" web page instead of the PDF. The Actor detects this and returns `BLOCKED_OR_NOT_A_DOCUMENT` with a hint instead of extracting rubbish. To read these files, open **Proxy configuration**, choose **Residential** proxies and set the country to **Israel (IL)**.

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/vantum~hebrew-document-reader/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"documents":[{"url":"https://example.co.il/file.pdf"}],"outputFormat":"markdown"}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("vantum/hebrew-document-reader").call(run_input={
    "documents": [{"url": "https://example.co.il/file.pdf"}],
    "oneItemPerPage": True,  # one row per page, handy for RAG chunking
})
for page in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(page["page"], page["text"][:80])
```

It works with Make, Zapier, n8n, LangChain, LlamaIndex and the Apify MCP server like any other Apify Actor.

### Tips

- Use **Markdown** output for LLMs and RAG. Headings, lists and tables are kept, and hard-wrapped PDF lines are joined back into paragraphs.
- Use **One dataset row per page** for search indexes or page citations.
- If a PDF's text layer is broken (wrong letters or gibberish), set **When to use OCR** to *Always*.
- Use **Never OCR** when you only want the cheap text layer and don't care about scanned pages.
- **Remove niqqud** makes vocalised texts (poetry, prayer books, children's books) easier to search.
- Memory: OCR uses one CPU core per 4 GB. 2 GB is fine for most jobs. Give it 8–16 GB for big scanned batches so pages are OCRed in parallel.

### Limitations

- Handwriting is not supported. Tesseract reads printed text.
- On **scanned** pages, a line that mixes Hebrew and English words is the hardest case for any OCR engine. Word order is repaired, but individual mixed-script words can be misread more often than pure Hebrew or pure English. Text-layer PDFs, DOCX and web pages are not affected.
- Tables in text-layer PDFs come out one cell per line. Turn on **Preserve PDF layout** to keep the columns.
- These formats are reported as `UNSUPPORTED_TYPE` with a hint on how to convert them: legacy `.doc`, `.xlsx`, `.pptx`, `.odt`, ZIP archives and HEIC photos.
- Password-protected PDFs are reported as `PDF_PASSWORD_PROTECTED`.
- Pages that need JavaScript to render (single-page apps) may have no text in their HTML. Link to the document file itself instead.

### FAQ

**Is my data stored?** The files are processed inside your own Apify run, and the text is saved only to your run's dataset and key-value store. Nothing is sent to third-party AI or OCR APIs. Everything runs on open-source software inside the container.

**How accurate is the OCR?** On 300-dpi renders of real Hebrew reports and regulations, OCR output matched the original text layer at 95–99% word-sequence similarity in our tests (pages full of dot leaders, like tables of contents, score lower). Each page reports Tesseract's confidence in `ocrConfidence`, so you can flag weak scans.

**Does it handle Arabic too?** Yes. The RTL repair works for Arabic, and `ara` / `heb+ara` OCR models are included.

***

### בעברית

**חילוץ טקסט נקי ובסדר הנכון מקבצי PDF, סריקות, Word, תמונות ודפי אינטרנט בעברית.**

רוב כלי ה-PDF וה-OCR נבנו לשפות שנכתבות משמאל לימין, ובעברית הם משבשים את הטקסט. סימני פיסוק קופצים לצד הלא נכון, סוגריים מתהפכים, ומספרים ומילים באנגלית זזים ממקומם. הכלי הזה נבנה ונבדק על מסמכים ישראליים אמיתיים, והוא מתקן בדיוק את הבעיות האלה.

- קבצי PDF עם שכבת טקסט נקראים ישירות, ומסמכים סרוקים ותמונות עוברים זיהוי תווים (OCR) בעברית ובאנגלית. ההחלטה מתקבלת לכל עמוד בנפרד.
- קבצי Word ‏(DOCX) נקראים כולל כותרות, רשימות וטבלאות. מדפי אינטרנט נשלף רק התוכן עצמו, ודפי "עברית ויזואלית" ישנים מתוקנים.
- קידוד ישן (Windows-1255) מתוקן אוטומטית, ואפשר גם להסיר ניקוד וטעמים.
- הפלט הוא טקסט רגיל או Markdown, בשורה אחת לכל מסמך או לכל עמוד, ועם זיהוי שפה וכיוון כתיבה.
- משלמים רק על עמודים שנקראו בפועל. מסמכים שנכשלו והרצת ניסיון (Dry run) לא עולים כלום.
- אתרי ממשלה (gov.il, knesset.gov.il) חוסמים גלישה מחוץ לישראל. כדי לקרוא מהם, הפעילו פרוקסי Residential עם מדינה ישראל (IL).

### Open-source components

The Actor uses [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) and the official [tessdata](https://github.com/tesseract-ocr/tessdata) models (Apache-2.0), [Poppler](https://poppler.freedesktop.org/) utilities (GPL, called as separate programs), [python-docx](https://github.com/python-openxml/python-docx) (MIT), [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/) (MIT), [HTTPX](https://www.python-httpx.org/) (BSD), [Pillow](https://python-pillow.org/) (MIT-CMU) and the [Apify SDK](https://docs.apify.com/sdk/python) (Apache-2.0). See `THIRD_PARTY_LICENSES.md`.

# Actor input Schema

## `documents` (type: `array`):

Links to PDF (text or scanned), DOCX, images (JPG, PNG, TIFF, WEBP, GIF, BMP), web pages or .txt files. Google Drive, Google Docs, Dropbox and GitHub share links are converted to direct downloads automatically. You can also point to a text file with one URL per line.

## `uploadedFiles` (type: `array`):

Upload documents from your computer. They are stored in a key-value store and read from there.

## `keyValueStore` (type: `string`):

Pick one of your Apify key-value stores to extract every document stored in it (or only the keys listed below). Handy for files saved by other Actors or uploaded earlier. Read-only access.

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

Optional. Record keys to read from the store above. End a key with \* to match a prefix, e.g. invoice-\*. Leave empty to read all records.

## `ocrLanguages` (type: `string`):

Languages for OCR of scanned pages and images (Tesseract codes). Hebrew + English handles most Israeli documents. Pick the smallest set you need; extra languages make OCR slower and less accurate.

## `ocrMode` (type: `string`):

Auto decides page by page, so a PDF that mixes typed and scanned pages is read correctly. Images are always OCRed.

## `outputFormat` (type: `string`):

Markdown keeps headings, lists and tables from DOCX and web pages, and joins hard-wrapped PDF lines into paragraphs.

## `maxPagesPerDocument` (type: `integer`):

Only the first N pages of each PDF / multi-page TIFF are read (and charged). Protects you from surprise 900-page files.

## `oneItemPerPage` (type: `boolean`):

Off: one row per document. On: one row per page (with page number, method and OCR confidence), ideal for search indexes and RAG chunking.

## `includePages` (type: `boolean`):

Adds pages\[] (number, method, chars, OCR confidence, text) to each document row.

## `saveTextFiles` (type: `boolean`):

Saves the full text of each document to the key-value store and adds a download link (textFileUrl). Always done automatically for texts over 1 million characters.

## `preserveLayout` (type: `boolean`):

Keeps the physical layout of text-layer PDFs with spaces, which helps with tables and forms. Off gives clean reading-order text.

## `repairLegacyHebrewEncoding` (type: `boolean`):

Fixes gibberish like 'ùìåí' (Windows-1255 read as Latin-1) and reversed 'visual Hebrew' from old systems.

## `removeNiqqud` (type: `boolean`):

Strips Hebrew vowel points (ניקוד) and Torah cantillation marks so the text is easier to search.

## `keepBidiControlCharacters` (type: `boolean`):

Advanced. Off (recommended) removes invisible LRE/RLE/PDF/LRM/RLM marks and repairs punctuation and bracket order. On returns the raw extractor output untouched.

## `dryRun` (type: `boolean`):

Downloads each document, counts text and scanned pages and estimates the price, without extracting or charging anything.

## `maxDocuments` (type: `integer`):

Safety cap on the number of documents read in one run.

## `maxFileSizeMb` (type: `integer`):

Larger files are skipped with a FILE_TOO_LARGE error (not charged).

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

How long to wait for each download.

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

How many documents are downloaded and read at the same time. OCR itself uses one worker per CPU core (1 core per 4 GB of run memory).

## `proxyConfiguration` (type: `object`):

Usually not needed. Use it for sites that block foreign visitors: many Israeli government sites (gov.il, knesset.gov.il) only answer Israeli IPs, so choose Residential proxy with country Israel (IL). Proxy traffic is billed per megabyte.

## Actor input object example

```json
{
  "documents": [
    {
      "url": "https://boi.org.il/media/flpbnbte/%D7%A1%D7%A7%D7%99%D7%A8%D7%AA-%D7%94%D7%94%D7%AA%D7%A4%D7%AA%D7%97%D7%95%D7%99%D7%95%D7%AA-%D7%91%D7%A9%D7%99%D7%9E%D7%95%D7%A9-%D7%91%D7%9E%D7%96%D7%95%D7%9E%D7%9F.pdf"
    }
  ],
  "ocrLanguages": "heb+eng",
  "ocrMode": "auto",
  "outputFormat": "text",
  "maxPagesPerDocument": 10,
  "oneItemPerPage": false,
  "includePages": false,
  "saveTextFiles": false,
  "preserveLayout": false,
  "repairLegacyHebrewEncoding": true,
  "removeNiqqud": false,
  "keepBidiControlCharacters": false,
  "dryRun": false,
  "maxDocuments": 1000,
  "maxFileSizeMb": 50,
  "requestTimeoutSecs": 90,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `documents` (type: `string`):

One row per document or page.

## `quality` (type: `string`):

No description

## `allFields` (type: `string`):

No description

## `textFiles` (type: `string`):

No description

## `summary` (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 = {
    "documents": [
        {
            "url": "https://boi.org.il/media/flpbnbte/%D7%A1%D7%A7%D7%99%D7%A8%D7%AA-%D7%94%D7%94%D7%AA%D7%A4%D7%AA%D7%97%D7%95%D7%99%D7%95%D7%AA-%D7%91%D7%A9%D7%99%D7%9E%D7%95%D7%A9-%D7%91%D7%9E%D7%96%D7%95%D7%9E%D7%9F.pdf"
        }
    ],
    "maxPagesPerDocument": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("vantum/hebrew-document-reader").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 = {
    "documents": [{ "url": "https://boi.org.il/media/flpbnbte/%D7%A1%D7%A7%D7%99%D7%A8%D7%AA-%D7%94%D7%94%D7%AA%D7%A4%D7%AA%D7%97%D7%95%D7%99%D7%95%D7%AA-%D7%91%D7%A9%D7%99%D7%9E%D7%95%D7%A9-%D7%91%D7%9E%D7%96%D7%95%D7%9E%D7%9F.pdf" }],
    "maxPagesPerDocument": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("vantum/hebrew-document-reader").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 '{
  "documents": [
    {
      "url": "https://boi.org.il/media/flpbnbte/%D7%A1%D7%A7%D7%99%D7%A8%D7%AA-%D7%94%D7%94%D7%AA%D7%A4%D7%AA%D7%97%D7%95%D7%99%D7%95%D7%AA-%D7%91%D7%A9%D7%99%D7%9E%D7%95%D7%A9-%D7%91%D7%9E%D7%96%D7%95%D7%9E%D7%9F.pdf"
    }
  ],
  "maxPagesPerDocument": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call vantum/hebrew-document-reader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vantum/hebrew-document-reader"
        }
    }
}
```

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/SxYG6AvBHNw4QgI8E/builds/pPJbrSgEJbtwJsrEQ/openapi.json
