# Documents to Markdown for RAG (Docling) (`br_data_hub/docs-to-markdown`) Actor

Convert PDF and DOCX files to clean Markdown with Docling: page count, detected tables, metadata and optional RAG-ready chunks.

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

## Pricing

from $2.80 / 1,000 pages

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

## Documents to Markdown for RAG (Docling)

Turn **PDF and DOCX** files into clean, structured **Markdown** ready for LLMs, RAG pipelines and vector databases. Conversion runs on [Docling](https://github.com/docling-project/docling), the open-source document parser from IBM Research (now under the LF AI & Data Foundation), which understands page layout, reading order, headings, lists and **tables** instead of dumping raw text.

### What you get per document

- `markdown`: the full document as Markdown, headings and tables included
- `pageCount`, `title`, `fileName`, `format` (`pdf` or `docx`), `fileSizeBytes`
- `tableCount` and `tables`: each table with its page, number of rows and columns, and the table as Markdown
- `chunks` (optional): the Markdown split into heading-aware pieces for embeddings, each with its heading path
- `billedPages`, `markdownChars`, `processingSecs`, `status` (`ok` or `partial`) and `warnings`

### Input

| Field | Description |
|---|---|
| `documentUrls` | Public links to PDF or DOCX files, up to 100 per run. The format is detected from the file bytes, so links without an extension work. |
| `uploadedFile` | Optional file uploaded from your computer, converted together with the URLs. |
| `chunking` | Also return RAG chunks (default `false`). |
| `chunkSize` / `chunkOverlap` | Maximum characters per chunk (default 2,000) and characters repeated from the previous chunk (default 200). |
| `tableStructure` | Rebuild PDF tables cell by cell with Docling's TableFormer model (default `true`). |
| `includeTables` | Include each table's Markdown in `tables` (default `true`). |
| `ocr` | OCR scanned PDFs (default `false`; digital PDFs already contain their text). |
| `maxPagesPerDocument` / `maxFileSizeMb` | Safety limits (default 200 pages, 50 MB). Documents over the limits return an error and are free. |

The default input converts one public page from a research paper with a table, so you can see the output in under a minute.

### Output example

```json
{
  "url": "https://example.com/annual-report.pdf",
  "fileName": "annual-report.pdf",
  "format": "pdf",
  "status": "ok",
  "title": "Annual Report 2025",
  "pageCount": 12,
  "tableCount": 3,
  "tables": [{"page": 4, "rows": 8, "columns": 5, "markdown": "| Year | Revenue | ... |"}],
  "markdown": "# Annual Report 2025\n\n## Highlights\n\n...",
  "chunks": [{"index": 0, "headings": ["Annual Report 2025", "Highlights"], "text": "...", "chars": 1840}],
  "billedPages": 12,
  "markdownChars": 38211,
  "processingSecs": 41.3
}
```

Files that cannot be downloaded, are not PDF or DOCX, or fail to convert return an item with `status: "error"` and an `error` message, and you are not charged for them.

### Chunking for RAG

Chunks follow the document structure: sections are cut at headings, small sibling sections are merged up to `chunkSize`, and long sections are split at paragraph, then line, then word boundaries. Each chunk carries its `headings` path (for example `["User guide", "Installation"]`), which you can store as metadata or prepend to the text before embedding.

### How much does it cost?

Pay per event, no usage fees on top: **US$ 0.004 per converted page**, plus a tiny start charge of US$ 0.00005 per run.

DOCX files have no fixed pages, so every 3,000 characters of Markdown count as one page (minimum 1). Documents that fail are free. A 1-page PDF costs about US$ 0.004, a 5-page one US$ 0.02 and a 100-page one US$ 0.40. Put several documents in one run to pay the start only once.

Speed on Apify (measured on 30/10/2026): the default 1-page input took about 18 s, of which roughly 15 s is fixed start-up (loading the Docling models); each extra PDF page adds roughly 0.2 to 0.5 s. A 100-page PDF converted in about 24 s on one thread.

The niche leader charges about US$ 0.02 per document regardless of size; we are cheaper for documents up to 5 pages and charge in proportion for longer ones.

**$0.004 per page** (`page` event, pay per event). Charged per page of each converted document (DOCX: each 3,000 Markdown characters count as one page). Failed documents are free.

- `apify-actor-start`: $0.00005 (Charged once when a run starts (Apify synthetic event).)

| You get | Free tier | Bronze tier (10% off) | Gold tier (30% off) |
|---|---|---|---|
| 100 pages | $0.40 | $0.36 | $0.28 |
| 1,000 pages | $4.00 | $3.60 | $2.80 |
| 10,000 pages | $40.00 | $36.00 | $28.00 |

Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. No subscription to this Actor and no charge for platform usage: you pay only for results.
The Apify Free plan includes $5 of monthly credit, enough for about **1,250 pages** at the list price.
You can cap the cost of any run with **Maximum cost per run**; the Actor stops when it is reached.

### Data source and limits

Your own documents, or public links you provide. Files are processed in the run's memory and are not stored anywhere else; the dataset of the run keeps the converted Markdown. Conversion uses Docling's open models (layout analysis and TableFormer), which run inside the Actor, with no external AI API. Scanned PDFs need `ocr: true`. Complex layouts (multi-column magazines, forms) are converted on a best-effort basis.

Docling is MIT licensed; its models are released under permissive licenses. This Actor is not affiliated with IBM or the Docling project.

### More questions

#### Which file formats are supported?

PDF and DOCX. The format is detected from the first bytes of the file, so links without an extension or with a wrong content type still work. Other files (PPTX, XLSX, HTML pages, images, ZIP) return an item with `status: "error"` and `Not a PDF or DOCX file`, and are not charged.

#### Does it work with scanned PDFs?

Yes, with `ocr: true`. OCR is off by default because digital PDFs already contain their text and OCR makes the run slower. If a scanned PDF comes back with almost no Markdown, run it again with OCR on.

#### What chunk size should I use for embeddings?

`chunkSize` is in characters, overlap included; about 4 characters make one token in English, so the default of 2,000 is roughly 500 tokens. Chunks are cut at headings first, small sibling sections are merged, and long sections are split at paragraph, line and then word boundaries. `chunkOverlap` (default 200) repeats the end of the previous chunk of the same section and is capped at half the chunk size. Each chunk has a `headings` path you can keep as metadata or prepend before embedding.

#### Are tables kept as tables?

Yes. Tables are rebuilt cell by cell with Docling's TableFormer model and written as Markdown tables, both inside `markdown` and in `tables` with their page, rows and columns. Turn off `tableStructure` for faster runs on text-only documents, or `includeTables` to keep only each table's page and size in `tables`.

#### Can I send a Google Drive or Dropbox share link?

Only if the link downloads the file itself. Share pages return HTML, which is rejected as not a PDF or DOCX (free). Use a direct download link, or upload the file in `uploadedFile`.

#### What are the limits per run?

Up to 100 documents per run (repeated URLs are converted once), processed one at a time. `maxPagesPerDocument` (default 200, up to 2,000) and `maxFileSizeMb` (default 50, up to 500) skip larger documents with an error, free of charge. When a run reaches your **Maximum cost per run**, it stops after the current document.

#### Are my documents sent to an AI service or stored?

No external AI API is called: Docling's layout and table models run inside the Actor. Files are downloaded into the run's memory and only the converted result is saved, in the run's dataset, which follows your Apify storage retention.

#### Is a partly broken PDF charged?

When Docling converts only part of a document, the item comes back with `status: "partial"` and the problems in `warnings`, and its pages are charged like a normal result. Documents that fail completely are free.

### Use it via API

Run it from any language and get the results as JSON. Replace `<YOUR_API_TOKEN>` with your [Apify API token](https://console.apify.com/settings/integrations).

```bash
curl -X POST "https://api.apify.com/v2/acts/br_data_hub~docs-to-markdown/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"documentUrls": ["https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf"]}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("br_data_hub/docs-to-markdown").call(run_input={'documentUrls': ['https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf']})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

You can also schedule runs, send results to webhooks, or connect the Actor to Make, Zapier, n8n, Google Sheets and other [integrations](https://docs.apify.com/platform/integrations).

### Use it with AI agents (MCP)

This Actor is ready for AI agents: typed input and output schemas, pay-per-event pricing, limited permissions and short runs.

- **Apify MCP server:** add `https://mcp.apify.com/?tools=br_data_hub/docs-to-markdown` to Claude, ChatGPT, Cursor, VS Code or any MCP client, and the agent can call this Actor as a tool.
- **Agent frameworks:** call it from LangChain, LlamaIndex, CrewAI or the OpenAI Agents SDK through the Apify integrations, or with the API call above.
- Results come as structured JSON with stable field names, documented in the **Output** tab.

### FAQ

#### Where does the data come from?

Your own documents, or public links you provide. Files are processed in the run's memory and are not stored anywhere else; the dataset of the run keeps the converted Markdown. Conversion uses Docling's open models (layout analysis and TableFormer), which run inside the Actor, with no external AI API. Scanned PDFs need `ocr: true`. Complex layouts (multi-column magazines, forms) are converted on a best-effort basis.

#### How much does it cost?

$0.004 per page. Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. See **How much does it cost?** above for examples.

#### Do I pay for errors or empty results?

No. Charged per page of each converted document (DOCX: each 3,000 Markdown characters count as one page). Failed documents are free.

#### Can I run it on a schedule or connect it to other tools?

Yes. Use Apify schedules to run it daily or weekly, webhooks to get notified, and integrations such as Make, Zapier, n8n and Google Sheets. Everything also works through the API.

#### Can AI agents use it?

Yes. It works as a tool in the Apify MCP server and in agent frameworks, and AI agents can pay per event. See **Use it with AI agents (MCP)**.

#### Is it legal to use this data?

The Actor reads only public sources. You are responsible for how you use the data and for complying with the source's terms and with privacy laws such as GDPR.

#### I found a bug or need a feature. What should I do?

Open an issue in the **Issues** tab. We answer within 14 days, usually much sooner.

### More Actors from BR Data Hub

| Actor | What it does |
|---|---|
| [Website to llms.txt Generator](https://apify.com/br_data_hub/website-to-llms-txt) | Crawl one website (robots.txt and sitemap aware), generate spec-compliant llms.txt and llms-full.txt files, au |
| [RSS & Atom Feed Reader with Full Text](https://apify.com/br_data_hub/rss-full-text-feed) | Read RSS, Atom and JSON Feed (or find the feed of any website) and get clean items with ISO dates, full articl |
| [Research Papers Search for RAG, from OpenAlex data](https://apify.com/br_data_hub/openalex-research-search) | Search 250M+ scholarly papers from OpenAlex data, or look up DOIs: authors with institutions, venue, citations |
| [Brazil CNPJ Lookup API (Consulta CNPJ)](https://apify.com/br_data_hub/br-cnpj-lookup) | Look up Brazilian companies by CNPJ: registration status, partners (masked CPF), activities, tax regime and sc |

See all our Actors at [apify.com/br_data_hub](https://apify.com/br_data_hub).

### Usar em português

Informe links de arquivos PDF ou DOCX (ou envie um arquivo) e receba o documento em Markdown limpo, com número de páginas, tabelas detectadas e metadados. Ative `chunking` para receber o texto já dividido em pedaços por seção, prontos para RAG. A cobrança é por página convertida; arquivos com erro não são cobrados.

**Quanto custa:** $0.004 por resultado (`page`); 1.000 resultados saem por $4.00. Desconto pelo nível da assinatura Apify: Bronze 10%, Silver 20%, Gold ou acima 30%. Erros e consultas sem resultado não são cobrados. Use também pela API ou por agentes de IA no servidor MCP da Apify (`https://mcp.apify.com/?tools=br_data_hub/docs-to-markdown`).

# Actor input Schema

## `documentUrls` (type: `array`):

Enter public links to PDF or DOCX files, one per line, up to 100 per run. The format is detected from the file, so links without an extension work too.

## `uploadedFile` (type: `string`):

Upload a PDF or DOCX from your computer instead of giving a link. It is converted together with the URLs above.

## `chunking` (type: `boolean`):

Turn on to also get the Markdown split into heading-aware chunks, ready for embeddings. Each chunk keeps its heading path.

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

Set the maximum characters per chunk, overlap included, e.g. 2000. About 4 characters make one token in English.

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

Set how many characters to repeat from the end of the previous chunk of the same section, e.g. 200, so context is not lost at the cut. Capped at half the chunk size.

## `tableStructure` (type: `boolean`):

Keep on to rebuild PDF tables cell by cell with Docling's TableFormer model. Turn off for faster runs on text-only documents.

## `includeTables` (type: `boolean`):

Keep on to add every detected table (page, rows, columns and Markdown) to the result. Turn off to list only table position and size.

## `ocr` (type: `boolean`):

Turn on for scanned PDFs and text inside images. Slower; leave off for digital PDFs, which already contain their text.

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

Set a page limit, e.g. 200. Longer documents are skipped with an error and not charged.

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

Set a size limit in MB, e.g. 50. Larger files are skipped with an error and not charged.

## Actor input object example

```json
{
  "documentUrls": [
    "https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf"
  ],
  "chunking": false,
  "chunkSize": 2000,
  "chunkOverlap": 200,
  "tableStructure": true,
  "includeTables": true,
  "ocr": false,
  "maxPagesPerDocument": 200,
  "maxFileSizeMb": 50
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with all results

## `files` (type: `string`):

Key-value store with the files and the OUTPUT summary of the run

# 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 = {
    "documentUrls": [
        "https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("br_data_hub/docs-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 = { "documentUrls": ["https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("br_data_hub/docs-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 '{
  "documentUrls": [
    "https://raw.githubusercontent.com/docling-project/docling/v2.145.0/tests/data/pdf/sources/2305.03393v1-pg9.pdf"
  ]
}' |
apify call br_data_hub/docs-to-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,br_data_hub/docs-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/70HvxfSoXkUUOzeu5/builds/pghcwxdlGg48Wk6uG/openapi.json
