# Docling Document Converter: PDF & Office to Markdown (`tallowlanelabs/docling-document-converter`) Actor

Convert PDFs (including scans), Word, PowerPoint, Excel, HTML and images into clean, LLM-ready Markdown or structured Docling JSON with tables, headings, reading order, OCR and optional RAG chunks with page references.

- **URL**: https://apify.com/tallowlanelabs/docling-document-converter.md
- **Developed by:** [Tallow Lane Labs](https://apify.com/tallowlanelabs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 page 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

## Docling Document Converter: PDF, Word, PowerPoint & HTML to Markdown/JSON for LLMs

Turn PDFs (including scanned ones), DOCX, PPTX, XLSX, HTML, Markdown, CSV and images into clean, **LLM-ready Markdown** or the full structured **Docling JSON**. Headings, reading order, lists and **tables** are kept. You can also have documents **split into RAG chunks** with heading paths and page numbers.

It runs IBM's open-source [Docling](https://github.com/docling-project/docling) (MIT) with its layout, TableFormer and OCR models built into the image. **Your documents never leave the Actor run:** no third-party APIs and no LLM calls.

*By Tallow Lane Labs*

### What you get

| | |
|---|---|
| **Markdown** | Real `#` headings, ordered/bulleted lists, pipe tables, and `<!-- image -->` placeholders where figures sit. |
| **Docling JSON** | The lossless `DoclingDocument`: every text, table cell and picture, with page number and bounding box. |
| **RAG chunks** (optional) | Token-sized chunks (Docling `HybridChunker`) that respect sections, tables and lists. Each chunk has `headings`, `pageNumbers` and `tokenCount`. Chunks are delivered in the document row, or as one dataset row per chunk ready for vector DB integrations. |
| **OCR** | Scans and image-only pages are OCR'd automatically (RapidOCR / PP-OCRv6). You can force OCR or turn it off. |
| **Tables** | TableFormer *fast* (default) or opt-in *accurate* for dense tables. Tables in Office and HTML files are read natively. |

### Supported inputs

- **Files:** PDF, DOCX, PPTX, XLSX, HTML, MD, CSV, AsciiDoc, PNG, JPG, TIFF, BMP and WEBP. Up to 500 MB each (100 MB by default).
- **Two ways in:** upload files in the input form (*Upload documents*), or paste direct links (*Document URLs*). You can mix them in one run, with up to 1,000 documents per run.
- **Not supported:** password-protected PDFs, legacy `.doc` and `.ppt` files, and URLs that need a login. These come back as a `failed` row and **are not charged**.

### Input example

```json
{
  "urls": [{ "url": "https://arxiv.org/pdf/2408.09869" }],
  "outputFormat": "both",
  "ocrMode": "auto",
  "tableMode": "fast",
  "maxPagesPerDocument": 200,
  "chunking": true,
  "chunkMaxTokens": 512
}
```

### Output

You get one dataset row per document (`recordType: "document"`):

```json
{
  "fileName": "2206.01062.pdf", "format": "pdf", "status": "success",
  "title": "DocLayNet: A Large Human-Annotated Dataset for Document-Layout Analysis",
  "pagesConverted": 9, "totalPages": 9, "truncated": false, "ocrPages": 0,
  "tables": 5, "pictures": 6, "markdownChars": 52489, "chunkCount": 42,
  "markdown": "## DocLayNet: A Large Human-Annotated ...",
  "markdownUrl": null,
  "json": null, "jsonUrl": "https://api.apify.com/v2/key-value-stores/…/records/doc-0000-2206.01062-docling.json",
  "chunks": [{ "chunkIndex": 0, "text": "…", "headings": ["DocLayNet …"], "pageNumbers": [1], "tokenCount": 134 }],
  "billedUnits": { "pageConverted": 9, "pageAccurateTables": 0, "ocrPage": 0, "chunkBatch": 1 },
  "processingSeconds": 30.1, "doclingVersion": "2.143.0"
}
```

- Outputs up to *Max inline content size* (2 MB by default) are placed directly in the row. Larger ones go to the run's key-value store, and the row links to them through `markdownUrl`, `jsonUrl` and `chunksUrl`. Docling JSON is typically 10–20× the size of the Markdown.
- The **Documents**, **Markdown** and **RAG chunks** dataset views give you a quick table. The run's `SUMMARY` record totals the pages, OCR pages and failures.
- `status` is `success`, `partial_success` (some pages failed or the per-document timeout hit) or `failed` (with an `error` message).

### Pricing (pay per event)

| Event | Price | When |
|---|---|---|
| Actor start | $0.00125 per GB of memory ($0.005 at the default 4 GB) | Once per run |
| Page converted | **$0.003** | Each PDF page or PPTX slide converted from its text layer with the default *fast* table mode. Formats without pages (DOCX, HTML, XLSX, MD, CSV) count one page per started 3,000 characters of actual text (minimum 1 per document). Markup, table padding and link URLs are not counted. |
| Page converted (accurate tables) | **$0.007** | Only if you choose *Table structure = Accurate*: each PDF or image page processed with the TableFormer accurate model. It **replaces** the $0.003 page charge. DOCX, PPTX, XLSX and HTML keep the $0.003 price in accurate mode, because their tables are read natively. |
| OCR page | **$0.01** | A page where OCR produced at least half of the text: scans, photos and image files, or every page with *OCR = Force*. It **replaces** the page charge and is never added to it. This applies in accurate table mode too: an OCR page costs $0.01, not $0.017. |
| RAG chunks | $0.001 per started batch of 100 chunks, per document | Only when chunking is enabled |

Every page is billed exactly once, at one of the three page prices.

- **Failed documents are never charged.**
- *Max pages per document* caps both work and cost per file.
- The Actor respects your run's **maximum total charge**. It converts only as many pages as fit, then stops.
- Examples at the default 4 GB: a 10-page digital PDF costs **$0.035** including the start fee, or $0.075 with accurate tables. A 100-page scanned book costs **$1.005**. A 20-page Word document (about 40,000 characters) costs $0.047.

### Speed and memory

These figures come from local benchmarks on one vCPU, which matches the default 4 GB memory setting.

| Document type | Seconds per page |
|---|---|
| Plain-text PDF | about 1.5–2 s |
| Typical paper or report with figures and tables | about 3 s (4.5 s with accurate tables) |
| Dense statistical tables | about 8 s (about 18 s with accurate tables) |
| Scanned page with OCR | about 5 s |
| DOCX, PPTX or HTML | well under 1 s per document |

- Peak memory stayed below 2.5 GB on every test file, so **4 GB is the recommended setting**.
- 8 GB gives two vCPUs and converts PDFs about 1.8× faster. The start fee is then $0.01.
- Models load in about 3 s per run.

### Privacy and data retention

- **Documents fetched from URLs** are downloaded to a temporary folder inside the run container and deleted right after conversion. They are never written to datasets or key-value stores.
- **Uploaded files** are **deleted** from their key-value store after the run by default (*Delete uploaded files after run*). Turn that off if you want to reuse them.
- **Converted outputs** (Markdown, JSON, chunks) stay in the run's dataset and key-value store under your normal Apify retention settings. You can also send them to a named store of your choice.
- No document content is sent to any external service.

**You must have the right to process the documents you submit.** Converting a document does not give you any rights to its content.

### Tips

- If a scanned PDF has a garbage text layer (bad earlier OCR), use **OCR = Force**.
- If you only need text from born-digital PDFs, use **OCR = Off**. It is fastest; scanned pages come back empty.
- Use **Table structure = Accurate** only for dense tables with merged or multi-row headers, such as financial statements and statistical releases. It is 1.5–2× slower and costs $0.007 per page instead of $0.003.
- **Skip OCR inside figures** is on by default. On digital pages, picture and chart regions are not OCR'd, which makes papers about 30–40% faster. The Markdown is identical. You only lose text that is drawn inside raster figures, such as screenshot labels, and that text only ever appears in the JSON. Turn it off if you need that text. Scanned pages are always OCR'd in full.
- For RAG, enable **chunking** and **Output chunks as separate dataset rows**, then connect the dataset to the Pinecone, Qdrant or other vector DB integration.
- Multi-column layouts, footnotes and page headers are handled by Docling's layout model. Repeating page headers and footers are moved out of the Markdown body (they stay in the JSON as furniture).

### Limitations

- Very complex tables (many merged header rows, dense statistical releases) can occasionally have shifted or merged cells. Check `json` if you need exact cell coordinates.
- OCR is tuned for Latin and Chinese scripts (PP-OCRv6). Handwriting is not supported.
- Formulas come out as text, and pictures are not described. No vision-language models are used.

### Open-source licenses

This Actor's code is MIT. The bundled components are listed below; all allow commercial use, and the full list is in `LICENSES.md`.

| Component | License |
|---|---|
| Docling | MIT |
| docling-layout-heron model | Apache-2.0 |
| TableFormer weights | CDLA-Permissive-2.0 |
| RapidOCR and PP-OCR weights | Apache-2.0 |
| all-MiniLM-L6-v2 tokenizer | Apache-2.0 |
| PyTorch | BSD-3 |
| ONNX Runtime | MIT |

### Support

Questions or issues: open an issue on this Actor's Issues tab, or email Tallow Lane Labs at wdeornellas+tallowlanelabs@gmail.com.

# Actor input Schema

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

Upload PDF, DOCX, PPTX, XLSX, HTML, Markdown, CSV or image files (PNG, JPG, TIFF). They are stored in a key-value store of your choice and read by the Actor. By default uploaded files are deleted after the run (see 'Delete uploaded files after run').

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

Direct links to documents (PDF, DOCX, PPTX, XLSX, HTML, MD, CSV, images). Each URL is downloaded once, converted, and the downloaded copy is discarded.

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

Markdown is best for LLMs and RAG. Docling JSON is the full lossless document model (layout, provenance, bounding boxes, table cells).

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

Auto: OCR only regions with no text layer (scans, embedded images) – billed as OCR pages only where OCR produced most of the text. Force: OCR every page (use for scans with a bad text layer; every page is billed as an OCR page). Off: text layer only, cheapest and fastest; scanned pages come back empty.

## `tableMode` (type: `string`):

Fast (default): TableFormer fast model, good for most tables; billed at the normal page price ($0.003/page). Accurate (opt-in): TableFormer accurate model for dense tables with merged cells (e.g. financial statements); about 1.5-2x slower and billed $0.007 per PDF/image page instead of $0.003 (OCR pages stay $0.01, no extra). Off: tables come out as plain text. Applies to PDFs and images; Office/HTML tables are read natively and always billed at the normal price.

## `skipOcrOnFigures` (type: `boolean`):

OCR mode Auto only: on digital pages (pages with a text layer), don't OCR regions detected as pictures/charts. Faster, and figure-internal labels are not part of the Markdown anyway; turn off if you need chart/diagram labels in the JSON output. Scanned pages are always OCR'd in full. No effect on price.

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

Only the first N pages of each PDF are converted (and billed). The output marks truncated documents.

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

Documents larger than this are skipped (not billed).

## `documentTimeoutSecs` (type: `integer`):

Stop converting a document after this many seconds; pages finished so far are returned as a partial result.

## `includeImagePlaceholders` (type: `boolean`):

Insert  where pictures appear, so LLMs know a figure was there.

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

Split each document into token-sized chunks (Docling HybridChunker: respects headings, tables and lists) with heading path and page numbers. Billed $0.001 per started batch of 100 chunks, counted per document.

## `chunkMaxTokens` (type: `integer`):

Measured with the all-MiniLM-L6-v2 tokenizer (close to most embedding models; leave headroom for OpenAI tokenizers).

## `chunksAsDatasetItems` (type: `boolean`):

Also push one dataset item per chunk (recordType = 'chunk') – handy for feeding vector databases directly via integrations.

## `inlineContentMaxKb` (type: `integer`):

Markdown/JSON/chunks up to this size are put directly in the dataset item; bigger outputs are saved to the key-value store and linked (…Url fields).

## `outputKeyValueStoreName` (type: `string`):

Optional named key-value store for outputs too big to inline. Default: the run's own store (subject to your retention settings).

## `deleteUploadedFilesAfterRun` (type: `boolean`):

When on (default), files you uploaded through 'Upload documents' are deleted from their key-value store after conversion, so your source documents are not kept. URL downloads are never stored.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    }
  ],
  "outputFormat": "markdown",
  "ocrMode": "auto",
  "tableMode": "fast",
  "skipOcrOnFigures": true,
  "maxPagesPerDocument": 200,
  "maxFileSizeMb": 100,
  "documentTimeoutSecs": 600,
  "includeImagePlaceholders": true,
  "chunking": false,
  "chunkMaxTokens": 512,
  "chunksAsDatasetItems": false,
  "inlineContentMaxKb": 2048,
  "deleteUploadedFilesAfterRun": true
}
```

# Actor output Schema

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

One record per input document with status, page count, Markdown/JSON content or links, and optional chunks.

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

Converted Markdown/JSON files stored in the default key-value store.

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

JSON summary of the run: documents processed, pages, failures and timing.

# 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": [
        {
            "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tallowlanelabs/docling-document-converter").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": [{ "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" }] }

# Run the Actor and wait for it to finish
run = client.actor("tallowlanelabs/docling-document-converter").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": [
    {
      "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    }
  ]
}' |
apify call tallowlanelabs/docling-document-converter --silent --output-dataset

```

## MCP server setup

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

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/CDNnJcHGaVDjePAFe/builds/mV3OcoPkBpSBNR9TG/openapi.json
