# Document to Markdown for RAG and AI Agents (`kadev-code/doc-to-markdown`) Actor

Convert PDF, DOCX, PPTX, XLSX and HTML into Markdown with tables, titles and optional chunks. No OCR or AI models.

- **URL**: https://apify.com/kadev-code/doc-to-markdown.md
- **Developed by:** [Kadev Code](https://apify.com/kadev-code) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 converted 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 for RAG and AI Agents

Convert PDF, DOCX, PPTX, XLSX and HTML documents into clean Markdown for retrieval augmented generation, document search and AI agents. This Actor extracts text with deterministic document parsers. It requires no browser, language model, API key, OCR engine or model download. Its narrow parser stack avoids the model and rendering dependencies of heavier document pipelines.

Semantic headings and tables are preserved where the source provides them. Word heading styles become Markdown headings, presentation titles become headings, and each populated workbook sheet becomes a heading followed by a table. HTML scripts, styles, navigation, footers and images are removed. PDF headings are inferred conservatively from whole lines and relative font sizes. PDF titles use meaningful metadata, then the largest useful first-page text, excluding license notices. Font-relative spacing preserves words in tightly spaced PDFs, including LaTeX documents.

PDF pages are normalized when at least 80% of their nonblank characters share a 90°, 180° or 270° text orientation. This also handles page-level `/Rotate` values. Text and ruled tables are then extracted in that reading frame; other rotated text is excluded. The conservative 80% threshold keeps diagram axis labels from changing the page orientation. On mixed pages below that threshold, horizontal text is kept and rotated text is omitted. Arbitrary angles and pages without a consistent orientation can lose meaningful rotated content.

Useful ruled PDF tables become Markdown tables and are appended after the prose on their page. Very sparse grids, grids with mostly short labels, and tables over 20 columns stay as prose; this can also affect compact numeric tables. Diagram fragments are not promoted to headings based on font size alone. Complex layouts, borderless tables, merged cells and multi-column reading order may need manual review. No parser can guarantee identical visual layout in Markdown.

### Input

The default input is a bundled, public-domain HTML example. It runs without network access:

```json
{"documents": [{"example": true}]}
```

Use a public direct-download URL or a binary file that you placed in an Apify key-value store:

```json
{
  "documents": [
    {"url": "https://example.org/report.pdf"},
    {"key": "REPORT", "storeId": "your-store-id", "filename": "report.docx"}
  ],
  "includeMetadata": true,
  "maxFileSizeMB": 10,
  "maxPages": 100,
  "maxSheets": 20,
  "maxChars": 1000000,
  "chunkSize": 2000
}
```

Replace the illustrative URL and store identifier with your own sources. Provide exactly one of `url`, `key` or `example` per document. Omit `storeId` to use the run's default store. Upload Office/PDF records as binary content, or HTML as text; JSON/base64 record bodies are not supported. Set `filename` for extensionless records. Recognized MIME types and file signatures also identify extensionless downloads. HTTP redirects are followed with DNS and connected-address checks at each hop. Only public HTTP(S) addresses on ports 80/443 are accepted, with no embedded username or password. No linked pages, images or external Office relationships are downloaded.

`includeMetadata` adds filename, format and byte size. `chunkSize=0` disables chunks. A positive value returns consecutive character slices with exclusive `endChar` offsets, no overlap and no additional charge. Slices can split a table, heading or word; retain the full Markdown for structural processing.

### Output

One dataset item is written for every attempted document, including failures. Sources skipped after the 55-second processing budget expires receive a free row with `error: "Skipped: run processing budget exhausted"`. Sources beyond your spending limit are not attempted and have no row. A default run returns:

```json
{
  "url": "example://sample.html",
  "title": "RAG document example",
  "markdown": "# RAG document example\n\nA local example that requires no network access.\n\n## Revenue\n\n| Quarter | USD |\n| --- | --- |\n| Q1 | 120 |\n| Q2 | 180 |",
  "pageCount": null,
  "sheetCount": null,
  "charCount": 143,
  "error": null,
  "metadata": {"filename": "sample.html", "format": "html", "sizeBytes": 372}
}
```

`pageCount` counts PDF pages or PPTX slides. DOCX pagination requires a renderer and is returned as `null`; HTML and XLSX also have no page count. `sheetCount` is only populated for XLSX. Workbook formulas use their saved cached values; this Actor does not recalculate formulas. The first populated row of each table becomes its Markdown header. Optional chunks contain `index`, `startChar`, `endChar` and `text`.

### Pricing and limits

The price is **USD 0.004 per successful document**, or USD 4 per 1,000 documents, with no start fee. Failed downloads, empty output, corrupt documents, rejected limits and sources skipped after the processing budget generate no conversion charge. Metadata and chunks are included. A result must be delivered before it becomes eligible for a conversion charge. The Actor stops when your spending limit is reached. A billing failure can leave an already delivered result uncharged and stops further processing.

There are at most 20 sources, 20 MiB per source, 200 PDF pages/slides, 50 sheets and 2,000,000 output characters. Defaults are lower; see the input schema. Office ZIPs are capped at 50 MiB expanded and 5,000 parts; workbooks are capped at 100,000 cells. Limits reject the whole document rather than returning partial output. HTTP operations use a 10-second timeout and up to two retries with exponential backoff for transient errors. A document has a 20-second processing deadline; the run has a 55-second processing budget; remaining sources receive free skipped rows. Split larger batches across runs if needed. Storage and SDK cleanup can extend total wall time. Memory allocation is 512 MiB.

Scanned/image-only PDFs need OCR and return a free error. Encrypted files, invalid archives, unsupported formats, blocked downloads and unavailable KVS records also return clear errors. A malformed top-level input produces one free diagnostic row. Unexpected parser details are hidden to avoid leaking document contents into logs.

### Responsible use and retention

Use only public sources or files you have permission to process. Do not submit
private third-party documents or unnecessary personal information. Temporary
conversion files are removed when processing ends, including failed or timed-out
conversions. Uploaded KVS records remain under your control, and derived Markdown
remains in the run's dataset. Manage source and dataset retention in your Apify
account. The bundled example is dedicated to the public domain (CC0).

# Actor input Schema

## `documents` (type: `array`):

One source per object: {"url":"https://.../file.pdf"}, {"key":"report.docx","storeId":"optional-store-id"}, or {"example":true}. Optional filename identifies extensionless sources. Limit: 20 documents.

## `includeMetadata` (type: `boolean`):

Add filename, detected format and source size in bytes. Title and page/sheet counts are always returned.

## `maxFileSizeMB` (type: `integer`):

Reject files larger than this size without charging. Office archives also have a fixed 50 MiB expanded-size limit.

## `maxPages` (type: `integer`):

Reject the whole PDF or PPTX when the page/slide count exceeds this limit. DOCX pagination is not available without a renderer.

## `maxSheets` (type: `integer`):

Reject workbooks with more sheets. All workbooks also have a fixed 100000-cell limit.

## `maxChars` (type: `integer`):

Reject oversized conversion output instead of silently truncating a document.

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

Return consecutive non-overlapping chunks with zero-based startChar/endChar offsets. Exact character cuts may split Markdown tables or headings.

## Actor input object example

```json
{
  "documents": [
    {
      "example": true
    }
  ],
  "includeMetadata": true,
  "maxFileSizeMB": 10,
  "maxPages": 100,
  "maxSheets": 20,
  "maxChars": 1000000,
  "chunkSize": 0
}
```

# Actor output Schema

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

Complete Markdown, source identifiers and conversion errors in the default dataset.

# 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 = {
    "documents": [
        {
            "example": true
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kadev-code/doc-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 = { "documents": [{ "example": True }] }

# Run the Actor and wait for it to finish
run = client.actor("kadev-code/doc-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 '{
  "documents": [
    {
      "example": true
    }
  ]
}' |
apify call kadev-code/doc-to-markdown --silent --output-dataset

```

## MCP server setup

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