# Document OCR | PDF to Markdown | Invoice, Table & Image to Text (`nidamindllc/doc-ocr`) Actor

Read PDF files and images and get the text as Markdown. Tables, headings, and reading order stay correct. 96.7% text accuracy on a 39-document test of receipts, forms, and reports. More than 100 languages. Pay per page.

- **URL**: https://apify.com/nidamindllc/doc-ocr.md
- **Developed by:** [Scott Shinn](https://apify.com/nidamindllc) (community)
- **Categories:** AI, Developer tools, Business
- **Features:** Limited permissions
- **Stats:** 19 total users, 7 monthly users, 88.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 page ocr'ds

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

## Document OCR API: PDF and Image to Markdown

This Actor reads PDF files and images. It gives you the text as Markdown. Tables stay as tables. Headings stay as headings. The text stays in the correct reading order.

You can use the output for search indexes, RAG pipelines, and data extraction.

### Accuracy

We use a vision-language OCR model that runs on our own GPU servers.

We tested the model on 39 real documents with known correct text:

| Document type | Documents | Text accuracy |
|---------------|-----------|---------------|
| Receipts | 12 | 97.5% |
| Forms | 12 | 98.3% |
| Mixed documents (reports, letters, tables) | 15 | 94.8% |
| **All documents** | **39** | **96.7%** |

Text accuracy is the percentage of words in the correct text that the OCR output also contains.

On the public OmniDocBench document parsing benchmark, the model scores 96.3 out of 100.

The average time for one page is approximately 9 seconds.

### How to use this Actor

1. Put one or more URLs in the `imageUrls` field. Each URL must point to a PDF file or an image.
2. If a PDF has many pages, set `maxPages` to limit the number of pages.
3. Start the Actor.
4. Get the results from the dataset.

Each URL must be public. The Actor cannot open files that need a login.

### Example

**Input:**

```json
{ "imageUrls": ["https://templates.invoicehome.com/invoice-template-us-neat-750px.png"] }
```

**Output** (part of one dataset item):

```markdown
### INVOICE

East Repair Inc.
1912 Harvest Lane
New York, NY 12210

INVOICE #  US-001
INVOICE DATE  11/02/2019
DUE DATE  26/02/2019
```

The Actor also returns the line items as a Markdown table:

| QTY | DESCRIPTION | UNIT PRICE | AMOUNT |
|-----|-------------|-----------|--------|
| 1 | Front and rear brake cables | 100.00 | 100.00 |
| 2 | New set of pedal arms | 15.00 | 30.00 |
| 3 | Labor 3hrs | 5.00 | 15.00 |

### Input

| Field | Type | Description |
|-------|------|-------------|
| `imageUrls` | array of strings | Required. The URLs of the PDF files and images. |
| `maxPages` | integer | Optional. The maximum number of pages to read from each PDF. `0` means no limit. |

### Output

You get one dataset item for each URL:

```json
{
  "url": "...",
  "ok": true,
  "numPages": 1,
  "markdown": "## INVOICE\n\nEast Repair Inc. ...",
  "pages": [{ "markdown": "...", "blocks": [] }]
}
```

| Field | Description |
|-------|-------------|
| `url` | The input URL. |
| `ok` | `true` if the Actor read the document. `false` if it did not. |
| `numPages` | The number of pages that the Actor read. |
| `markdown` | The text of all pages. A `---` line separates the pages. |
| `pages` | One object for each page. Each object has the Markdown of that page and its `blocks`. |
| `blocks` | The layout regions of the page. Each block has a type (for example, text, table, or title) and a bounding box. |
| `error` | The cause of the failure. This field is only present when `ok` is `false`. |

If one URL fails, the Actor writes an item with `ok: false` and continues with the next URL.

### Supported documents

- Invoices, receipts, and financial statements, with tables.
- Forms.
- Scanned pages and photos of documents.
- Pages with more than one column.
- Pages with mathematical formulas.
- Text in more than 100 languages, for example English, Spanish, Arabic, Hindi, Chinese, Japanese, and Russian.

Printed text gives the best results. Handwriting and low-quality scans give lower accuracy.

### Price

You pay for each page that the Actor reads:

- One image is one page.
- A PDF with 10 pages is 10 pages.

You do not pay for a URL that fails. There is no monthly fee.

### Limits

- The Actor reads one page at a time. A large batch takes more time, but the speed stays constant.
- Each URL must be public.
- A very large PDF can take a long time. Use `maxPages` to control the time and the cost.

# Actor input Schema

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

The URLs of the PDF files and images. Each URL must be public. The Actor reads each PDF page by page.

## `maxPages` (type: `integer`):

The maximum number of pages to read from each PDF. 0 means no limit.

## Actor input object example

```json
{
  "imageUrls": [
    "https://tesseract.projectnaptha.com/img/eng_bw.png"
  ],
  "maxPages": 0
}
```

# Actor output Schema

## `results` (type: `string`):

Markdown text, number of pages, and layout blocks for every URL processed.

# 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://tesseract.projectnaptha.com/img/eng_bw.png"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nidamindllc/doc-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://tesseract.projectnaptha.com/img/eng_bw.png"] }

# Run the Actor and wait for it to finish
run = client.actor("nidamindllc/doc-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://tesseract.projectnaptha.com/img/eng_bw.png"
  ]
}' |
apify call nidamindllc/doc-ocr --silent --output-dataset

```

## MCP server setup

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