# PDF to Markdown & Text Extractor: DOCX, PPTX, Excel + OCR (`pewterdesk/documents-to-ai-ready-markdown`) Actor

Convert PDF, Word, PowerPoint, Excel, CSV, HTML and image files to clean Markdown or text for LLMs and RAG: headings, tables, reading order, page markers and chunks. Scanned pages are OCR'd locally with Tesseract. Pay per page; blank and failed pages are free.

- **URL**: https://apify.com/pewterdesk/documents-to-ai-ready-markdown.md
- **Developed by:** [PewterDesk](https://apify.com/pewterdesk) (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

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 to Markdown & Text Extractor: DOCX, PPTX, Excel + OCR

**PDF to Markdown and text extractor** for LLMs: convert PDFs, Word, PowerPoint and Excel files to clean Markdown or text, with OCR for scanned pages.&#x20;

Turn your documents into **clean Markdown or plain text that LLMs and RAG pipelines can use**: one dataset row per file, or one row per chunk ready for your vector database.

- **PDF**: headings detected from font size and weight, **multi-column reading order** (research papers and newsletters come out in the right order), **tables as Markdown tables** in their reading position, de-hyphenated line breaks, `<!-- page N -->` markers, and page ranges.
- **Scanned and image-only PDFs**: OCR'd **locally with Tesseract**. In *Auto* mode only pages with no text layer or a broken one (`(cid:123)` garbage) are OCR'd. Every OCR page reports a confidence score.
- **Images** (PNG, JPG, TIFF including multi-page, WEBP, BMP, GIF): OCR to text.
- **Word (.docx)**: headings, bullet and numbered lists, bold text and tables, all in document order.
- **PowerPoint (.pptx)**: one section per slide with its title, bullets, tables and optional speaker notes.
- **Excel (.xlsx) and CSV**: one Markdown table per sheet.
- **HTML**: main content only. Navigation, footers, scripts and forms are removed, while links, lists, tables and code blocks are kept.
- **TXT, MD and JSON**: passed through (JSON is pretty-printed).

**Private by design.** Files are processed inside the Actor container. Nothing is sent to Google Lens or any third-party OCR or AI API.

### Why this one

| | This Actor | Typical PDF/OCR Actors |
|---|---|---|
| OCR | Local Tesseract, only where needed | Often Google Lens wrappers, or OCR on every page |
| Structure | Headings, tables, lists, reading order | Flat text dump |
| RAG chunks with page ranges | ✅ built in | ❌ |
| Formats | PDF, DOCX, PPTX, XLSX, CSV, HTML, images | Usually PDF only |
| Price | $0.002 per text page / $0.006 per OCR page | Up to $0.015 per OCR page |
| Blank or failed pages | Free | Charged |

### Who uses this

- **RAG and agent builders.** Ingest manuals, contracts, policies and research PDFs as Markdown chunks with page citations.
- **Ops and finance teams.** Pull the text out of scanned invoices, receipts and forms so you can parse or search it.
- **Analysts.** Convert slide decks and spreadsheets into text you can summarise with an LLM.
- **Developers.** Call it from the API, from Make or n8n, or from your agent framework as a "read this file" tool.

### Input

Upload files in Console, or pass URLs. Google Drive, Google Docs, Dropbox and GitHub share links are converted to downloads automatically.

```json
{
  "fileUrls": ["https://example.com/annual-report.pdf", "https://drive.google.com/file/d/FILE_ID/view"],
  "outputFormat": "markdown",
  "chunkSize": 2000,
  "chunkOverlap": 200,
  "ocrMode": "auto",
  "ocrLanguages": ["eng", "deu"]
}
```

Only process documents you own or have the right to use.

### Output (one row per document)

```json
{
  "fileName": "report.pdf", "status": "ok", "format": "pdf", "title": "Acme Quarterly Report",
  "pageCount": 3, "pagesProcessed": 3, "textPages": 2, "ocrPages": 0, "emptyPages": 1, "tables": 1,
  "wordCount": 65, "approxTokens": 112,
  "markdown": "<!-- page 1 -->\n\n# Acme Quarterly Report\n\nQuarterly revenue grew ...\n\n| Region | Revenue | Growth |\n|---|---|---|\n| Europe | 4.2M | 18% |",
  "chunks": [{"index": 0, "text": "...", "charCount": 1987, "pageStart": 1, "pageEnd": 2}],
  "billedPages": {"text": 2, "ocr": 0}
}
```

Set **Dataset rows → One row per chunk** to get `fileName, chunkIndex, pageStart, pageEnd, text` rows that go straight into Pinecone, Qdrant, Weaviate or pgvector.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Page processed (text layer, slide, sheet, or 3,000 characters of DOCX/HTML/CSV/TXT) | **$0.002** |
| Page OCR'd (scanned PDF page or image) | **$0.006** |
| Blank pages, failed downloads, unsupported files | **free** |

For example, a 100-page digital PDF costs $0.20, and 100 scanned pages cost $0.60. The Actor stops cleanly at the maximum charge you set for a run and never processes pages it can't bill.

### Tips

- **Scanned documents**: choose only the OCR languages you need. Supported: English, German, French, Spanish, Italian, Portuguese, Dutch and Polish.
- **Large batches**: raise **Files processed in parallel** together with memory (about 1 GB per parallel OCR job).
- **Very large PDFs**: use **Page range** and **Max pages per document** to control cost.
- **Not supported**: legacy .doc/.ppt/.xls files (save them as .docx/.pptx/.xlsx first), handwriting, and math-formula reconstruction.

### FAQ

**Is my data stored?** Only in your own run's dataset and storage, which follow your Apify retention settings.

**How accurate is OCR?** Clean scans at 200 DPI or more usually reach over 90% confidence. Check `ocrConfidence` for each file or page.

**Can I use it from an AI agent?** Yes. Call the Actor through the Apify API or MCP with `fileUrls` and read `markdown`.

***

Built by **PewterDesk** ([pewterdesk.pages.dev](https://pewterdesk.pages.dev)). More tools: [apify.com/pewterdesk](https://apify.com/pewterdesk).

# Actor input Schema

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

Upload your documents (PDF, DOCX, PPTX, XLSX, CSV, HTML, TXT/MD, PNG/JPG/TIFF/WEBP). Only process files you own or have the right to use.

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

Direct links to your files. Google Drive / Docs, Dropbox and GitHub share links are converted to download links automatically (the file must be shared as 'anyone with the link').

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

Markdown keeps structure that LLMs use well; plain text strips formatting.

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

Split each document into RAG-ready chunks on paragraph/table boundaries, with page ranges. ~4 characters ≈ 1 token, so 2000 ≈ 500 tokens.

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

Trailing paragraphs repeated at the start of the next chunk (at most half the chunk size).

## `outputMode` (type: `string`):

'One row per chunk' needs a chunk size above 0. Billing is the same either way.

## `includePages` (type: `boolean`):

Adds a 'pages' array with Markdown, method (text/ocr) and OCR confidence for every page/slide/sheet.

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

Auto uses the PDF's text layer when it's good and falls back to local Tesseract OCR for scanned, image-only or broken-encoding pages. Images are always OCR'd.

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

Languages in your scanned documents. Picking only the ones you need is faster and more accurate.

## `extractTables` (type: `boolean`):

Render ruled PDF tables as Markdown tables in reading position.

## `pageRange` (type: `string`):

Optional, e.g. '1-5, 8, 20-'. Pages outside the range are skipped and not billed.

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

Safety cap per file (0 = unlimited).

## `pdfPassword` (type: `string`):

Only if your PDFs are password-protected.

## `includeSpeakerNotes` (type: `boolean`):

Appends slide speaker notes as a quote under each slide.

## `htmlMainContentOnly` (type: `boolean`):

Drops navigation, footers, sidebars, scripts and forms from HTML files.

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

Larger files are skipped (not charged).

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

Raise together with memory (each 1 GB ≈ one parallel OCR job).

## Actor input object example

```json
{
  "fileUrls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ],
  "outputFormat": "markdown",
  "chunkSize": 0,
  "chunkOverlap": 200,
  "outputMode": "document",
  "includePages": false,
  "ocrMode": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "extractTables": true,
  "maxPagesPerDocument": 500,
  "includeSpeakerNotes": true,
  "htmlMainContentOnly": true,
  "maxFileSizeMb": 100,
  "maxConcurrency": 2
}
```

# Actor output Schema

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

Markdown/text per document with page markers and RAG chunks (default dataset).

## `runSummary` (type: `string`):

Counts for this run (processed, failed, stopped at spending limit) as JSON.

# 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": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pewterdesk/documents-to-ai-ready-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": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("pewterdesk/documents-to-ai-ready-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": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ]
}' |
apify call pewterdesk/documents-to-ai-ready-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pewterdesk/documents-to-ai-ready-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/EgzefcjBKJoZhD7KI/builds/oP8kpSZ06acyDLaix/openapi.json
