# PDF Text Extractor & Document to Markdown (Word, Excel, PPT) (`pavel.tashev/doc-to-markdown`) Actor

Extract text from PDF, Word, PowerPoint, Excel, HTML and EPUB files as clean, LLM-ready Markdown. Batch file URLs, tables kept, pay only for documents that convert. Built for RAG and AI agents.

- **URL**: https://apify.com/pavel.tashev/doc-to-markdown.md
- **Developed by:** [Pavel Tashev](https://apify.com/pavel.tashev) (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 $2.50 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does PDF Text Extractor & Document to Markdown do?

**This Actor extracts text from PDF, Word (DOCX), PowerPoint (PPTX), Excel (XLSX), HTML, EPUB, CSV, JSON and XML files and returns it as clean, LLM-ready Markdown. Scanned PDFs and images (PNG, JPG, TIFF, WebP, BMP) are read with built-in OCR.** Use it as a bulk PDF text extractor, a PDF to Markdown converter, an OCR tool for scans or a document parser for AI pipelines. Give it a list of file URLs and it returns one result per document: the Markdown text, the document title, file type, word count and how many pages were read with OCR.

It is built for **RAG pipelines, AI agents, search indexing and knowledge bases**, where you need the text of many documents in one consistent format. Because it runs on the Apify platform, you get API access, scheduling, webhooks, integrations (Make, Zapier, n8n, LangChain, LlamaIndex) and run monitoring out of the box.

### Why use this PDF text extractor?

- **One tool for every common format.** No separate PDF, Word and PowerPoint parsers to maintain.
- **Markdown keeps structure.** Headings, lists and tables survive the conversion, so chunking and embeddings work better than with flat text.
- **Excel sheets become Markdown tables** that language models can read directly.
- **OCR for scanned PDFs and images, with no Google and no external APIs.** Pages without a text layer are read with the open-source Tesseract engine inside your run, in 14 languages. Your files never leave the run.
- **Mixed PDFs just work.** In a PDF with both text pages and scanned pages, only the scanned pages go through OCR, and the text stays in page order.
- **Pay only for documents that convert.** Downloads that fail, files that are too large and unsupported formats are never charged. OCR is charged only for pages where it found readable text.
- **Batch friendly.** Paste hundreds of URLs or upload a text file with one URL per line; files are processed in parallel.

Typical uses: feeding company documents into a chatbot, indexing research papers, extracting text from pitch decks and reports, digitizing scanned archives and receipts, preparing training or evaluation data, and giving AI agents a reliable "read this file" tool.

### How to extract text from PDF and Word files

1. Click **Try for free**.
2. In **File URLs**, paste direct links to your documents (or upload a text file of URLs).
3. Click **Start**.
4. When the run finishes, open the **Output** tab. The **Overview** view lists every file and its status; the **Markdown** view shows the converted text.
5. Download the results as JSON, CSV, Excel or HTML, or fetch them through the API.

### Input

| Field | Description | Default |
|---|---|---|
| **File URLs** | Direct links to documents. Duplicates are removed automatically. | – |
| **Include Markdown in output** | Turn off to get only metadata (type, title, word count). | On |
| **OCR mode** | **Auto** reads images and PDF pages that have no text layer. **Off** never runs OCR (images fail, scanned pages come back empty). **Force** reads every PDF page with OCR, even pages that already have text. | Auto |
| **OCR languages** | Languages in your scans: English, German, French, Spanish, Italian, Portuguese, Dutch, Polish, Bulgarian, Romanian, Czech, Russian, Ukrainian, Turkish. Pick up to 5. | English |
| **Maximum OCR pages per file** | OCR stops after this many pages in one file; the result is marked `ocrTruncated`. | 200 |
| **Maximum file size (MB)** | Larger files are skipped and not charged. | 50 |
| **Files processed in parallel** | Higher is faster but uses more memory. | 5 |

Example input:

```json
{
  "fileUrls": [
    { "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" },
    { "url": "https://calibre-ebook.com/downloads/demos/demo.docx" }
  ],
  "includeMarkdown": true
}
```

### Output

Each document produces one item in the dataset:

```json
{
  "url": "https://calibre-ebook.com/downloads/demos/demo.docx",
  "fileName": "demo.docx",
  "fileType": "docx",
  "fileSizeBytes": 1311881,
  "title": "Text Formatting",
  "markdown": "Demonstration of DOCX support in calibre\n\nThis document demonstrates ...",
  "wordCount": 1703,
  "characterCount": 11139,
  "likelyScanned": false,
  "status": "success",
  "error": null,
  "processedAt": "2026-09-15T09:12:44.120Z"
}
```

A scanned page or image read with OCR looks like this (real output, text shortened):

```json
{
  "url": "https://archive.org/download/aberpa.whittierjg.1887.statue/page/n10.jpg",
  "fileName": "aberpa.whittierjg.1887.statue_0010.jpg",
  "fileType": "jpg",
  "fileSizeBytes": 686743,
  "title": "STATUE OF LIBERTY. ae",
  "markdown": "STATUE OF LIBERTY. ae\n\nWAR DEPARTMENT, t\nWASHINGTON City, September 27, 1886.\n\nGENERAL: Among the requirements of the\nJoint Resolution of Congress, approved March 3, ...",
  "wordCount": 204,
  "characterCount": 1226,
  "likelyScanned": false,
  "ocrPages": 1,
  "ocrLanguages": ["eng"],
  "ocrTruncated": false,
  "status": "success",
  "error": null
}
```

A file that cannot be converted is still listed, with `"status": "failed"` and a plain-language `error` such as *"Download failed with HTTP 404 Not Found: the file was not found at this URL."*

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Output fields

| Field | Meaning |
|---|---|
| `url` | The URL you provided |
| `fileName` | File name from the server or the URL |
| `fileType` | `pdf`, `docx`, `pptx`, `xlsx`, `html`, `epub`, `csv`, `json`, `xml`, `txt`, `md`, `png`, `jpg`, `tiff`, `webp` or `bmp` |
| `title` | Document title from its metadata, or its first heading |
| `markdown` | The converted text |
| `wordCount`, `characterCount` | Size of the converted text |
| `likelyScanned` | `true` when a PDF has pages without a text layer (scanned images) |
| `ocrPages` | Number of pages or images where OCR found readable text (these are the charged OCR pages) |
| `ocrLanguages` | OCR languages used, when OCR ran |
| `ocrTruncated` | `true` when OCR stopped early because of *Maximum OCR pages per file* or your maximum cost per run |
| `status`, `error` | `success` or `failed`, with the reason for failures |

### How much does it cost to convert documents and scans to text?

This Actor uses **pay-per-event pricing** with two events. See the **Pricing** tab for current prices.

- **Document converted:** a small fee for each document that converts successfully. Failed downloads and unsupported files cost nothing.
- **OCR page:** charged separately for each scanned PDF page or image where OCR found readable text. Text PDFs, Word, PowerPoint, Excel and the other text formats never use OCR, so they never incur this charge. Pages that OCR could not read (illustrations, blank scans) are not charged.

Platform compute is included in the price. You can set a maximum cost per run: the Actor OCRs only as many pages as your budget allows, marks the file `ocrTruncated`, and skips files it can no longer afford.

### Tips

- **Use direct file links.** A link to a "download page" returns that page's HTML, not the file.
- **Choose the right OCR languages.** Tesseract reads a language much better when it is selected. Add only the languages that appear in your documents; each one slows OCR down.
- **Avoid OCR charges** by setting *OCR mode* to *Off* when you only need text PDFs and office files.
- **Force mode** helps when a PDF has a broken or garbled text layer; it re-reads every page with OCR.
- **OCR speed:** about 1–2 seconds per page at the default memory. For large scanned batches, try 2–4 GB of memory so more pages can run in parallel.
- **Large batches:** keep parallel files at 5–10. Some servers rate-limit many simultaneous downloads.
- **Metadata only:** turn off *Include Markdown in output* to quickly check file types and sizes across many URLs.

### Supported formats and limitations

- Supported: PDF (text and scanned), DOCX, PPTX, XLSX, HTML, EPUB, CSV, JSON, XML, TXT, MD, and images: PNG, JPG, TIFF (including multi-page), WebP, BMP.
- OCR works best on printed text in clean scans. It is weak on handwriting, phone photos taken at an angle, multi-column layouts and complex tables; reading order can differ from the visual layout. OCR text is plain paragraphs, without Markdown headings or tables.
- Not supported yet: legacy `.doc`, `.ppt` and `.xls` files, password-protected documents, HEIC photos, languages outside the list above.
- HTML pages are converted as a whole, including navigation text. For clean article extraction from websites, use a web crawler Actor.
- Files that need a login or that block automated downloads cannot be fetched.

### Related tools

Build a content or RAG pipeline with these tools:

- [Audio & Video Transcriber](https://apify.com/pavel.tashev/audio-video-transcriber): turn audio, video and podcast episodes into text and subtitles.
- [RSS Feed Reader & Finder](https://apify.com/pavel.tashev/rss-feed-reader): read RSS, Atom and JSON feeds or find the feed of any website.
- [Sitemap URL Extractor](https://apify.com/pavel.tashev/sitemap-url-extractor): list every URL of a website from its sitemaps, or only new and removed pages.

### FAQ and support

**Is my data stored?** Documents are downloaded only for conversion. OCR runs inside your run with Tesseract; nothing is sent to Google or any other external API. Results are saved to your own Apify dataset, which you control.

**Can I use this with AI agents?** Yes. The Actor works through the Apify API and the Apify MCP server, so agents can call it as a document-reading tool.

**Something doesn't convert correctly?** Open an issue in the **Issues** tab with the file URL (if it is public) and what you expected. We respond to issues and usually ship fixes quickly.

Only convert documents you have the right to access and process.

# Actor input Schema

## `fileUrls` (type: `array`):

Direct links to the documents you want to convert. Supports PDF (including scanned PDFs), Word (.docx), PowerPoint (.pptx), Excel (.xlsx), HTML, EPUB, CSV, JSON, XML, plain text and images (PNG, JPG, TIFF, WebP, BMP). You can paste many URLs or upload a text file with one URL per line.

## `includeMarkdown` (type: `boolean`):

Turn off to return only metadata (file type, title, word count) without the converted text.

## `ocrMode` (type: `string`):

OCR reads text from images and from PDF pages that have no text layer (scans). "Auto" runs OCR only where it is needed, "Off" never runs it (scanned pages come back empty and images fail), "Force" OCRs every PDF page even if it already has text. OCR pages are charged separately.

## `ocrLanguages` (type: `array`):

Languages of the text in your scans and images. Pick the ones that appear in the documents (up to 5); each extra language makes OCR slower.

## `maxOcrPagesPerFile` (type: `integer`):

Stop OCR after this many pages in one file. Pages beyond the limit are left out and the result is marked as truncated.

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

Files larger than this are skipped and not charged.

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

How many documents to download and convert at the same time. Higher is faster but uses more memory.

## Actor input object example

```json
{
  "fileUrls": [
    {
      "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    },
    {
      "url": "https://calibre-ebook.com/downloads/demos/demo.docx"
    }
  ],
  "includeMarkdown": true,
  "ocrMode": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "maxOcrPagesPerFile": 200,
  "maxFileSizeMb": 50,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `results` (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 = {
    "fileUrls": [
        {
            "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
        },
        {
            "url": "https://calibre-ebook.com/downloads/demos/demo.docx"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pavel.tashev/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 = { "fileUrls": [
        { "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" },
        { "url": "https://calibre-ebook.com/downloads/demos/demo.docx" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pavel.tashev/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 '{
  "fileUrls": [
    {
      "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    },
    {
      "url": "https://calibre-ebook.com/downloads/demos/demo.docx"
    }
  ]
}' |
apify call pavel.tashev/doc-to-markdown --silent --output-dataset

```

## MCP server setup

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