# DOCX, PPTX, XLSX & EPUB to Text API — Office Docs to Markdown (`highbrow_fame/office-document-to-text-api`) Actor

Convert Word, PowerPoint, Excel, OpenDocument and EPUB files at public links to Markdown and text, with metadata, sheets as JSON rows and slides with notes. Office Document to Text API.

- **URL**: https://apify.com/highbrow_fame/office-document-to-text-api.md
- **Developed by:** [yestrue](https://apify.com/highbrow_fame) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 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

## DOCX, PPTX, XLSX & EPUB to Text API — Office Docs to Markdown

Turn Word, PowerPoint, Excel, OpenDocument and EPUB files at public links into clean Markdown, plain text and structured JSON — one record per file, with the document's title, subject, keywords, language and dates. Spreadsheets come back as JSON rows keyed by their header row plus a Markdown table per sheet; presentations as slides with titles and speaker notes; EPUBs as chapters. The file type is read from the bytes, so a link without an extension, a redirecting download link or a misnamed file still converts. No login, no uploads: give it links, get text.

**Try it in 1 minute:**

1. Press **Start** — the prefilled input converts three public files: a Word demo document, Microsoft's Financial Sample spreadsheet and the Project Gutenberg EPUB of *Frankenstein*.
2. A few seconds later the **Output** tab shows one record per file: Markdown and text for the DOCX, 700 rows as JSON objects (plus a Markdown table) for the XLSX, and 30 chapters for the EPUB. The whole prefilled run took 2.5 seconds in a test on 19 October 2026.
3. Download JSON, CSV or Excel, or call the Actor from the API, Make, Zapier, n8n or an AI agent through the Apify MCP server.

Price: **$0.50 per 1,000 documents**. Links that give no document (404, a web page, a PDF, an unsupported or empty file) are free.

**Use it to:**

- Feed Office documents to an LLM or a RAG pipeline as Markdown instead of binary attachments — headings, bold, lists and tables survive.
- Turn Excel and CSV exports into JSON rows an API or a spreadsheet can use, with the header row as keys and dates as ISO 8601.
- Pull the text and speaker notes out of a PowerPoint deck for summaries, search indexes or slide-by-slide analysis.
- Convert EPUB books into chapters for text analysis, translation or audio production.
- Read the metadata of hundreds of public documents (title, subject, keywords, language, created and modified dates) in one run.

### How it works

1. Each link is downloaded directly (the proxy is used only to retry a download that failed on the network). Files up to 50 MB are accepted.
2. The type is decided from the bytes: a ZIP is opened and its entries say whether it is DOCX, PPTX, XLSX, ODT, ODS, ODP or EPUB; legacy `.xls` is recognised by its OLE2 header; CSV by its content type or extension. A `%PDF` file, a legacy `.doc`/`.ppt`, or a web page answering instead of a file comes back as a free record with a clear status.
3. DOCX is converted with mammoth (DOCX → HTML) and Turndown (HTML → Markdown); spreadsheets with SheetJS; PPTX, ODT, ODP and EPUB are read straight from their XML. Text, Markdown, word count and the document's properties go into one record.

Supported: `.docx`, `.pptx`, `.xlsx`, `.xls`, `.csv`/`.tsv`, `.ods`, `.odt`, `.odp`, `.epub`. Not supported: PDF (use the PDF Text Extractor Actor), `.doc`/`.ppt` (Office 97-2003 binary formats — save them as `.docx`/`.pptx`), images inside documents (text only).

### Input

| Field | What it does |
|---|---|
| `urls` | Public links to the files, one per line. Required. |
| `outputFormat` | `both` (default), `markdown` or `text`. |
| `maxRows` | Spreadsheets: data rows per sheet in `rows[]` and the Markdown table (default 1000, 0 = all). The full `rowCount` is always reported. |
| `includeRows` | Spreadsheets: deliver `rows[]` (default on). |
| `sheetNames` | Spreadsheets: only these sheets (case-insensitive). Empty = all. |
| `maxTextLength` | Cut `text` and `markdown` to this many characters and set `textTruncated` (default 0 = no limit). |
| `maxConcurrency` | Parallel downloads (default 5). |
| `proxyConfiguration` | Used only for network retries. |

### Output

One record per link:

| Field | What it is |
|---|---|
| `url`, `type`, `bytes` | Final download address, detected type (`docx`, `pptx`, `xlsx`, `xls`, `csv`, `ods`, `odt`, `odp`, `epub`), file size |
| `title`, `subject`, `keywords`, `description`, `language`, `publisher`, `createdAt`, `modifiedAt` | The document's own properties, when set |
| `author` | EPUB only: the book's author from the OPF. For Office and OpenDocument files the creator property is usually a person's user name and is not delivered (null). |
| `text`, `markdown`, `wordCount`, `textTruncated` | The content; `text` uses blank lines between paragraphs and tabs between table cells |
| `pageCount`, `slideCount`, `sheetCount`, `sheetNames`, `chapterCount` | Where the format has them |
| `sheets[]` | Spreadsheets: `{ name, rowCount, columnCount, hasHeader, headers[], rows[], rowsTruncated, markdownTable }` — `rows` are objects keyed by the header row when the first row is a header (all cells non-empty, distinct, non-numeric text), arrays otherwise |
| `slides[]` | PPTX/ODP: `{ index, title, text, notes }` |
| `chapters[]` | EPUB: `{ index, title, text }` in reading order |
| `warnings[]` | DOCX: styles or elements the converter could not map |
| `input`, `status`, `error`, `scrapedAt` | What you gave, and why a link gave no document |

Statuses: `OK` (charged), `NOT_FOUND`, `NOT_A_DOCUMENT`, `NOT_SUPPORTED`, `TOO_BIG`, `NO_TEXT`, `INVALID_INPUT`, `FAILED` (all free).

#### Example

A Word document:

```json
{
  "input": "https://files.example.org/reports/q1.docx",
  "url": "https://files.example.org/reports/q1.docx",
  "type": "docx",
  "bytes": 48211,
  "title": "Quarterly report",
  "author": null,
  "subject": "Finance",
  "keywords": "revenue, q1",
  "description": null,
  "language": "en-GB",
  "publisher": null,
  "createdAt": "2024-03-01T10:00:00.000Z",
  "modifiedAt": "2024-03-05T08:30:00.000Z",
  "pageCount": 3,
  "wordCount": 23,
  "text": "Quarterly report\n\nRevenue grew 12 % year on year & costs fell.\n\nBy region\n\nRegion\tSales\nNorth\t120\nSouth\t80\n\nOutlook remains positive.",
  "markdown": "# Quarterly report\n\nRevenue grew **12 %** year on year & costs fell.\n\n## By region\n\n| Region | Sales |\n| --- | --- |\n| North | 120 |\n| South | 80 |\n\nOutlook remains positive.",
  "warnings": [],
  "textTruncated": false,
  "status": "OK",
  "scrapedAt": "2026-10-19T12:56:23.689Z"
}
```

A spreadsheet (`text` and `markdown` shortened):

```json
{
  "input": "https://files.example.org/orders.xlsx",
  "url": "https://files.example.org/orders.xlsx",
  "type": "xlsx",
  "bytes": 17436,
  "title": "Order book",
  "sheetCount": 2,
  "sheetNames": ["Orders", "Numbers"],
  "sheets": [
    {
      "name": "Orders",
      "rowCount": 3,
      "columnCount": 3,
      "hasHeader": true,
      "headers": ["Product", "Qty", "Shipped"],
      "rows": [
        { "Product": "Widget", "Qty": 3, "Shipped": "2024-01-15T00:00:00.000Z" },
        { "Product": "Gadget", "Qty": 5.5, "Shipped": "n/a" }
      ],
      "rowsTruncated": true,
      "markdownTable": "| Product | Qty | Shipped |\n| --- | --- | --- |\n| Widget | 3 | 2024-01-15T00:00:00.000Z |\n| Gadget | 5.5 | n/a |"
    }
  ],
  "wordCount": 17,
  "markdown": "## Orders\n\n| Product | Qty | Shipped |\n| --- | --- | --- |\n| Widget | 3 | …",
  "status": "OK",
  "scrapedAt": "2026-10-19T12:56:23.967Z"
}
```

### FAQ

**Is this an official API?** No, it's an unofficial API built on public files — it converts documents at public links with open-source parsers (mammoth, SheetJS, Turndown); there is no Microsoft or OpenDocument service behind it.

**Can it read PDFs or scanned documents?** No. A PDF link comes back as a free `NOT_SUPPORTED` record pointing to the PDF Text Extractor Actor; scanned pages need OCR. Images inside Word or PowerPoint files are not delivered either — this Actor is about text.

**How are spreadsheet rows shaped?** When the first row of a sheet is a header (every cell a distinct, non-empty, non-numeric text), `rows` are objects keyed by those headers; otherwise `rows` are arrays and the Markdown table uses column letters. Dates become ISO 8601 strings, numbers stay numbers. `maxRows` limits what is delivered per sheet; `rowCount` always says how many rows the sheet has.

**What about personal data?** The document's "last modified by" and, for Office and OpenDocument files, the creator property (usually a person's user name) are not delivered. `author` is filled only for EPUBs, where it names the book's author. The text of the document itself is delivered as is.

**Why did the prefilled links change?** The example files are hosted by calibre, Project Gutenberg and Microsoft and may move; if one gives `NOT_FOUND`, replace it with any public document link.

**Like it?** A short review on the Store page helps other people find this Actor. Something missing or broken? Tell us on the Issues tab — we read every one.

### Related Actors

- [PDF Text Extractor](https://apify.com/highbrow_fame/pdf-text-extractor) — text, pages and metadata from any PDF link
- [PDF to Markdown API](https://apify.com/highbrow_fame/pdf-to-markdown-api) — headings, tables and text of a PDF
- [OCR API](https://apify.com/highbrow_fame/ocr-api) — text from images and scanned PDF pages
- [URL to Markdown API](https://apify.com/highbrow_fame/url-to-markdown-api) — clean page text for LLMs and agents
- [Article Extractor API](https://apify.com/highbrow_fame/article-extractor-api) — title, author, date and full text of any article

# Actor input Schema

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

Public links to Office, OpenDocument or EPUB files, one per line: .docx, .pptx, .xlsx, .xls, .csv, .ods, .odt, .odp, .epub. The type is detected from the file itself, so the link does not need an extension. Up to 50 MB per file.

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

What to deliver per document: Markdown (headings, bold, lists and tables kept), plain text, or both.

## `maxRows` (type: `integer`):

Spreadsheets: how many data rows of each sheet to deliver in rows\[] and in the Markdown table. 0 = all rows. The full row count is always reported.

## `includeRows` (type: `boolean`):

Spreadsheets: deliver each sheet's rows as JSON — objects keyed by the header row when the first row is a header, arrays otherwise. Off keeps only headers, counts and the Markdown table.

## `sheetNames` (type: `array`):

Spreadsheets: names of the sheets to deliver (case does not matter). Empty = every sheet.

## `maxTextLength` (type: `integer`):

Cut text and Markdown to this many characters and set textTruncated. 0 = no limit. Dataset records are limited to 9 MB; a very long EPUB may need a cap.

## `maxConcurrency` (type: `integer`):

How many files to download and convert at the same time.

## `proxyConfiguration` (type: `object`):

Files are downloaded directly first. The proxy is used only to retry a download that failed on the network.

## Actor input object example

```json
{
  "urls": [
    "https://calibre-ebook.com/downloads/demos/demo.docx",
    "https://www.gutenberg.org/ebooks/84.epub.noimages",
    "https://go.microsoft.com/fwlink/?LinkID=521962"
  ],
  "outputFormat": "both",
  "maxRows": 1000,
  "includeRows": true,
  "maxTextLength": 0,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every result as a JSON record, with a status for each input.

## `resultsCsv` (type: `string`):

The same records as CSV, for a spreadsheet.

# 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://calibre-ebook.com/downloads/demos/demo.docx",
        "https://www.gutenberg.org/ebooks/84.epub.noimages",
        "https://go.microsoft.com/fwlink/?LinkID=521962"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("highbrow_fame/office-document-to-text-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://calibre-ebook.com/downloads/demos/demo.docx",
        "https://www.gutenberg.org/ebooks/84.epub.noimages",
        "https://go.microsoft.com/fwlink/?LinkID=521962",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("highbrow_fame/office-document-to-text-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://calibre-ebook.com/downloads/demos/demo.docx",
    "https://www.gutenberg.org/ebooks/84.epub.noimages",
    "https://go.microsoft.com/fwlink/?LinkID=521962"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call highbrow_fame/office-document-to-text-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,highbrow_fame/office-document-to-text-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/4xlAAce2b7txb5JhR/builds/jhZEevdBXgf2A4cnw/openapi.json
