# Document to Markdown Converter for AI (`jetlaunch/document-to-markdown-converter`) Actor

Convert PDF, DOCX, PPTX, XLSX, EPUB, HTML and images (with OCR) from public URLs into clean Markdown and structured JSON for AI agents and RAG.

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

## Pricing

from $15.00 / 1,000 document converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Document to Markdown Converter for AI

Turn documents from public URLs into clean Markdown and structured JSON that language models, RAG pipelines and AI agents can use directly. It reads PDF, DOCX, PPTX, XLSX, EPUB, HTML and images (PNG, JPEG, TIFF, BMP, WEBP, GIF), with OCR for scanned pages.

Each output record has the Markdown text, the tables as CSV or JSON, the headings with levels and page numbers, page and word counts, an OCR flag, document metadata and warnings. Layout is recovered with reading order, so multi-column pages and tables come out as text a model can follow.

### Who it is for

- Developers feeding documents into vector databases, knowledge bases or prompts
- AI agent builders who need one tool call that turns a link into usable text
- Analysts who want tables out of PDFs, slide decks and spreadsheets as CSV
- Teams that must handle mixed files (Word, PowerPoint, Excel, EPUB, scans) with one input format

### What it does

1. Downloads each URL (http or https only, up to 50 MB).
2. Detects the format from the file content, not the file name.
3. Converts it with Docling, an open source document converter (MIT licence). If Docling fails on a file, the MarkItDown library (MIT licence) is used as a fallback and a warning says so.
4. Reads scanned pages and images with OCR when OCR is on. Pages that already have a text layer are never sent to OCR.
5. Pushes one record per URL and deletes the downloaded file.

All AI models are baked into the image, so runs make no model downloads and your documents are not sent to any third-party AI service.

### Input

| Field | Meaning |
| --- | --- |
| urls | Public document links, up to 200 per run |
| ocr | Read scanned pages and images (default on) |
| ocrQuality | fast (default) or high, a larger model for noisy scans |
| pageRange | PDF only, for example 1-10, 5 or 3- |
| includeMarkdown | Include the Markdown text (default on) |
| tableFormat | csv, json, both or none |
| tableMode | fast (default) or accurate for complex tables, about 1.5 times slower |
| includeDoclingJson | Save the full structured document to the key-value store |
| maxPagesPerDocument | Refuse documents above this many pages, up to 200 |
| maxFileSizeMb | Refuse files above this size, up to 50 |

Example input:

```json
{
  "urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"],
  "pageRange": "1-3",
  "ocr": true,
  "tableFormat": "csv"
}
```

### Output

One record per URL, in the dataset. A shortened example:

```json
{
  "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
  "status": "ok",
  "format": "pdf",
  "engine": "docling",
  "markdown": "## Form W-9\n\n(Rev. March 2024)\n\nDepartment of the Treasury ...",
  "tables": [{"index": 1, "page": 3, "num_rows": 6, "num_columns": 2, "csv": "IF the entity/individual ...,THEN check the box for ...\n..."}],
  "headings": [{"level": 2, "text": "Form W-9", "page": 1}],
  "page_count": 6,
  "pages_processed": 3,
  "word_count": 3650,
  "ocr_used": false,
  "ocr_pages": 0,
  "metadata": {"title": "Form W-9 (Rev. March 2024)", "pages_converted": "1-3", "file_size_bytes": 140815},
  "warnings": [],
  "charged": true
}
```

A document that cannot be converted still gets a record with status "error", an error_code (for example private_address, file_too_large, too_many_pages, password_protected, unsupported_format, no_text_extracted, http_error) and a plain message. Error records are never charged.

What counts as a page: a PDF page, a PPTX slide, an XLSX sheet, or one image. DOCX, HTML and EPUB have no fixed pages, so they count 1 page per 1,000 words, rounded up. The warnings list says when this estimate was used.

### Pricing

Pay per event. You are charged only for documents that were converted and produced text.

| Event | Price | When |
| --- | --- | --- |
| Document converted | $0.015 | Once per successfully converted document |
| Page processed | $0.006 | Per page in a converted document |
| OCR page | $0.015 | Per page that had no text layer and was read with OCR, on top of the page price |

Examples: a 10-page PDF with text costs $0.075. A 10-page scanned PDF costs $0.225. A 30,000-word EPUB counts as 30 pages and costs $0.195. Apify also adds its standard run start charge, a fraction of a cent. Set a maximum cost per run in the run options: the Actor skips any document that could exceed the remaining budget, without charge.

### Limits and safety

- Maximum 50 MB and 200 pages per document. Larger files and longer PDFs are refused without charge. Use pageRange to convert part of a long PDF.
- Only http and https on ports 80, 443, 8080 and 8443. URLs that resolve to private, loopback, link-local or cloud metadata addresses are refused, also after every redirect.
- Downloaded files are deleted after each document. Document content is never written to the run log.
- Legacy .doc, .ppt and .xls, password protected files, and files behind a login are not supported.
- OCR is tested on English, French, German, Spanish, Polish, Portuguese, Italian and Chinese text, which read accurately with either OCR quality setting. For Japanese, set ocrQuality to high: the fast setting misreads Japanese characters. Cyrillic text (Russian, Ukrainian and similar) is not read correctly yet with either setting. Handwriting and very low quality scans may give weak results.
- Speed on the platform with 4 GB: about 5 to 10 seconds per text PDF page, about 10 to 20 seconds per scanned page, and a fixed 30 to 45 seconds of start-up per run. Office, HTML and EPUB files take a few seconds.
- Table extraction can miss or merge cells in complex layouts. Try tableMode accurate.
- The link in docling_json_url needs your Apify API token or the Console.

### Sources and licences

The Actor runs on Docling (MIT) and MarkItDown (MIT). The baked-in model weights are the Docling layout model (Apache-2.0), the TableFormer table model (CDLA-Permissive-2.0) and PaddleOCR PP-OCRv6 models run through RapidOCR (Apache-2.0). Documents you convert keep whatever rights and licences they have; you are responsible for having the right to process them. This Actor is not affiliated with or endorsed by IBM, Microsoft, Docling, MarkItDown, PaddlePaddle or any other project named here.

### FAQ

**Does it work on scanned PDFs?** Yes. Pages with no text layer are read with OCR and billed as OCR pages. Turn OCR off to skip them.

**Why is a page charged for a Word file?** Word, HTML and EPUB files have no fixed pages, so 1,000 words count as one page. Conversion of these formats is quick, and the price stays low.

**Can I get the tables as data?** Yes. Set tableFormat to csv, json or both. Each table has its page, row count and column count.

**Is my document sent to an AI service?** No. Everything runs inside the Actor container with models included in the image.

**What if one URL fails?** The other documents still run. The failed one gets an error record and no charge.

**Can I use it from code or an agent?** Yes, through the Apify API, the client libraries or the Apify MCP server. The output is plain JSON.

### Support

Open an issue in the Issues tab of this Actor with the URL (if public), the format and the run ID. Bugs in conversion quality are tracked there as well.

# Actor input Schema

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

Public http or https links to documents, one per line. Up to 200 per run. Links to private networks, localhost or cloud metadata addresses are refused.

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

Read text from pages that have no text layer and from image files. Pages that already contain text are never sent to OCR, so leaving this on only costs extra for scanned content (event: OCR page). Turn it off to skip scans and images.

## `ocrQuality` (type: `string`):

Fast uses the compact OCR model and is about three times quicker, with similar results on clean scans. High uses the larger model for noisy, small or low-contrast text.

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

Convert only some pages of each PDF, for example 1-10, 5 or 3- (page 3 to the end). Leave empty for all pages. Ignored for other formats.

## `includeMarkdown` (type: `boolean`):

Put the converted Markdown text in each output record. Turn it off if you only need tables, headings and metadata.

## `tableFormat` (type: `string`):

How extracted tables are returned in the tables list: CSV text, JSON (columns and rows), both, or none. Tables are always kept in the Markdown as well.

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

Fast is right for most documents. Accurate reads complex tables better and takes about 1.5 times longer.

## `includeDoclingJson` (type: `boolean`):

Save the complete structured document (reading order, bounding boxes, every text and table item) as a JSON file in the run's key-value store. The record has a docling_json_url link. Not available when the fallback engine was used.

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

Documents with more pages than this are refused without charge. The upper limit is 200. Use the page range to convert part of a longer PDF.

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

Files larger than this are refused without charge. The upper limit is 50.

## Actor input object example

```json
{
  "urls": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ],
  "ocr": true,
  "ocrQuality": "fast",
  "pageRange": "1-3",
  "includeMarkdown": true,
  "tableFormat": "csv",
  "tableMode": "fast",
  "includeDoclingJson": false,
  "maxPagesPerDocument": 200,
  "maxFileSizeMb": 50
}
```

# Actor output Schema

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

One record per URL with Markdown, tables, headings, page and word counts, OCR flag, metadata and warnings.

# 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://www.irs.gov/pub/irs-pdf/fw9.pdf"
    ],
    "pageRange": "1-3"
};

// Run the Actor and wait for it to finish
const run = await client.actor("jetlaunch/document-to-markdown-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": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"],
    "pageRange": "1-3",
}

# Run the Actor and wait for it to finish
run = client.actor("jetlaunch/document-to-markdown-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": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ],
  "pageRange": "1-3"
}' |
apify call jetlaunch/document-to-markdown-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jetlaunch/document-to-markdown-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/Gzup8quGNtVeJbUCb/builds/8lbzInUQYKsz23fuy/openapi.json
