# PDF, Word, Excel, PowerPoint to Markdown & RAG Chunks (`tamatama/doc-to-markdown`) Actor

Convert PDF, DOCX, XLSX and PPTX files to clean Markdown, plain text or RAG-ready chunks with page numbers and heading paths. Tables become Markdown tables. $0.50 per 1,000 pages, pages without text are free.

- **URL**: https://apify.com/tamatama/doc-to-markdown.md
- **Developed by:** [Otama Labs](https://apify.com/tamatama) (community)
- **Categories:** AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## PDF, Word, Excel, PowerPoint to Markdown & RAG Chunks

Turn **PDF, DOCX, XLSX and PPTX** files into clean **Markdown**, **plain text** or **RAG-ready chunks** in one Actor. Headings are rebuilt from the layout, ruled tables become Markdown tables, and every chunk keeps its **page numbers and heading path**, so your LLM app can cite where an answer came from.

**$0.50 per 1,000 pages.** Pages without a text layer (scans, images) are listed in the output and **not charged**. No per-document fee.

### What you can use it for

- **RAG and AI search**: feed manuals, policies, reports and contracts into a vector database, with page references for citations.
- **AI agents**: let an agent read a PDF or an Office file from a link and get Markdown back.
- **Bulk text extraction**: convert a folder's worth of documents (by URL) into text for search, analysis or translation.
- **Spreadsheets and slides for LLMs**: Excel sheets become Markdown tables, slides become sections with their notes.

### Output example

With **Output format = Markdown** (one row per document):

```json
{
  "url": "https://example.com/remote-work-policy.pdf",
  "fileName": "remote-work-policy.pdf",
  "fileType": "pdf",
  "title": "Sample Document: Remote Work Policy",
  "pageCount": 2,
  "pagesConverted": 2,
  "chargedPages": 2,
  "pagesWithoutText": [],
  "markdown": "# Sample Document: Remote Work Policy\n\nThis is a sample document ...\n\n## 2. Equipment allowance\n\n| Role | Allowance (USD) | Monitor included |\n|---|---|---|\n| Engineering | 800 | Yes |\n| Design | 900 | Yes |\n| Sales | 500 | No |\n\n## 3. Working hours\n\n...",
  "charCount": 1137,
  "error": null,
  "convertedAt": "2026-10-20T03:05:12+00:00"
}
```

With **Output format = RAG chunks**, **Chunk size = 500** **Chunk overlap = 50** (one row per chunk; each chunk starts with the last line or words of the previous one):

```json
{
  "url": "https://example.com/remote-work-policy.pdf",
  "fileName": "remote-work-policy.pdf",
  "fileType": "pdf",
  "title": "Sample Document: Remote Work Policy",
  "chunkIndex": 3,
  "chunkCount": 4,
  "pageStart": 1,
  "pageEnd": 2,
  "headings": ["Sample Document: Remote Work Policy", "3. Working hours"],
  "text": "| Design | 900 | Yes |\n| Sales | 500 | No |\n\n## 3. Working hours\n\nCore hours are 10:00 to 15:00 ...",
  "charCount": 212
}
```

### How to use

1. Paste links to your documents in **Document URLs** (any public or signed download link, e.g. from S3, Google Cloud Storage or an Apify key-value store).
2. Pick an **Output format**: Markdown, plain text or RAG chunks.
3. Click **Start**. Results appear in the **Output** tab; download them as JSON, CSV or Excel, or read them through the API.

The Actor works well from code and from AI agents: call it through the Apify API or the Apify MCP server with a list of URLs and read the dataset.

### Input

| Field | What it does |
|---|---|
| **Document URLs** | Links to PDF, DOCX, XLSX or PPTX files. The type is detected from the file content, so download links without an extension work. Up to 50 MB per file. You can also link a text file that lists document URLs (up to 1,000). |
| Output format | `markdown` (default), `text` or `chunks`. |
| Chunk size / Chunk overlap | For RAG chunks: maximum characters per chunk (default 2,000) and characters repeated from the previous chunk (default 200). Chunks break at headings first, then at paragraphs and sentences. |
| Add page markers | Adds `<!-- page N -->` comments to the Markdown. |
| Max pages per document | Convert only the first N pages (0 = all, up to 1,000). |
| Max rows per Excel sheet | Default 1,000 rows per sheet. |

### How each format is converted

| Format | What you get |
|---|---|
| PDF | Text in reading order (multi-column pages included), headings from font sizes (`#` to `###`, plus bold one-line headings), bullet lists, ruled tables as Markdown tables. Rotated side text (e.g. preprint stamps) is skipped. |
| Word (.docx) | Headings from the document's heading styles, paragraphs, bullet and numbered lists, tables, in document order. |
| Excel (.xlsx) | One `##` section per sheet with the sheet as a Markdown table (values, not formulas; dates as ISO dates). |
| PowerPoint (.pptx) | One `##` section per slide with its title, text (bullets keep their indentation), tables and speaker notes. |

### Pricing

Pay per event: **$0.50 per 1,000 pages** (`page` event, $0.0005), plus Apify's tiny start fee of $0.00005 per run.

Examples: a 20-page PDF costs $0.01. 1,000 pages of reports cost $0.50. A 10-slide deck costs $0.005.

What counts as a page:

- **PDF**: each page that has text. Pages without text (scans, images only) are free and listed in `pagesWithoutText`.
- **PowerPoint**: each slide with content.
- **Excel**: each non-empty sheet, plus one more page for every 500 rows after the first 500.
- **Word**: Word files have no fixed pages, so every 3,000 characters of text count as one page (at least one).

Documents that cannot be downloaded or read are reported with an `error` and are not charged. Set a maximum cost per run in the run options for a hard cap; the Actor stops converting when the cap is reached.

### Limits

- **Scanned PDFs are not OCR'd** in this version: pages without a text layer come back empty (and free) and are listed in `pagesWithoutText`.
- Tables are detected when they have ruling lines. Tables drawn only with spacing come out as text lines.
- Old binary formats (.doc, .xls, .ppt) and password-protected files are not supported.
- Up to 50 MB per file and 1,000 pages per document. A document is converted completely before its rows are saved, so split very long documents with **Max pages per document** if you need results sooner.
- Excel: the first 200 columns are read, and a sheet ends after 1,000 empty rows in a row.

### Data and privacy

The Actor only downloads the URLs you give it (one request per file, at most one request per second to the same host). Documents are processed in memory during the run and are not stored anywhere except your own run's dataset. Only convert documents you have the right to use.

### FAQ

**Why is a page empty?** It probably has no text layer (a scan or an image). It is listed in `pagesWithoutText` and not charged.

**Can I send many files at once?** Yes, add as many URLs as you like. Files are downloaded in parallel and converted one after another.

**Why does a Word file show more "pages" than in Word?** Word pages depend on fonts and margins, so the Actor counts 3,000 characters as one page to keep pricing predictable.

**Can I use it from LangChain, LlamaIndex, Make, n8n or Zapier?** Yes. Call the Actor through the Apify API (for example `run-sync-get-dataset-items` with your URLs and `outputFormat: "chunks"`) and load the rows into your vector store, or use the Apify integrations for Make, n8n and Zapier. AI agents can call it through the Apify MCP server.

### Related Actors by the same author

| Actor | What it does |
|---|---|
| [ATS Jobs](https://apify.com/tamatama/ats-jobs) | Open jobs from company career boards (Greenhouse, Lever, Ashby, Recruitee, Personio, Teamtailor) in one schema. |

# Actor input Schema

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

Links to PDF, Word (.docx), Excel (.xlsx) or PowerPoint (.pptx) files. The file type is detected from the content, so links without an extension work too.

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

Markdown keeps headings, lists and tables. Plain text drops the Markdown marks. RAG chunks splits each document into pieces with page numbers and the heading path, one dataset row per chunk.

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

Maximum characters per chunk (RAG chunks only). Chunks break at headings first, then paragraphs and sentences.

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

Characters repeated from the end of the previous chunk (RAG chunks only). At most half of the chunk size.

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

Insert  comments in the Markdown where a new page (slide, sheet) starts.

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

Convert only the first N pages (slides, sheets) of each document. 0 = all (up to 1,000).

## `maxRowsPerSheet` (type: `integer`):

Rows read from each Excel sheet (besides the header row).

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://api.apify.com/v2/key-value-stores/TmLpEGDADXE0rUYDl/records/sample-remote-work-policy.pdf"
    }
  ],
  "outputFormat": "markdown",
  "chunkSize": 2000,
  "chunkOverlap": 200,
  "includePageMarkers": false,
  "maxPagesPerDocument": 0,
  "maxRowsPerSheet": 1000
}
```

# Actor output Schema

## `documents` (type: `string`):

No description

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

No description

# 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://api.apify.com/v2/key-value-stores/TmLpEGDADXE0rUYDl/records/sample-remote-work-policy.pdf"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tamatama/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 = { "urls": [{ "url": "https://api.apify.com/v2/key-value-stores/TmLpEGDADXE0rUYDl/records/sample-remote-work-policy.pdf" }] }

# Run the Actor and wait for it to finish
run = client.actor("tamatama/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 '{
  "urls": [
    {
      "url": "https://api.apify.com/v2/key-value-stores/TmLpEGDADXE0rUYDl/records/sample-remote-work-policy.pdf"
    }
  ]
}' |
apify call tamatama/doc-to-markdown --silent --output-dataset

```

## MCP server setup

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