# Document to Markdown - PDF, Word, PowerPoint, Excel & OCR (`kadi_bence/document-to-markdown`) Actor

Convert documents to Markdown or text for LLMs: PDF, Word (DOCX), PowerPoint (PPTX), Excel (XLSX), HTML, EPUB and scanned images (Tesseract OCR). Input: file URLs or uploaded files. Returns per document: Markdown, title, page count, word count, tables and optional RAG chunks.

- **URL**: https://apify.com/kadi_bence/document-to-markdown.md
- **Developed by:** [Bence Kadi](https://apify.com/kadi_bence) (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 $2.00 / 1,000 documents

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, Word, PowerPoint, Excel & OCR converter

Convert **PDF, Word, PowerPoint, Excel, HTML, EPUB, OpenDocument, RTF and scanned images** into clean **Markdown**, plain **text** and ready-to-embed **RAG chunks**, for **$2 per 1,000 documents**.

### 📄 What is Document to Markdown?

It downloads the files you list (or reads them from your Apify storage) and returns one JSON row per document, with headings, tables, page numbers and metadata kept, and built-in **Tesseract OCR** for scans. All formats share the same output fields. No API key, no third-party AI service, and your files never leave the run.

**Markdown an LLM can use:** headings from font sizes and bold titles (in PDFs too), two-column papers in the right order, real Markdown tables (including booktabs tables without vertical lines), and repeated headers, footers and page numbers removed. Invisible `<!-- Page 3 -->` markers (`Slide` / `Sheet` for PowerPoint and Excel) and per-chunk `pages` and `headingPath` let you cite sources.

**Use cases:**

- **AI / RAG pipelines:** manuals, policies and contracts as chunks with page references for Pinecone, Qdrant, Weaviate or pgvector.
- **LLM ingestion:** clean Markdown instead of messy PDF text for GPT, Claude, Gemini or Llama, with fewer tokens.
- **Developers and search teams:** text and metadata (title, author, dates, pages) for Elasticsearch, Algolia or Typesense.
- **Automation agencies:** text from invoices, reports and scanned letters in n8n, Make or Zapier, or as an MCP tool for agents.
- **Data migration:** old DOC/RTF/ODT/XLS archives into Markdown for Notion, Confluence or Obsidian.

#### Output fields

| Field | Description | Example |
|---|---|---|
| `url` / `finalUrl` | Your URL / the URL after redirects | `https://arxiv.org/pdf/2401.18059` |
| `source` | `url` or `keyValueStore` | `url` |
| `keyValueStoreKey` | Record key (store input) | `null` |
| `fileName` | File name | `2401.18059v1.pdf` |
| `format` | Detected format | `pdf` |
| `mimeType` | MIME type | `application/pdf` |
| `sizeBytes` | File size | `2547113` |
| `title` | Document title | `RAPTOR: ...` |
| `pages` | Total pages, slides, sheets or frames | `23` |
| `pagesConverted` | Pages converted (null for Word/HTML) | `23` |
| `wordCount` / `charCount` | Text size | `12132` |
| `tableCount` | Markdown tables | `13` |
| `ocrUsed` / `ocrPages` | OCR used, and on which pages | `false` / `[]` |
| `ocrConfidence` | Mean Tesseract confidence, 0-100 | `95.8` |
| `markdown` / `text` | Converted content (per output format) | `<!-- Page 1 -->\n# RAPTOR...` |
| `pageContents[]` | Optional per-page `page`, `type`, `ocr`, `markdown`/`text` | - |
| `chunks[]` | Optional `index`, `text`, `headingPath`, `pages`, `charCount` | see below |
| `metadata` | Author, creator, producer, dates... | `{"producer": "pdfTeX-1.40.25"}` |
| `truncated` | Pages skipped by your limit | `false` |
| `warnings` | Non-fatal notes | `[]` |
| `error` / `errorCode` | Failure reason (null on success) | `null` |
| `convertedAt` | UTC timestamp | `2026-10-05T03:20:13Z` |

#### Supported formats

- **Documents:** PDF, DOCX/DOCM, PPTX, XLSX/XLSM, XLS, CSV/TSV, HTML, EPUB, ODT, ODS, ODP, RTF, DOC (legacy Word, text only), TXT, Markdown, JSON, XML and Jupyter notebooks.
- **Images (OCR):** PNG, JPG, TIFF (multi-page), BMP, GIF and WEBP.
- **Not supported:** legacy `.ppt`, ZIP archives and encrypted Office files. Save them as PPTX/DOCX or unzip them first.

**Use cases:** Developer tools (AI and LLM integrations, transform & process data, process & convert media) · Collect & distribute content.

### 🚀 How to use Document to Markdown

1. Open [Document to Markdown](https://apify.com/kadi_bence/document-to-markdown) on Apify Store and click **Try for free**.
2. Paste **document URLs**, one per line. You can also **upload files** or point the actor to an Apify **key-value store** that holds your files.
3. Choose the **output format** (Markdown, text or both). If you want them, turn on **RAG chunks**, **per-page content** or more **OCR languages**.
4. Click **Start**. The prefilled example (an arXiv paper, a Word file and a scanned TIFF) finishes in about 10 seconds.
5. Download the results, or read them through the API, n8n, Make, Zapier, LangChain or LlamaIndex.

### 🔧 Input guide

**Document URLs (`urls`).** Direct file links; the type is detected from the content.

- Good: `https://arxiv.org/pdf/2401.18059`, a pre-signed S3/Azure/GCS link, a key-value store record URL.
- Bad: a login-protected link, a Google Drive share link, or a web page that only *links* to the PDF (it is converted as HTML, with a warning).
- Duplicates are skipped; non-http(s) entries are listed in RUN_SUMMARY.

**Uploads and key-value store (`uploadedFiles`, `keyValueStoreId`, `keyValueStoreKeys`).** Uploads go to your own key-value store. For files already in Apify storage, give the store ID or name; all records are converted unless you list keys.

**Output (`outputFormat`, `includeTables`, `includePageMarkers`, `includePageContents`).** `markdown` (default), `text` or `both`. Tables and page markers are on by default. Per-page content adds `pageContents[]`.

**RAG chunks (`chunkSize`, `chunkOverlap`).** `0` = off. Otherwise `chunks[]` of about N characters (minimum 200), split on headings, paragraphs and tables, with 200 characters of overlap by default. 1,500-3,000 characters suits most embedding models.

**OCR (`ocrMode`, `ocrLanguages`).** `auto` OCRs only images and pages without a text layer. `always` OCRs every PDF page (for broken text layers; every page is then charged). `off` never OCRs, so scans fail as free `no_text` errors. Languages: English, German, French, Spanish, Italian; each extra one slows OCR.

**Limits and performance.**

- `maxPagesPerDocument`: 200 (up to 5,000); extra pages are skipped and the item is `truncated`. `pageRange`: e.g. `1-5, 8, 20-`.
- `maxFileSizeMb`: 50 (up to 500); larger files are skipped for free. Above 100 MB, use 4-8 GB of memory.
- Up to 10,000 documents per run and 10,000 rows per spreadsheet sheet.
- 5 parallel downloads, 120 s timeout, two retries on 429/5xx and timeouts. Each 2 GB of memory converts one more document in parallel (up to 4).

**Other options.** `removeHeadersFooters` (on) drops repeated PDF headers and footers. `pdfPassword` unlocks encrypted PDFs and is stored as a secret.

**Polite downloading.** robots.txt (including crawl-delay) is respected on every host and redirect. Private and internal network addresses are refused.

Full example input:

```json
{
  "urls": [
    "https://arxiv.org/pdf/2401.18059",
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx",
    "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
  ],
  "outputFormat": "markdown",
  "chunkSize": 2000,
  "chunkOverlap": 200,
  "ocrMode": "auto",
  "ocrLanguages": ["eng", "deu"],
  "maxPagesPerDocument": 200,
  "maxFileSizeMb": 50
}
```

### 📦 Output

One dataset item per document. Real item from a run on 2026-10-05 (`markdown` shortened):

```json
{
  "url": "https://arxiv.org/pdf/2401.18059",
  "source": "url",
  "keyValueStoreKey": null,
  "fileName": "2401.18059v1.pdf",
  "format": "pdf",
  "mimeType": "application/pdf",
  "sizeBytes": 2547113,
  "title": "RAPTOR: RECURSIVE ABSTRACTIVE PROCESSING FOR TREE-ORGANIZED RETRIEVAL",
  "pages": 23,
  "pagesConverted": 23,
  "wordCount": 12132,
  "charCount": 75919,
  "tableCount": 13,
  "ocrUsed": false,
  "ocrPages": [],
  "ocrConfidence": null,
  "markdown": "<!-- Page 1 -->\n# RAPTOR: RECURSIVE ABSTRACTIVE PROCESSING FOR TREE-ORGANIZED RETRIEVAL\n\nParth Sarthi, Salman Abdullah, ...\n\n## ABSTRACT\n\nRetrieval-augmented language models can better adapt to changes in world state ...",
  "text": null,
  "metadata": { "creator": "LaTeX with hyperref", "producer": "pdfTeX-1.40.25", "createdAt": "2024-02-01T01:45:46", "modifiedAt": "2024-02-01T01:45:46" },
  "truncated": false,
  "warnings": [],
  "error": null,
  "errorCode": null,
  "convertedAt": "2026-10-05T03:20:13Z"
}
```

A table from the same paper, as it appears in `markdown`:

```markdown
| Model | ROUGE | BLEU-1 | BLEU-4 | METEOR |
|---|---|---|---|---|
| SBERT with RAPTOR | 30.87% | 23.50% | 6.42% | 19.20% |
| SBERT without RAPTOR | 29.26% | 22.56% | 5.95% | 18.15% |
```

**The scanned TIFF from the same run** has `"format": "image"`, `"ocrUsed": true`, `"ocrConfidence": 95.8` and this markdown:

`"This is a lot of 12 point text to test the ocr code and see if it works on all types of file format.\n\nThe quick brown dog jumped over the lazy fox. ..."`

**Optional `chunks[]` items** (`chunkSize: 2000`, from the NIST AI RMF PDF, text shortened):

`{"index": 10, "text": "uncertainties in their models and systems, which in turn can improve overall sys...", "headingPath": ["Artificial Intelligence Risk Management Framework (AI RMF 1.0)", "Part 1: Foundational Information", "1.1 Understanding and Addressing Risks, Impacts, and Harms"], "pages": [9, 10], "charCount": 1580}`

**Failed documents** are free rows with `error` and `errorCode`: `http`, `robots`, `too_large`, `password_required`, `unsupported_format`, `no_text`, `invalid_file`, `blocked_host`, `dns`, `timeout`, `empty_file` (rarer: `refused`, `tls`, `network`, `not_found`, `internal`).

**Dataset views:** **Documents** (overview), **Markdown**, **Metadata** (MIME type, size, OCR details, warnings) and **Errors**.

**RUN_SUMMARY** (key-value store) holds the totals: documents, errors by code, formats, pages, OCR pages, charged events, invalid inputs, charge-limit status and duration. Your files are not saved.

**Export** as JSON, CSV, Excel, XML, RSS or an HTML table, or read it through the API.

### 💵 Pricing: $2 per 1,000 documents

| Event | Price | When |
|---|---|---|
| `document` | **$0.002** | Per successfully converted document. Each **started 20 pages** (PDF pages, slides, sheets) counts once, so a 1-20 page file = 1, a 45-page file = 3. Word/HTML/text files count 500 words as one page (one event per 10,000 words) |
| `ocr-page` | **$0.002** | Per page or image actually read with OCR (auto mode never OCRs pages that have a text layer) |

Apify also charges its tiny **$0.00005 per-run start fee**. Platform compute is included in the prices above. Failed, empty, password-protected and unsupported files are listed with the reason but **never charged**.

| Typical run | Events | Cost |
|---|---|---|
| 100 Word files or short PDFs (up to 20 pages) | 100 `document` | **$0.20** |
| 1,000 ten-page PDFs | 1,000 `document` | **$2.00** |
| 100 PDFs of 100 pages | 500 `document` | **$1.00** |
| 10 scanned PDFs of 20 pages | 10 `document` + 200 `ocr-page` | **$0.42** |

Add $0.00005 per run for the start fee. You can cap spending with **Max charge per run**. The run stops cleanly at your limit and never delivers a document it could not charge.

### 🔌 Use it via API

**JavaScript** (`npm install apify-client`):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('kadi_bence/document-to-markdown').call({
    urls: ['https://arxiv.org/pdf/2401.18059'],
    chunkSize: 2000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].chunks.length);
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_API_TOKEN')
run = client.actor('kadi_bence/document-to-markdown').call(
    run_input={'urls': ['https://arxiv.org/pdf/2401.18059'], 'outputFormat': 'both'}
)
for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['fileName'], item['wordCount'], item['errorCode'])
```

**cURL** (runs the actor and returns the items in one call):

```bash
curl -X POST "https://api.apify.com/v2/acts/kadi_bence~document-to-markdown/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://arxiv.org/pdf/2401.18059"], "chunkSize": 2000}'
```

**Apify CLI:**

```bash
apify call kadi_bence/document-to-markdown --input '{"urls": ["https://arxiv.org/pdf/2401.18059"]}'
```

**MCP for AI agents** (Claude, Cursor, VS Code and other MCP clients):

```json
{"mcpServers": {"apify": {"url": "https://mcp.apify.com/?actors=kadi_bence/document-to-markdown"}}}
```

### 🔗 Integrations & scheduling

- **Schedules:** run on a cron, e.g. nightly.
- **Webhooks:** on "run succeeded", Apify calls your URL with the run ID.
- **Zapier, Make, n8n:** start runs and read results with the Apify app or node.
- **Google Sheets, Slack, email:** via Apify integrations or the tools above.

**Recipes:**

1. **Convert new PDFs for a RAG pipeline.** Your app or n8n/Make flow starts the actor with only the newly added PDF URLs and `chunkSize: 2000` (it does not remember earlier runs). A "run succeeded" webhook calls your ingest endpoint, which embeds `chunks[]` and stores `url`, `pages` and `headingPath` as metadata.
2. **Document inventory:** export the **Documents** view to Google Sheets.
3. **Failure alerts:** a Make or n8n flow posts the **Errors** view to Slack.

### 🧰 Related tools by the same developer

**Content pipelines**

- [Bulk Image Downloader](https://apify.com/kadi_bence/bulk-image-downloader): all images and files from pages into a ZIP. $0.80 / 1,000 files.

**Website due diligence**

- [Website Tech Stack Detector](https://apify.com/kadi_bence/tech-stack-detector): CMS, ecommerce, analytics and frameworks from 7,600+ fingerprints. $1.50 / 1,000 websites.
- [SEO Site Audit Crawler](https://apify.com/kadi_bence/seo-site-audit): broken links, redirects, titles/meta, canonical and hreflang on every page. $1.50 / 1,000 pages.
- [Website Screenshot & PDF API](https://apify.com/kadi_bence/website-screenshot): full-page/mobile PNG, JPEG, WebP and PDF captures. $2.50 / 1,000 screenshots.
- [Bulk WHOIS & RDAP Domain Lookup](https://apify.com/kadi_bence/domain-whois-lookup): registrar, age, expiry, DNS/MX/SPF/DMARC. $1.50 / 1,000 domains.

### ❓ FAQ

**How does it work?**
It downloads each file, detects the format from the content and converts it with open-source libraries inside the run (pdfplumber for PDFs, Tesseract for scans). No external AI or OCR API is called.

**What are the limits?**
200 pages and 50 MB per document by default (up to 5,000 pages and 500 MB), 10,000 documents per run and 10,000 rows per sheet.

**How good are PDF tables?**
Ruled tables and booktabs-style tables (scientific papers, many reports) become Markdown tables. Tables with no lines at all come out as text lines in reading order. Word, PowerPoint, Excel and HTML tables are always converted exactly.

**Does OCR work on handwriting or photos?**
OCR is Tesseract 5.5 (LSTM). It works best on printed text and scans: typically 90%+ confidence on clean 200-300 dpi scans. Handwriting and poor phone photos give poor results.

**How fast is it?**
In our tests: text PDFs about 0.1 s per page, OCR about 1-2 s per scanned page (1 CPU core), Office files under a second each. The prefilled 3-document example takes about 10 seconds.

**Which URLs can it download? What about blocked sites?**
Direct file links you supply. Files disallowed by robots.txt fail as free `robots` errors. Login-protected files can't be fetched: use pre-signed links or upload them. Google Drive disallows automated downloads, so download and upload those files.

**Are my files stored? Is it legal?**
Files stay in memory only for the conversion. Only your dataset and RUN_SUMMARY are saved, under your account's retention settings. Metadata such as `author` may contain personal names; handle it according to your own privacy obligations. You are responsible for having the right to process your documents (this is not legal advice).

**Can I use it from code or an AI agent?**
Yes: API, Python/JS clients, CLI or MCP (see above), with the same fields for every format.

**What does a big job cost?**
10,000 ten-page PDFs cost $20; 1,000 PDFs of 100 pages cost $10, plus any OCR pages. Cap it with **Max charge per run**, `maxPagesPerDocument` or `pageRange`.

**What if a document fails?**
It is listed with `error` and `errorCode`, is not charged, and the run continues. If a file should work, open an issue in the **Issues** tab with the URL and code.

**What's new?**
See the changelog below.

### 📝 Changelog

- **1.0 (2026-10-05):** First release. 20+ formats, PDF headings/tables/reading order, header and footer removal, page markers, RAG chunks with page references, Tesseract OCR (eng/deu/fra/spa/ita), key-value store input and file upload, password-protected PDFs. Failed documents are not charged.
- **2026-10-05:** Store page rewritten.

### 🤝 Need a custom version?

I build custom scrapers, scheduled data feeds and integrations (CSV, Excel, Google Sheets, API, MCP for AI agents). Tell me the sites and fields you need:

- Email: bence.kadi@gmail.com
- Apify profile: https://apify.com/kadi_bence

### Credits and licences

Built on open-source libraries, all under permissive licences:

- [MarkItDown](https://github.com/microsoft/markitdown) (MIT, © Microsoft) for Word, PowerPoint, HTML and EPUB
- [pdfplumber](https://github.com/jsvine/pdfplumber) (MIT) and [pdfminer.six](https://github.com/pdfminer/pdfminer.six) (MIT) for PDF text and layout
- [pypdfium2](https://github.com/pypdfium2-team/pypdfium2) (Apache-2.0 / BSD-3) for page rendering
- [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) (Apache-2.0) via pytesseract (Apache-2.0)
- [openpyxl](https://openpyxl.readthedocs.io) (MIT) and [xlrd](https://github.com/python-excel/xlrd) (BSD) for spreadsheets
- [striprtf](https://github.com/joshy/striprtf) (BSD-3) for RTF
- [antiword](https://packages.debian.org/antiword) (GPL-2.0, run as a separate program) for legacy `.doc`

This actor is not affiliated with Microsoft, Adobe or Google. Product names are trademarks of their owners.

Sample documents in the prefilled input:

- the arXiv paper 2401.18059 (CC BY 4.0, Sarthi et al.)
- `test.docx` from the MarkItDown test suite (MIT)
- `phototest.tif` from the Tesseract test repository (Apache-2.0)

### Related Actors

More low-cost Actors by the same developer, built on official APIs and public data:

- [Website Screenshot & PDF API](https://apify.com/kadi_bence/website-screenshot) — full-page screenshots and PDFs of any URL
- [Bulk Image Downloader](https://apify.com/kadi_bence/bulk-image-downloader) — download all images from URLs as a ZIP
- [AI Visibility Tracker](https://apify.com/kadi_bence/ai-visibility-tracker) — how ChatGPT, Perplexity, Gemini and Claude mention your brand
- [TED Tenders Scraper](https://apify.com/kadi_bence/ted-tenders-scraper) — EU public tenders and contract award winners
- [SAM.gov Scraper](https://apify.com/kadi_bence/sam-gov-scraper) — US federal contract opportunities and awards
- [SEO Site Audit](https://apify.com/kadi_bence/seo-site-audit) — 0-100 SEO score per page, broken links and fix hints
- [Website Tech Stack Detector](https://apify.com/kadi_bence/tech-stack-detector) — CMS, ecommerce, analytics and frameworks of any website

All my Actors: [apify.com/kadi_bence](https://apify.com/kadi_bence)

# Actor input Schema

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

Direct links to the files, one per line, e.g. https://arxiv.org/pdf/2401.18059. Supported: PDF, DOCX, PPTX, XLSX/XLS, CSV, HTML, EPUB, ODT/ODS/ODP, RTF, DOC, TXT/MD/JSON and images (PNG, JPG, TIFF, BMP, GIF, WEBP). The file type is detected from the content, so links without an extension are fine. Apify key-value store record URLs and pre-signed S3/Azure/GCS links work too. Login pages and Google Drive share links do not.

## `uploadedFiles` (type: `array`):

Optional. Upload documents from your computer. They are stored in your own Apify account's key-value store, under your control.

## `keyValueStoreId` (type: `string`):

Optional. ID or name of an Apify key-value store that holds your files, e.g. my-contracts (Console > Storage > Key-value stores, or the API). Every record is converted unless you list keys below.

## `keyValueStoreKeys` (type: `array`):

Optional. Only convert these records of the key-value store above, e.g. handbook.pdf. Leave empty to convert all records.

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

Markdown keeps headings, lists and tables (best for LLMs and RAG). Plain text has no markup. Both = a markdown and a text field per document.

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

Keep tables as Markdown tables (PDF tables with ruling lines or booktabs rules, Word, PowerPoint, Excel, HTML). Off = table cells as tab-separated text lines.

## `includePageMarkers` (type: `boolean`):

Insert  (Slide / Sheet for PowerPoint and Excel) before each page, so you can cite page numbers. Markers are HTML comments, so they are invisible when the Markdown is rendered.

## `includePageContents` (type: `boolean`):

Also return a pageContents array with the content of each page, slide or sheet separately. Useful when you index page by page.

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

0 = no chunks. Otherwise also return chunks\[] of about this many characters, split on headings, paragraphs and tables, each with its heading path and page numbers. Example: 2000. 1,500-3,000 characters (~400-800 tokens) suits most embedding models.

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

How many characters at the end of one chunk are repeated at the start of the next one, e.g. 200. Only used when the chunk size is above 0.

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

Auto = read images and PDF pages that have no text layer with Tesseract OCR; normal text pages are extracted directly (fast, exact). Always = OCR every PDF page (for PDFs with a broken text layer). Off = never OCR. Each OCR page is charged as an ocr-page event.

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

Languages in the scanned documents, e.g. English + German. Pick only the ones you need: each extra language makes OCR slower.

## `removeHeadersFooters` (type: `boolean`):

Drop running headers, footers and page numbers that repeat on most PDF pages, so they don't pollute your chunks.

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

Convert at most this many pages (PDF pages, slides, sheets or image frames) of each document, e.g. 50. The rest is skipped and the item is marked truncated. Fewer pages = lower cost.

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

Optional, e.g. 1-5, 8, 20- . Applies to PDF pages, slides, sheets and image frames. Empty = all pages.

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

Larger files are skipped and not charged. Give the run more memory (4-8 GB) for files above 100 MB.

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

How many files are downloaded at the same time, e.g. 5. Conversion itself uses the CPU of the run (give it 4-8 GB of memory to convert several big files in parallel).

## `requestTimeoutSecs` (type: `integer`):

Give up on a download after this many seconds, e.g. 120. Downloads are retried twice on 429/5xx errors and timeouts.

## `pdfPassword` (type: `string`):

Optional password for encrypted PDFs, used for all PDFs in this run. Stored as a secret. Encrypted Office files are not supported.

## Actor input object example

```json
{
  "urls": [
    "https://arxiv.org/pdf/2401.18059",
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx",
    "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
  ],
  "outputFormat": "markdown",
  "includeTables": true,
  "includePageMarkers": true,
  "includePageContents": false,
  "chunkSize": 0,
  "chunkOverlap": 200,
  "ocrMode": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "removeHeadersFooters": true,
  "maxPagesPerDocument": 200,
  "maxFileSizeMb": 50,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 120
}
```

# Actor output Schema

## `overview` (type: `string`):

File, type, title, pages, words, tables, OCR and error per document.

## `markdown` (type: `string`):

The converted Markdown of each document.

## `full` (type: `string`):

All fields incl. text, chunks, per-page content and metadata.

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

Counts, formats, pages, OCR pages, charged events and errors.

# 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/2401.18059",
        "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx",
        "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kadi_bence/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://arxiv.org/pdf/2401.18059",
        "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx",
        "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("kadi_bence/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://arxiv.org/pdf/2401.18059",
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx",
    "https://raw.githubusercontent.com/tesseract-ocr/test/main/testing/phototest.tif"
  ]
}' |
apify call kadi_bence/document-to-markdown --silent --output-dataset

```

## MCP server setup

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