# PDF & DOCX to Markdown — Document Extractor for LLM/RAG (`runlayer/document-to-markdown`) Actor

Convert PDF and Word (DOCX) documents into clean Markdown, text, or JSON. Smart PDF paragraph reflow, page markers for RAG citations, full DOCX structure (headings, lists, tables), custom auth headers. No browser — parses in seconds. Charged per page processed — no startup fee.

- **URL**: https://apify.com/runlayer/document-to-markdown.md
- **Developed by:** [Runlayer](https://apify.com/runlayer) (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 page processeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## PDF & DOCX to Markdown — Document Text Extractor for LLMs

Convert **PDF and Word (DOCX) documents** into clean **Markdown, plain text, or
JSON** — ready for RAG pipelines, LLM prompts, embeddings, and datasets. Point
it at your document URLs and get back structured, chunk-ready content.

**Billing is per page actually processed** (about ⅓ the price of hosted parsing
APIs). No startup fee. Failed documents cost $0.

### Quick start

```json
{
  "fileUrls": ["https://example.com/whitepaper.pdf"]
}
````

→ one dataset item per document:

```json
{
  "url": "https://example.com/whitepaper.pdf",
  "fileType": "pdf",
  "pages": 15,
  "wordCount": 6112,
  "title": "Attention Is All You Need",
  "markdown": "The dominant sequence transduction models are based on…"
}
```

### What it does well

| | |
|---|---|
| **PDF** | Page-aware text extraction with **smart paragraph reflow** (fixes the broken-mid-sentence line breaks raw PDF extractors produce); optional `--- Page N ---` markers so your chunks can cite pages; document title from PDF metadata |
| **DOCX** | Full structure preserved — headings, lists, **tables** (GFM), links, bold/italic — via real .docx parsing, not text-dump |
| **Outputs** | Markdown / plain text / JSON (JSON includes per-page text array for PDFs) |
| **Protected files** | Custom request headers (e.g. `Authorization: Bearer …`) for presigned or authenticated URLs you have access to |
| **Cost control** | `maxPagesPerDoc` cap (default 500) so a giant PDF can't surprise you |
| **Speed** | No browser involved — documents parse in seconds on the lightweight runtime |

### Built for AI pipelines

- **RAG ingestion:** fetch → `markdown` → chunk → embed. Use `pageMarkers` to keep
  page-level citations.
- **Whole knowledge bases:** pass hundreds of URLs in one run; each becomes one
  clean dataset record.
- **Agents:** call via the Apify API or MCP server to give an agent readable
  documents instead of binary blobs.
- Pairs with **[Website to Markdown](https://apify.com/runlayer/website-to-markdown)**
  from the same publisher — web pages + documents, one uniform Markdown output
  for your whole ingestion pipeline.

```bash
curl -X POST "https://api.apify.com/v2/acts/runlayer~document-to-markdown/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fileUrls": ["https://example.com/report.pdf"], "outputFormat": "json"}'
```

### Pricing

A small fixed price **per page processed** (PDF pages; DOCX bills as ~500-word
page equivalents, minimum 1), plus standard Apify platform usage — which is tiny
here, since no browser is involved. Failed documents are never billed.

### Current limits (roadmap)

- **Scanned/image-only PDFs are not OCR'd yet** — they return a clear error and
  are not billed. OCR support is planned; ask for it in the issues tab if you
  need it and it moves up the list.
- Complex multi-column PDF layouts extract in reading order on a best-effort
  basis (this is a hard limit of the PDF format itself).
- DOC (legacy Word), ODT and image formats are not yet supported.

### FAQ

**Where do my documents go?** They're fetched, parsed in the run's container,
and the extracted content is stored only in your own run's dataset. Nothing is
retained by the actor. Only submit documents you have the right to process.

**A document failed — was I charged?** No. Only successfully processed pages
are billed.

***

Need OCR, ODT, or another format? **Open an issue** — this actor iterates fast.
If it saves you time, a ⭐ review helps others find it.

### More tools by Runlayer

Part of a suite of fast, no-nonsense web utilities — all pay-per-result, charged only on success, no startup fee:

- [Website Screenshot API](https://apify.com/runlayer/web-screenshot-pro) — full-page PNG / JPEG / WebP / PDF
- [Website to Markdown](https://apify.com/runlayer/website-to-markdown) — clean Markdown for LLMs & RAG
- [PDF & DOCX to Markdown](https://apify.com/runlayer/document-to-markdown) — documents → Markdown for RAG
- [SEO Audit + Core Web Vitals](https://apify.com/runlayer/website-seo-audit) — scored on-page audit with fixes
- [Website Performance Audit](https://apify.com/runlayer/website-performance-audit) — bulk Core Web Vitals & page speed
- [Tech Stack Detector](https://apify.com/runlayer/tech-stack-detector) — CMS, frameworks, analytics, hosting
- [Domain, DNS & WHOIS Lookup](https://apify.com/runlayer/domain-dns-intelligence) — records, registration, SSL
- [RSS Feed Reader](https://apify.com/runlayer/rss-feed-reader) — RSS / Atom / JSON → normalized JSON
- [Job Postings API](https://apify.com/runlayer/job-postings-scraper) — Greenhouse, Lever, Ashby & more

### Use with AI agents (MCP)

This Actor is callable by AI agents through the [Apify MCP server](https://mcp.apify.com/). Agents in Claude, Cursor, Windsurf, LangGraph, CrewAI and others can discover it via `search-actors` and run it as a tool — its inputs and outputs are fully described in the schema for reliable agent use.

# Actor input Schema

## `fileUrls` (type: `array`):

Direct links to PDF or DOCX files (public URLs, presigned S3/GCS links, or Apify key-value-store record URLs). Each document produces one dataset item; billing is per page processed.

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

markdown (best for LLMs/RAG), text (plain), or json (markdown + text + per-page breakdown + metadata).

## `pageMarkers` (type: `boolean`):

Insert '--- Page N ---' separators between PDF pages so chunkers and citations can reference page numbers.

## `maxPagesPerDoc` (type: `integer`):

Safety cap: stop processing a PDF after this many pages (protects against huge documents and caps your cost).

## `requestHeaders` (type: `object`):

Optional headers sent when downloading the documents, e.g. {"Authorization": "Bearer …"} for protected files you have access to.

## `timeoutSecs` (type: `integer`):

Max time to download each document.

## Actor input object example

```json
{
  "fileUrls": [
    "https://example.com/report.pdf",
    "https://example.com/contract.docx"
  ],
  "outputFormat": "markdown",
  "pageMarkers": false,
  "maxPagesPerDoc": 500,
  "timeoutSecs": 60
}
```

# 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 = {
    "fileUrls": [
        "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("runlayer/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 = { "fileUrls": ["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("runlayer/document-to-markdown").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "fileUrls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ]
}' |
apify call runlayer/document-to-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=runlayer/document-to-markdown",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "PDF & DOCX to Markdown — Document Extractor for LLM/RAG",
        "description": "Convert PDF and Word (DOCX) documents into clean Markdown, text, or JSON. Smart PDF paragraph reflow, page markers for RAG citations, full DOCX structure (headings, lists, tables), custom auth headers. No browser — parses in seconds. Charged per page processed — no startup fee.",
        "version": "0.1",
        "x-build-id": "SDB0fKCge2p9dfINO"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/runlayer~document-to-markdown/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-runlayer-document-to-markdown",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/runlayer~document-to-markdown/runs": {
            "post": {
                "operationId": "runs-sync-runlayer-document-to-markdown",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/runlayer~document-to-markdown/run-sync": {
            "post": {
                "operationId": "run-sync-runlayer-document-to-markdown",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "fileUrls"
                ],
                "properties": {
                    "fileUrls": {
                        "title": "Document URLs",
                        "type": "array",
                        "description": "Direct links to PDF or DOCX files (public URLs, presigned S3/GCS links, or Apify key-value-store record URLs). Each document produces one dataset item; billing is per page processed.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "outputFormat": {
                        "title": "Output format",
                        "enum": [
                            "markdown",
                            "text",
                            "json"
                        ],
                        "type": "string",
                        "description": "markdown (best for LLMs/RAG), text (plain), or json (markdown + text + per-page breakdown + metadata).",
                        "default": "markdown"
                    },
                    "pageMarkers": {
                        "title": "Insert page markers (PDF)",
                        "type": "boolean",
                        "description": "Insert '--- Page N ---' separators between PDF pages so chunkers and citations can reference page numbers.",
                        "default": false
                    },
                    "maxPagesPerDoc": {
                        "title": "Max pages per document",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Safety cap: stop processing a PDF after this many pages (protects against huge documents and caps your cost).",
                        "default": 500
                    },
                    "requestHeaders": {
                        "title": "Custom HTTP headers for fetching files",
                        "type": "object",
                        "description": "Optional headers sent when downloading the documents, e.g. {\"Authorization\": \"Bearer …\"} for protected files you have access to."
                    },
                    "timeoutSecs": {
                        "title": "Download timeout (seconds)",
                        "minimum": 5,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Max time to download each document.",
                        "default": 60
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
