# Document to Markdown API: DOCX, XLSX, PPTX, No Login (`conserving_celerytop/document-to-markdown-api`) Actor

Convert public DOCX, XLSX, PPTX, CSV and HTML files to clean Markdown from a URL. One row per document with title, headings, word count and warnings. No login, no API key, no OCR. A URL that fails is returned as an error row and is not charged.

- **URL**: https://apify.com/conserving_celerytop/document-to-markdown-api.md
- **Developed by:** [Don Mangu](https://apify.com/conserving_celerytop) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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.
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

Use this document to markdown API to convert public DOCX, XLSX, PPTX, CSV and HTML files from a URL into clean Markdown, for $4.00 per 1,000 converted documents.

Paste one file URL per line and the Actor returns one row per document: the Markdown text, the title, the headings, counts of words, tables and images, and warnings about anything it skipped. Tables stay as Markdown tables, slides become sections with their notes, and spreadsheets become one table per sheet. The output is plain text that fits search indexes, vector stores and LLM prompts. You need no login, no API key and no proxy.

This is a tool built by an independent developer. It is not affiliated with Microsoft or with any file hosting service.

### What this Actor does

It downloads each public file URL you give it, checks what the file really is from its first bytes (not only from the file name), and converts it:

- **DOCX** (Word): headings, paragraphs, bold and italic, lists, links and tables. Images are counted and shown as `[Image: alt text]`.
- **XLSX** (Excel): every visible sheet as a Markdown table. Dates are shown as dates, formulas show the last value saved in the file, and hidden or empty sheets are skipped with a warning.
- **PPTX** (PowerPoint): one section per slide with the slide number and title, the text in reading order, tables, charts as a table of the values saved in the file, picture alt text and speaker notes.
- **CSV**: one Markdown table. The separator (comma, semicolon, tab or pipe) and the text encoding are detected.
- **HTML**: the page content as Markdown with absolute links. Scripts and styles are removed. It keeps the whole page, including menus. For article extraction from a live web page, use the web page Actor listed under Related Actors.

Not supported: PDF files, old binary Office files (.doc, .xls, .ppt), password-protected files, images and OCR. These return a row with status error and a message that names the reason. An error row is never charged.

### How to convert documents to Markdown, step by step

1. Click **Try for free**. No API key is needed.
2. In **urls**, enter one public file URL per line. The file must open in a browser without a login. A direct download link works best.
3. Optional: set **maxResults**, **maxFileSizeMb**, **maxRowsPerSheet** and **timeoutSeconds** to keep a run small and predictable.
4. Optional: for spreadsheets, set **sheetsAs** to one-row-per-sheet to get each sheet as its own row.
5. Click **Start**, open the **Overview** view, and export as JSON, CSV or Excel. The Markdown is in the `markdown` field.

Typical uses: preparing company documents for an LLM or a search index, turning a folder of exported spreadsheets into text, reading slide decks and their notes, and checking a list of public file links in one run.

### Input

| Field | Meaning | Default |
|---|---|---|
| urls | Public file URLs, one per line. Up to 1,000 per run | one sample DOCX |
| maxResults | Stop after this many converted rows | 100 |
| sheetsAs | one-row-per-document or one-row-per-sheet for XLSX files | one-row-per-document |
| maxRowsPerSheet | Rows kept from each XLSX sheet and each CSV file | 1000 |
| maxFileSizeMb | Largest file accepted, checked while it downloads. Hard limit 50 | 25 |
| timeoutSeconds | Total time for one URL, including redirects and retries | 60 |
| includeImages | Embed DOCX and PPTX pictures as base64 data (300 KB each, 4 MB per document) and keep HTML image addresses | false |

### Input example

```json
{
  "urls": [
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test_with_comment.docx",
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.xlsx",
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/does-not-exist.docx"
  ],
  "maxRowsPerSheet": 3
}
```

### Output

One row per document, in the order of your list. These are the fields:

| Field | Meaning |
|---|---|
| url, finalUrl | The URL you submitted and the address the file was read from after redirects |
| fileType, fileName | docx, xlsx, pptx, csv or html, and the file name from the server or the URL |
| sizeBytes | Size of the downloaded file |
| title | From the file properties, a title style, the first heading or the file name |
| markdown | The converted document |
| charCount, wordCount | Length of the Markdown in characters and in words |
| pageOrSheetCount | Slides in a PPTX, sheets in an XLSX, pages in a DOCX when the file stores a page count. Empty for CSV and HTML |
| headings | Headings with a level and text. Slides and sheets are listed as level 2 headings |
| tablesCount, imagesCount | Tables and images found |
| sheetName | The sheet name when sheetsAs is one-row-per-sheet |
| warnings | Notes about anything skipped or cut, such as hidden sheets, charts or cut rows |
| status, error | ok or error, and the reason for an error |
| fetchedAt | Time of the download (UTC) |

A DOCX row can be long. The real run of `test_with_comment.docx` in the example above returned 4,553 characters of Markdown, 644 words, 1 table and 4 headings. The XLSX row and the error row below are copied unchanged from a local run on 7 October 2026. The XLSX was cut to 3 rows per sheet by the input above:

```json
{
  "url": "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.xlsx",
  "finalUrl": "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.xlsx",
  "fileType": "xlsx",
  "fileName": "test.xlsx",
  "sizeBytes": 11562,
  "title": "test",
  "markdown": "## Sheet1\n\n| Alpha | Beta | Gamma | Delta |\n| --- | --- | --- | --- |\n| 89 | 82 | 100 | 12 |\n| 76 | 89 | 33 | 42 |\n\n## 09060124-b5e7-4717-9d07-3c046eb\n\n| ColA | ColB | ColC | ColD |\n| --- | --- | --- | --- |\n| 1 | 2 | 3 | 4 |\n| 5 | 6 | 7 | 8 |",
  "charCount": 243,
  "wordCount": 26,
  "pageOrSheetCount": 2,
  "headings": [
    {
      "level": 2,
      "text": "Sheet1"
    },
    {
      "level": 2,
      "text": "09060124-b5e7-4717-9d07-3c046eb"
    }
  ],
  "tablesCount": 2,
  "imagesCount": 0,
  "sheetName": null,
  "warnings": [
    "Sheet \"Sheet1\" was cut at 3 rows (your Max rows per sheet setting). More rows exist.",
    "Sheet \"09060124-b5e7-4717-9d07-3c046eb\" was cut at 3 rows (your Max rows per sheet setting). More rows exist."
  ],
  "status": "ok",
  "error": null,
  "fetchedAt": "2026-10-07T06:54:49.082Z"
}
```

A URL that cannot be converted returns a row like this, and it is not charged:

```json
{
  "url": "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/does-not-exist.docx",
  "finalUrl": null,
  "fileType": null,
  "fileName": null,
  "sizeBytes": null,
  "title": null,
  "markdown": null,
  "charCount": null,
  "wordCount": null,
  "pageOrSheetCount": null,
  "headings": [],
  "tablesCount": null,
  "imagesCount": null,
  "sheetName": null,
  "warnings": [],
  "status": "error",
  "error": "The server answered HTTP 404. The file was not found.",
  "fetchedAt": "2026-10-07T06:54:49.039Z"
}
```

### Pricing

Pay per event: **$4.00 per 1,000 converted documents** on the Free plan, with lower prices on Bronze, Silver and Gold plans. A converted document is one row with status ok. The start of a run costs $0.00005. A URL that is invalid, private, unreachable, too large, damaged or in an unsupported format returns a row with status error and is not charged. An XLSX file with sheetsAs set to one-row-per-sheet returns one row per sheet, and each of those rows is one charged document.

Worked example: converting 10 URLs where 8 convert and 2 fail costs 8 x $0.004 = $0.032, plus the start fee. A workbook with 5 sheets costs $0.004 as one row, or 5 x $0.004 = $0.02 as five rows.

### Use it from the API, Make, Zapier or n8n

You can start the Actor from the API, from Make, Zapier or n8n, and put it on a schedule to convert the same list of public file links every day or week. Each run only reads the URLs in its input.

### Limits

- Formats: DOCX, XLSX, PPTX, CSV and HTML. The type is decided from the file content first, then from the content type and the file name.
- Size: 25 MB by default, 50 MB at most. A file that unpacks to more than 400 MB is refused.
- Rows: up to 20,000 rows per sheet or CSV file. Each Markdown text is cut at 2,000,000 characters to fit one dataset row, and a warning says so.
- URLs: up to 1,000 per run. Duplicate URLs are removed. Up to 5 redirects, up to 3 attempts per URL with a pause that follows the Retry-After header, and 3 files at the same time.
- Ports: http and https on ports 80, 443, 8080 and 8443.
- Spreadsheet values are the values saved in the file. Number formats such as percent or currency are not applied, but dates are shown as dates.

### FAQ

**Is this legal to use?** The Actor reads only the exact public URLs you submit. It does not log in, solve CAPTCHAs, or crawl links. You are responsible for the URLs you submit and for having the right to copy and process the content of those files. Do not submit files you may not use.

**Which URLs work?** Direct links to a file that opens without a login. A link to a sharing page, a login page or a preview page (common with cloud drives) returns a web page and not the file. The Actor detects this when the link ends in .docx, .xlsx, .pptx or .csv, and returns an error row that says to use a direct download link.

**Are private addresses allowed?** No. Addresses such as localhost, 127.0.0.1, 10.x.x.x, 192.168.x.x and the cloud metadata address 169.254.169.254 are refused. This is checked for the URL, for every redirect, and again when the connection is made.

**Does it read scanned images or PDFs?** No. There is no OCR and there is no PDF support in this Actor. See Related Actors for PDF, image and web page conversion.

**Why did a URL return status error?** Read the `error` field. The common reasons are HTTP 404 or 403, a login page, a file above maxFileSizeMb, a file that is damaged or cut off, an old .doc, .xls or .ppt file, a password-protected file, or a timeout. Fix the link or the file and run again.

**What happens to the files?** The Actor downloads each file into memory, converts it and returns the rows to your dataset. The files themselves are not stored.

**How are charts, comments and macros handled?** A chart in a PPTX file is shown as a table of the values saved in the chart. Charts in XLSX and DOCX files and SmartArt in PPTX files are not converted. XLSX and PPTX rows carry a warning that counts what was skipped; DOCX rows do not. Other drawing shapes are skipped. Word comments and macros are ignored.

**How do I get one row per sheet?** Set sheetsAs to one-row-per-sheet. Each sheet becomes a row with its sheetName, and each row is charged.

### Bulk lists

Use a long list of file URLs from an Apify Dataset or from a file. Pick the Dataset under **Dataset with the list** and write the name of its field under **Field in the dataset**. Leave the field name empty to use the first text field. Or paste the web address of a .txt, .csv or .json file under **List file URL**. A .csv file uses its first column. A header row is skipped. The file can be up to 10 MB. Entries from the Dataset and the file are added to the ones typed under **Document URLs**, and duplicates are removed. The limit of 1,000 URLs per run covers the whole list. The price per converted document does not change.

### Related Actors

Other Actors by the same author for related jobs: pdf-text-extractor for PDF files, web-page-to-markdown for live web pages, and image-to-text-ocr for text in images. Search for these names on the Apify Store.

I built this Actor myself as an independent developer.

# Actor input Schema

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

Enter one public file URL per line. The file must open without a login. Supported: DOCX, XLSX, PPTX, CSV and HTML. Old .doc, .xls and .ppt files, PDF files and images are not supported.

## `listDatasetId` (type: `string`):

Pick an Apify Dataset that holds your file addresses, one entry per item. They are added to the entries typed above.

## `listDatasetField` (type: `string`):

Name of the dataset field that holds the entry. Leave empty to use the first text field it finds.

## `listFileUrl` (type: `string`):

Web address of a .txt, .csv or .json file with your file addresses, one entry per line. A header row is skipped. Up to 10 MB.

## `maxResults` (type: `integer`):

Stop after this many converted rows. Each converted row is one charged result. Rows with status error do not count and are not charged.

## `sheetsAs` (type: `string`):

Choose how an XLSX workbook is returned. One row per workbook puts every sheet into one row. One row per sheet returns each sheet as its own row, and each row is charged.

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

Keep at most this many rows of each XLSX sheet and of each CSV file. A warning says when rows were left out.

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

Reject a file that is larger than this many megabytes. The size is checked while the file downloads. The hard limit is 50 MB.

## `timeoutSeconds` (type: `integer`):

Total time allowed to download one URL, including redirects and retries.

## `includeImages` (type: `boolean`):

Off by default: an image is shown as \[Image: alt text] and only counted. On: images inside DOCX and PPTX files are embedded as base64 data (up to 300 KB each and 4 MB in total), and HTML images keep their address.

## Actor input object example

```json
{
  "urls": [
    "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx"
  ],
  "maxResults": 10,
  "sheetsAs": "one-row-per-document",
  "maxRowsPerSheet": 1000,
  "maxFileSizeMb": 25,
  "timeoutSeconds": 60,
  "includeImages": false
}
```

# Actor output Schema

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

No description

## `stats` (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": [
        "https://raw.githubusercontent.com/microsoft/markitdown/main/packages/markitdown/tests/test_files/test.docx"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("conserving_celerytop/document-to-markdown-api").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/main/packages/markitdown/tests/test_files/test.docx"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("conserving_celerytop/document-to-markdown-api").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/main/packages/markitdown/tests/test_files/test.docx"
  ],
  "maxResults": 10
}' |
apify call conserving_celerytop/document-to-markdown-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,conserving_celerytop/document-to-markdown-api"
        }
    }
}
```

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/FQHvxf5GYriHJR7yS/builds/dMM9ZNriEubV6vxNJ/openapi.json
