# Document to Markdown — PDF, DOCX & OCR for RAG (`caspiandata/doc-to-markdown`) Actor

Convert PDF, DOCX, HTML and text files to clean Markdown with headings, lists and tables. Scanned pages are OCR'd automatically. Get RAG-ready chunks for LLMs and vector databases. Pay only per document.

- **URL**: https://apify.com/caspiandata/doc-to-markdown.md
- **Developed by:** [Casian Data](https://apify.com/caspiandata) (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 $3.00 / 1,000 document converteds

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 to Markdown — PDF, DOCX & OCR for RAG

Turn **PDF, Word (DOCX), HTML and text files into clean Markdown** — with headings, lists and tables preserved, **automatic OCR for scanned pages**, and **RAG-ready chunks** you can send straight to an embedding model or vector database.

### What it does

- **PDF → Markdown** with real structure: headings are detected from font sizes, bullet lists are kept, hyphenated line breaks are joined, running headers/footers and page numbers are removed, and **two-column papers are read in the right order**.
- **Automatic OCR**: pages that have no text layer (scans, photos, image-only PDFs) are OCR'd with Tesseract. Choose `auto`, `force` or `off`, and pick languages (English bundled; 100+ others supported).
- **DOCX → Markdown** including tables (as GitHub-flavoured Markdown tables).
- **HTML → Markdown** keeping only the main content (navigation, scripts and footers dropped).
- **Chunks for RAG**: each document is split on heading and paragraph boundaries into chunks of your chosen size with overlap. Every chunk carries the nearest heading for context.
- **Page ranges** for long PDFs, a per-page output option, and file-size limits.

### Typical uses

- Feed documents into **LLM / RAG pipelines** (LangChain, LlamaIndex, OpenAI, Pinecone, Qdrant, Weaviate).
- Convert **invoices, contracts, reports and research papers** to text you can search or analyse.
- Batch-convert a list of PDF links from a website, a spreadsheet or another Actor.

### Input

| Field | Description |
|---|---|
| `urls` | Direct links to PDF, DOCX, HTML or TXT/Markdown files |
| `pageRange` | Optional, e.g. `1-20` |
| `ocr` | `auto` (default), `force`, `off` |
| `ocrLanguages` | Tesseract codes, e.g. `["eng","deu"]` |
| `chunkSize` / `chunkOverlap` | Characters per chunk (0 disables chunking) |
| `includePages` | Also return Markdown per page |

```json
{
  "urls": ["https://arxiv.org/pdf/1706.03762"],
  "pageRange": "1-2",
  "ocr": "auto",
  "chunkSize": 1500,
  "chunkOverlap": 150
}
```

### Output

One dataset item per document:

```json
{
  "sourceUrl": "https://arxiv.org/pdf/1706.03762",
  "type": "pdf",
  "title": "Attention Is All You Need",
  "pageCount": 15,
  "processedPages": 2,
  "ocrPages": 0,
  "characters": 7112,
  "markdown": "...\n\n# Attention Is All You Need\n\n...\n\n## Abstract\n\nThe dominant sequence transduction models are based on complex recurrent or convolutional neural networks ...",
  "chunks": [
    { "index": 0, "heading": "Attention Is All You Need", "text": "...", "chars": 780 }
  ],
  "error": null
}
```

(Real output for `"pageRange": "1-2"`, shortened.)

Failed documents are returned with an `error` message and are **not charged**.

### Pricing (pay per event)

You pay only for what is converted:

- **Document**: per converted document, includes the first 10 pages
- **Extra page**: each page beyond 10
- **OCR page**: each page that had to be OCR'd

No charge for failed or unsupported files. Set a maximum cost per run in the run options to cap spending.

### Tips

- For scanned documents in other languages, set `ocrLanguages`, e.g. `["eng","fra"]`.
- Use `pageRange` to test on a few pages before converting a large file.
- To convert private files, upload them to an Apify key-value store and use the record's URL.

### Use it from your code or no-code tools

- **API**: call the Actor with one HTTP request and read the results as JSON, CSV or Excel. Python and JavaScript clients are available (`apify-client`).
- **LangChain / LlamaIndex**: load the dataset with the Apify dataset loaders and index the `chunks` directly.
- **Make, n8n, Zapier**: use the Apify integration to convert every new PDF from Google Drive, Dropbox or email attachments automatically.
- **AI agents (MCP)**: agents connected to the Apify MCP server can call this Actor to read a PDF they were given a link to.

### FAQ

**Can it convert scanned PDFs to text?** Yes. Pages without a text layer are OCR'd automatically (`ocr: "auto"`). Use `force` for PDFs whose text layer is broken.

**How is this different from a plain PDF-to-text tool?** You get Markdown with headings and lists instead of a wall of text, page headers and footers removed, two-column papers in reading order, and chunks ready for embeddings.

**Which languages does OCR support?** English is built in. Add any Tesseract language code in `ocrLanguages`, e.g. `deu`, `fra`, `spa`, `tur`, `rus`, `ara`, `chi_sim`.

**How much does it cost?** $3 per 1,000 documents (first 10 pages included), $0.30 per 1,000 extra pages, $3 per 1,000 OCR pages. Failed files are free.

**Can I convert files from my computer?** Upload them to an Apify key-value store, Google Drive (public link) or any file host and paste the direct link.

### Limitations

- Complex PDF tables are output as text lines, not Markdown tables (DOCX and HTML tables are converted).
- Mathematical formulas are kept as plain text.
- Password-protected PDFs are not supported.

### Privacy

Documents are processed only to produce your output and are not stored outside your own Apify storage.

# Actor input Schema

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

Direct links to PDF, DOCX, HTML or TXT/Markdown files. To convert your own files, upload them to a key-value store or any file host and paste the public link.

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

Optional. Examples: "1-20", "5", "3-". Leave empty for all pages.

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

auto = OCR only pages without a text layer (scans). force = OCR every page. off = never OCR.

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

Tesseract language codes, e.g. eng, deu, fra, spa, ita, por, nld, pol, tur, rus, ukr, ara, chi_sim, jpn. English is bundled; others are downloaded on first use.

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

Split the Markdown into chunks for RAG / embeddings. 0 disables chunking.

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

Characters repeated between consecutive chunks so context is not cut mid-thought.

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

Adds a pages\[] array with the Markdown of each page and whether it was OCR'd.

## `mainContentOnly` (type: `boolean`):

For HTML pages, keep only <main>/<article> when present and drop navigation and footers.

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

Files larger than this are skipped (and not charged).

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

Stop after this many documents. 0 = no limit.

## Actor input object example

```json
{
  "urls": [
    "https://arxiv.org/pdf/1706.03762"
  ],
  "ocr": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "chunkSize": 1500,
  "chunkOverlap": 150,
  "includePages": false,
  "mainContentOnly": true,
  "maxFileSizeMb": 50,
  "maxDocuments": 0
}
```

# Actor output Schema

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

All results as a dataset (JSON, CSV, Excel and more).

# 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://arxiv.org/pdf/1706.03762"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("caspiandata/doc-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://arxiv.org/pdf/1706.03762"] }

# Run the Actor and wait for it to finish
run = client.actor("caspiandata/doc-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://arxiv.org/pdf/1706.03762"
  ]
}' |
apify call caspiandata/doc-to-markdown --silent --output-dataset

```

## MCP server setup

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