# PDF & Document to Markdown: OCR, Tables, RAG Chunks (`vimplement/document-to-markdown`) Actor

Convert PDFs, scanned images, Word, PowerPoint, Excel, CSV and HTML into clean Markdown or text with tables, OCR for scanned pages (12 languages preinstalled) and token-sized chunks for RAG and LLM pipelines.

- **URL**: https://apify.com/vimplement/document-to-markdown.md
- **Developed by:** [Victor Berg](https://apify.com/vimplement) (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 $4.00 / 1,000 document extracteds

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

## PDF & Document to Markdown: OCR, Tables, RAG Chunks

Turn **PDFs, scanned documents, images, Word, PowerPoint, Excel, CSV and HTML** into clean **Markdown or plain text** – with **tables**, **OCR for scanned pages** and **token-sized chunks for RAG and LLM pipelines**. Paste document URLs or upload files, then get one clean JSON item per document.

- **Markdown that keeps the structure** – headings, paragraphs, bullet and numbered lists, and tables in reading order. Multi-column PDF pages are read column by column.
- **Tables** – detected in PDFs and returned separately as Markdown and CSV (and kept in the Markdown).
- **OCR only where needed** – pages without a text layer (scans, photos, image-only PDFs) are read with Tesseract; normal text pages are not OCR'd and not charged for OCR. 12 languages preinstalled (English, Norwegian, Swedish, Danish, Finnish, German, French, Spanish, Italian, Portuguese, Dutch, Polish); other Tesseract languages are downloaded automatically.
- **RAG-ready chunks** – optional chunks of ~N tokens with overlap that keep headings, paragraphs and tables together, each with its page range and section heading.
- **Pay only for what works** – a failed document is returned with its error and never charged.
- **Private processing** – downloaded content is processed in memory during the run; private and internal network addresses are refused. Uploaded files and output stay in your Apify storage according to its retention settings.

### Use cases

- **RAG and AI agents**: feed PDFs, reports, manuals and policies into embeddings and vector databases.
- **Document automation**: pull text and tables out of invoices, statements, price lists and reports.
- **Scanned archives**: make scanned PDFs and images searchable.
- **Content migration**: convert Word/PowerPoint/HTML to Markdown for docs sites and knowledge bases.

### Input

| Field | Default | What it does |
|---|---|---|
| `urls` | – | Public document URLs (PDF, PNG/JPG/TIFF, DOCX, PPTX, XLSX, CSV, TXT/MD, HTML). The type is detected from the file itself. |
| `files` | – | Upload files in the input form, or pass Apify key-value-store record URLs. Use alone or with `urls`; duplicate links are converted once. |
| `outputFormat` | `markdown` | `markdown`, `text` or `both`. |
| `ocr` | `auto` | `auto` (only pages without text), `always`, `off`. |
| `ocrLanguages` | `["eng"]` | Tesseract codes, e.g. `["eng", "nor"]`. |
| `pageRange` | all | e.g. `1-5,8,10-`. |
| `maxPages` | 200 | Pages per document. |
| `extractTables` | `true` | Return tables as Markdown and CSV. |
| `includePages` | `true` | Add per-page text. |
| `chunkSize` / `chunkOverlap` | 0 / 100 | Chunks for RAG, in tokens (0 = no chunks). |
| `maxFileSizeMb` | 50 | Bigger files are skipped (not charged). |
| `maxConcurrency` | 2 | Documents in parallel. |

```json
{
  "urls": ["https://www.nhc.noaa.gov/data/tcr/AL022023_Arlene.pdf"],
  "outputFormat": "markdown",
  "ocr": "auto",
  "ocrLanguages": ["eng"],
  "chunkSize": 500,
  "chunkOverlap": 50
}
```

### Output

One item per document:

```json
{
  "url": "https://arxiv.org/pdf/1706.03762",
  "status": "ok",
  "documentType": "pdf",
  "fileName": "1706.03762",
  "pageCount": 15,
  "pagesExtracted": 15,
  "ocrPages": 0,
  "language": "en",
  "wordCount": 6012,
  "markdown": "# Attention Is All You Need\n\nAshish Vaswani ...\n\n## Abstract\n\nThe dominant sequence transduction models ...",
  "pages": [{ "page": 1, "text": "...", "ocr": false, "ocrConfidence": null }],
  "tables": [{ "page": 8, "index": 0, "rows": 9, "columns": 5, "markdown": "| Model | BLEU ... |", "csv": "Model,BLEU..." }],
  "chunks": [{ "index": 0, "text": "# Attention Is All You Need ...", "tokens": 498, "pageStart": 1, "pageEnd": 2, "section": "Abstract" }],
  "metadata": { "title": "...", "author": "...", "created": "..." },
  "sha256": "…",
  "warnings": null
}
```

A failed document: `{ "url": "...", "status": "error", "error": "download failed with HTTP 404" }` – not charged.

### Pricing

Pay per event – you pay only for results:

| Event | Price |
|---|---|
| Document (successful document) | **$0.004** |
| OCR page (only pages that needed OCR) | **$0.008** |
| Actor start | $0.002 |

1,000 text PDFs cost about $4; a 10-page scanned PDF costs $0.084. Set a **maximum cost per run** in the run options: the Actor stops cleanly when it is reached and tells you which documents were skipped.

### FAQ

**Does it work on scanned PDFs?** Yes. With `ocr: auto`, every page without a text layer is OCR'd; text pages are extracted directly.

**Which languages does OCR support?** 12 are preinstalled; any other Tesseract language code (e.g. `jpn`, `chi_sim`, `ara`, `hin`) is downloaded on first use in the run.

**How are tables handled?** PDF tables are detected from ruling lines and cell layout and returned as Markdown and CSV. Spreadsheet sheets and CSV files become tables directly. Word and HTML tables come through the Markdown.

**Can I use it from AI agents?** Yes – call it through the Apify API, the Apify MCP server, or Claude's Apify connector, and pass `chunkSize` to get embedding-ready chunks.

**Is my data stored?** Downloaded content is processed in memory during the run. Uploads are records in a key-value store you choose: temporary storage expires according to your Apify retention settings, while named permanent storage stays until you delete it. Converted output is saved in your run dataset. Deleting a run does not delete an upload from a separate named store.

### Limits

- Password-protected PDFs cannot be read. Very complex layouts (heavy multi-column magazines, math-heavy formulas) are approximations.
- OCR quality depends on the scan; the per-page `ocrConfidence` (0–100) helps you spot weak pages.
- Document links must be public (no website logins). Uploaded files must be readable from the run’s Apify account and permissions. If a temporary upload expires, upload it again.

### Legal and privacy

Process only documents you are allowed to use. Private and internal network addresses are refused. The Actor does not keep a separate document copy. Uploads and converted output remain in your Apify storage as described above.

# Changelog

This Actor's version history is a separate document: https://apify.com/vimplement/document-to-markdown/changelog.md

# Actor input Schema

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

Public links to the documents to convert: PDF (text or scanned), PNG/JPG/TIFF images, DOCX, PPTX, XLSX, CSV, TXT/Markdown and HTML pages. The file type is detected from the file itself, so links without an extension work too. Leave empty if you upload files below. The example is an 11-page public-domain NOAA hurricane report with headings and tables.

## `files` (type: `array`):

Upload documents from your computer instead of, or as well as, links. Apify keeps each upload in a key-value store you choose: temporary storage is deleted after your data retention period, permanent storage stays until you delete it. Same file types and price as links.

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

Markdown keeps headings, lists and tables (best for LLMs and RAG). Text is plain text. Both returns both fields.

## `ocr` (type: `string`):

Auto reads only pages without a text layer (scans) with OCR. Always runs OCR on every page. Off never runs OCR. OCR'd pages are charged per page.

## `ocrLanguages` (type: `array`):

Tesseract language codes, e.g. eng, nor, swe, dan, fin, deu, fra, spa, ita, por, nld, pol (preinstalled). Other Tesseract languages (e.g. jpn, chi_sim, ara) are downloaded automatically. Use several for mixed documents.

## `pageRange` (type: `string`):

Optional pages to extract, 1-based: e.g. '1-5,8,10-'. Empty = all pages (up to the maximum below).

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

Extraction stops after this many pages of each document.

## `extractTables` (type: `boolean`):

Detect tables in PDFs and return each as Markdown and CSV in the 'tables' field (also kept in the Markdown).

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

Add a 'pages' list with the text of each page and whether it was OCR'd.

## `chunkSize` (type: `integer`):

Split the document into chunks of about this many tokens for embeddings and RAG, keeping headings, paragraphs and tables together. 0 = no chunks.

## `chunkOverlap` (type: `integer`):

Tokens repeated from the end of one chunk at the start of the next (only with a chunk size).

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

Larger files are skipped with an error (not charged).

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

How many documents are processed at the same time. Raise the run memory for higher values.

## Actor input object example

```json
{
  "urls": [
    "https://www.nhc.noaa.gov/data/tcr/AL022023_Arlene.pdf"
  ],
  "outputFormat": "markdown",
  "ocr": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "maxPages": 200,
  "extractTables": true,
  "includePages": true,
  "chunkSize": 0,
  "chunkOverlap": 100,
  "maxFileSizeMb": 50,
  "maxConcurrency": 2
}
```

# Actor output Schema

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

One item per document: status, document type, pages, OCR pages, word count, language, Markdown and/or text, tables, RAG chunks, metadata and warnings. Failed documents carry the error and are not charged.

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

OUTPUT record: documents ok / failed / skipped, OCR pages, the OCR setup used and whether the maximum charge was reached.

# 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 = {
    "urls": [
        "https://www.nhc.noaa.gov/data/tcr/AL022023_Arlene.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vimplement/document-to-markdown").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 = { "urls": ["https://www.nhc.noaa.gov/data/tcr/AL022023_Arlene.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("vimplement/document-to-markdown").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 '{
  "urls": [
    "https://www.nhc.noaa.gov/data/tcr/AL022023_Arlene.pdf"
  ]
}' |
apify call vimplement/document-to-markdown --silent --output-dataset

```

## MCP server setup

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

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/xxhextjyEahGEcvK9/builds/knL6vUNAe2TByIPNW/openapi.json
