# DOCX to Markdown: Word, PowerPoint, Excel to Text for LLMs (`itayozer9/docx-to-markdown`) Actor

Convert Word .docx, PowerPoint .pptx and Excel .xlsx links or uploads to clean Markdown and plain text for LLMs and RAG: headings, lists, tables, links, footnotes, image alt text, metadata, word and token counts. Pay per file.

- **URL**: https://apify.com/itayozer9/docx-to-markdown.md
- **Developed by:** [Itay Ozer](https://apify.com/itayozer9) (community)
- **Categories:** AI, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 file 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

## DOCX to Markdown: Word, PowerPoint and Excel to text for LLMs

Turn Word (.docx), PowerPoint (.pptx) and Excel (.xlsx) files into clean Markdown and plain text that LLMs, RAG pipelines and AI agents can use right away. Give it links or upload files, and get one result per file with the Markdown, the plain text, the document properties, and word and token counts.

### What you get

- **Headings** as `#`, `##` (Word heading styles, Title and Subtitle), so you can split documents into chunks by section.
- **Lists**, bulleted and numbered, nested lists kept nested.
- **Tables** as Markdown tables. Merged cells keep the columns lined up. In the plain text, tables are tab-separated rows.
- **Links** as `[text](url)`, **bold**, *italic* and ~~strikethrough~~.
- **Footnotes and endnotes** as Markdown footnotes (`[^1]` and `[^1]: note text`).
- **Images as alt text**: `[Image: Bar chart of sales]`. Image files are never downloaded or returned, so results stay small.
- **PowerPoint**: one `## Slide N: Title` section per slide, bullet levels, tables, charts with their data as a table, picture alt text, speaker notes (optional), hidden slides marked.
- **Excel**: one `## Sheet: Name` section per sheet with a Markdown table. Values as Excel last showed them (formula results, dates as ISO dates). Empty sheets, rows and columns are left out. Hidden sheets are marked.
- **Metadata**: title, author, subject, keywords, description, last modified by, created and modified dates, the app that saved the file, slide and sheet counts.
- **Counts**: words, characters, tokens (OpenAI o200k_base, used by GPT-4o and later, a close guide for other models), tables, images, links, and the heading outline.

The file type is read from the file itself, not the name, so links without an extension work. Macro-enabled and template files (.docm, .dotx, .pptm, .xlsm) work too.

### Input

| Field | What it does |
|---|---|
| File URLs | Links to .docx, .pptx or .xlsx files, up to 1,000 per run |
| Upload files | Or upload files from your computer (kept in your own Apify storage) |
| Max rows per Excel sheet | Rows after this many on a sheet are skipped (default 1,000, up to 100,000) |
| Include speaker notes | Add PowerPoint speaker notes under each slide (default on) |

Example:

```json
{
    "urls": ["https://example.com/report.docx", "https://example.com/deck.pptx"],
    "maxRowsPerSheet": 1000,
    "includeNotes": true
}
```

### Output

One item per file (shortened):

```json
{
    "url": "https://example.com/report.docx",
    "fileName": "report.docx",
    "error": null,
    "format": "docx",
    "fileSizeBytes": 135824,
    "title": "Quarterly Report",
    "author": "Dana Writer",
    "createdAt": "2024-03-06T08:18:13Z",
    "markdown": "# Quarterly Report\n\nSales grew **fast** this quarter, see [the full report](https://example.com/report).\n\n## Highlights\n\n- North region\n  - Best month: July\n- South region\n\n| Region | Q2 | Q3 |\n| --- | --- | --- |\n| North | 10 | 12 |\n\n[Image: Bar chart of sales]",
    "text": "Quarterly Report\n\nSales grew fast this quarter, see the full report. ...",
    "wordCount": 57,
    "tokenCount": 123,
    "tableCount": 1,
    "imageCount": 1,
    "linkCount": 1,
    "headings": [{"level": 1, "text": "Quarterly Report"}, {"level": 2, "text": "Highlights"}],
    "truncated": false
}
```

A file that cannot be converted still gets a row, with `error` saying why in plain words (for example "This is an old binary Office file (.doc, .xls, .ppt) or a password-protected file"). Download the results as JSON, CSV or Excel, or read them with the Apify API.

### Pricing

Pay per file. You are never charged for files that fail or that have no text.

| Event | Price |
|---|---|
| File converted (up to 2 MB, and up to 2 MB of unpacked Word or PowerPoint text and markup) | $0.002 |
| Extra MB: each further MB of file size over 2 MB, or each further MB of unpacked Word or PowerPoint markup over 2 MB, whichever count is higher | $0.001 |
| Actor start (Apify's standard start event, per GB of memory) | $0.00005 |

Examples: a typical Word document, slide deck or spreadsheet costs $0.002 (in a test set of 545 real Office files, 7 needed extra MB events). A 10 MB slide deck full of photos costs $0.002 + 8 x $0.001 = $0.010. 1,000 typical files cost about $2.

The run stops cleanly at the maximum charge you set for the run: a file that would cost more than what is left is listed with an error and not charged.

### Limits

- Files up to 50 MB. Word files up to 8 MB of unpacked text and markup (hundreds of pages of plain text, fewer with heavy formatting), PowerPoint up to 20 MB.
- Excel: up to 200 columns per sheet and 200,000 cells per file; the result says `truncated` when rows were left out.
- Old binary formats (.doc, .xls, .ppt), password-protected files, OpenDocument (.odt, .ods, .odp), RTF and PDF are not converted (you get a clear error and no charge).
- Word equations, comments, headers and footers, and text inside SmartArt are left out.
- Links: the tool obeys each site's robots.txt and only fetches public http and https addresses. Sites that block tools or need a login cannot be read; download the file and upload it instead.
- A result item can hold up to 9 MB. For huge documents the heading list and then the plain text are dropped first (`outputTrimmed` says what was left out).

### FAQ

**Is my file stored?** Uploaded files sit in your own Apify key-value store. The tool keeps nothing after the run; results are in your own dataset.

**Why Markdown?** LLMs read Markdown well, and headings and tables survive, so chunking by section and answering questions about tables works better than with flat text.

**How exact is the token count?** It is the real count of the Markdown in OpenAI's o200k_base encoding. Other models count a little differently.

**Can I use it from an AI agent or MCP client?** Yes. Call the Actor with a list of links and read the `markdown` field of each item.

**What about PDFs?** Use our PDF to Markdown tool for PDF files.

Found a problem or need a feature? Open an issue on this page.

# Actor input Schema

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

Links to Word (.docx), PowerPoint (.pptx) or Excel (.xlsx) files, one per line (up to 1,000 per run). Macro-enabled and template files (.docm, .pptm, .xlsm, .dotx) work too. The sample is a public test document: replace it with your own.

## `files` (type: `array`):

Or upload Word, PowerPoint or Excel files from your computer. They are stored in your own Apify key-value store.

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

Excel only: rows after this many on each sheet are skipped and the result is marked truncated (1 to 100,000). A file stops at 200,000 cells in total.

## `includeNotes` (type: `boolean`):

PowerPoint only: add each slide's speaker notes under a Notes heading.

## Actor input object example

```json
{
  "urls": [
    "https://raw.githubusercontent.com/microsoft/markitdown/7482c092d9c0074a89803c9fdb63a969e7fe17fc/packages/markitdown/tests/test_files/test.docx"
  ],
  "maxRowsPerSheet": 1000,
  "includeNotes": true
}
```

# Actor output Schema

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

One item per file: Markdown, text, metadata and counts.

# 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://raw.githubusercontent.com/microsoft/markitdown/7482c092d9c0074a89803c9fdb63a969e7fe17fc/packages/markitdown/tests/test_files/test.docx"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("itayozer9/docx-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://raw.githubusercontent.com/microsoft/markitdown/7482c092d9c0074a89803c9fdb63a969e7fe17fc/packages/markitdown/tests/test_files/test.docx"] }

# Run the Actor and wait for it to finish
run = client.actor("itayozer9/docx-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://raw.githubusercontent.com/microsoft/markitdown/7482c092d9c0074a89803c9fdb63a969e7fe17fc/packages/markitdown/tests/test_files/test.docx"
  ]
}' |
apify call itayozer9/docx-to-markdown --silent --output-dataset

```

## MCP server setup

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