Document to Markdown: PDF, DOCX, XLSX, PPTX & OCR for AI avatar

Document to Markdown: PDF, DOCX, XLSX, PPTX & OCR for AI

Pricing

from $4.00 / 1,000 document processeds

Go to Apify Store
Document to Markdown: PDF, DOCX, XLSX, PPTX & OCR for AI

Document to Markdown: PDF, DOCX, XLSX, PPTX & OCR for AI

Convert PDF (OCR for scans), DOCX, XLSX, PPTX, HTML, EML and images to clean Markdown for LLMs and RAG. Tables as Markdown, per-page text, token counts, heading-aware chunks. PDF text extractor: $4 per 1,000 files, OCR $10 per 1,000 pages.

Pricing

from $4.00 / 1,000 document processeds

Rating

0.0

(0)

Developer

Kevin

Kevin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Security

Limited permissions

Share

Document to Markdown: PDF, DOCX, XLSX, PPTX & OCR for AI / RAG

Convert PDF, Word, Excel, PowerPoint, HTML, e-mail and image files to clean Markdown for ChatGPT, Claude, Gemini and RAG pipelines. A PDF text extractor with OCR: it reads the text layer of a PDF first and runs OCR only on the pages that have no text (scans, photographed pages), so you pay the OCR price only where it is needed. One Actor for PDF, DOCX, XLSX, PPTX, HTML, EML and images.

You get, per file: the whole Markdown, pages[], every table as a Markdown table, metadata (page count, OCR used, word count, token estimate) and optional heading-aware chunks[] for embeddings.

Who is it for

  • AI / LLM developers building RAG, chat-with-your-documents or agent tools who need Markdown instead of raw PDF text.
  • Data and ops teams turning invoices, reports, contracts and spreadsheets into text that can be searched, summarized or fed to a model.
  • No-code users (Make, Zapier, n8n) who want "file in, Markdown out" without running OCR or parsers themselves.

Quick answers

  • How do I convert a PDF to Markdown? Paste the link to the PDF into Document URLs and run. Result: markdown, per-page text, tables, metadata.
  • How do I OCR a scanned PDF? Same input. Pages with no text layer are OCRed automatically (ocr: auto). Choose the language(s) in OCR languages.
  • Which formats? PDF, DOCX, XLSX, PPTX, HTML, EML (e-mail), PNG, JPG, TIFF (multi-page), WebP, GIF, BMP, plus TXT, MD and CSV. The file content decides the type, not the extension.
  • How can I give it files? Direct URLs, an uploaded file, records of an Apify key-value store, or base64 strings (for API and agent calls).
  • Price: $0.004 per converted file ($4 per 1,000) plus $0.010 per OCR page ($10 per 1,000 pages). Files that fail are not charged. Apify also charges its small Actor-start fee.
  • Does it need an API key or an AI model? No. It runs locally in the container (Tesseract OCR), calls no external AI service, and needs no secrets.
  • RAG chunks? Switch on Include RAG chunks: text split at headings and paragraph ends, with heading path, page range and token estimate.
  • Cost control: set Apify's maximum cost per run. The Actor stops when the budget is used up and never OCRs more pages than the budget pays for. maxOcrPagesPerDocument caps OCR per file.

What you get

One dataset item per converted file (failed files are listed in the run summary, see below):

{
"documentIndex": 1,
"source": "https://example.com/quarterly-report.pdf",
"filename": "quarterly-report.pdf",
"format": "pdf",
"status": "ok",
"markdown": "# Quarterly Report\n\nApify actors turn websites and files into structured data ...\n\n## Key figures\n\n- Revenue grew in Europe\n- Costs stayed flat\n\n| Region | Revenue | Growth |\n| --- | --- | --- |\n| Europe | 120 | 5% |\n| Asia | 80 | 9% |\n\n## Outlook\n\nSecond page text about the outlook for next year.",
"metadata": {
"title": "Quarterly Report", "author": "Test Author", "createdAt": "2026-11-05T11:32:21",
"pageCount": 2, "ocrUsed": false, "ocrPages": 0,
"wordCount": 47, "characterCount": 350, "tokenEstimate": 88, "tableCount": 1, "sizeBytes": 3064
},
"pages": [
{"page": 1, "markdown": "# Quarterly Report\n\n...", "ocr": false, "wordCount": 37},
{"page": 2, "markdown": "## Outlook\n\nSecond page text ...", "ocr": false, "wordCount": 10}
],
"tables": [
{"page": 1, "index": 1, "rows": 3, "columns": 3, "markdown": "| Region | Revenue | Growth |\n| --- | --- | --- |\n| Europe | 120 | 5% |\n| Asia | 80 | 9% |"}
],
"chunks": [
{"index": 0, "text": "# Quarterly Report\n\n...", "headings": ["Quarterly Report"], "pageStart": 1, "pageEnd": 2, "tokenEstimate": 88}
],
"warnings": [],
"markdownUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/001-quarterly-report.pdf.md",
"processingSeconds": 0.21
}
  • markdownUrl is the complete Markdown as a .md file in the run's key-value store (also listed in the Output tab). If an item would exceed Apify's 9 MB dataset limit, chunks, then pages, then tables are left out (with a warning) and markdownUrl still has everything.
  • pages[]: PDF pages, spreadsheet sheets, slides, image frames. Word, HTML and e-mail files count as one page.
  • metadata.ocrConfidence (0-100) appears when OCR ran. Below 60 the Actor adds a warning that the text needs a check.
  • tokenEstimate is about 4 characters per token (use your own tokenizer for exact counts).
  • The run summary (OUTPUT record) lists every file with status, error code and message for failed files, OCR pages and timings.

Failed files

A file that cannot be converted (bad link, wrong type, corrupt, password protected, too big, too many pages, blocked address) gets a row with status: "failed", an errorCode and a clear error message in the OUTPUT record, and is not charged. If every file fails, the run fails with the first message. Error codes: bad_url, blocked_url, dns_failed, http_error, fetch_failed, timeout, too_large, too_many_pages, empty, unreadable, password_protected, unsupported_format, ocr_disabled, ocr_unavailable, ocr_failed, ocr_timeout, not_found, limit_reached, internal_error.

How to use

  1. Click Start with the prefilled example (a public-domain IRS form, 6 pages, about 3 seconds) or paste your own direct file links.
  2. For private files use Upload a file, a key-value store (sourceKeys) or base64 files ([{"filename": "a.pdf", "contentBase64": "..."}]).
  3. Optional: switch on Include RAG chunks, choose OCR languages, change limits.
  4. Open the Output tab, or call the dataset API from your code.

API example (JavaScript):

const run = await client.actor('<user>/document-to-markdown-for-ai').call({
documentUrls: ['https://example.com/contract.pdf', 'https://example.com/prices.xlsx'],
includeChunks: true, chunkSize: 600, ocrLanguages: ['eng', 'deu'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const doc of items) console.log(doc.filename, doc.metadata.tokenEstimate, doc.chunks.length);

How each format is converted

FormatResult
PDFText layer first (page by page). Tables found by ruling lines become Markdown tables; headings come from font size and bold; list bullets become - items; wrapped lines are joined into paragraphs. Pages with no text layer are OCRed. Metadata: title, author, dates.
DOCXHeadings (Title, Heading 1-6), paragraphs, bold/italic, bullet/numbered lists, tables, in document order. Embedded images are skipped.
XLSXOne Markdown table per visible sheet (hidden sheets skipped), cell values as shown by the last saved calculation, dates as ISO, a row cap (maxSheetRows, default 2,000) and a warning when cut.
PPTXOne section per slide: title, text in reading order, tables, speaker notes. Pictures are skipped.
HTMLMain content (<main> or <article>, else the body without nav/footer/aside), scripts and styles removed, links kept, tables extracted.
EMLSubject, From, To, Date, body (HTML preferred), list of attachments (attachments are listed, not converted: send them as separate files).
ImagesOCR. Multi-page TIFF = one page per frame. Small images are enlarged before OCR for better accuracy.
TXT / MD / CSVText as is; CSV becomes a table (with the row cap).

Limits (all adjustable in the input)

SettingDefaultMax
File size50 MB200 MB
Pages per document (PDF pages, slides, TIFF frames)1002,000
OCR pages per document502,000
Rows per sheet2,000200,000
Documents per run10010,000

Over a limit the file fails with a message that names the setting, and nothing is charged. Pages beyond maxOcrPagesPerDocument are not OCRed (and not charged): they are left empty and the file carries a warning.

What it cannot do (honest list)

  • No handwriting. OCR is Tesseract 5 for printed text. Photos of crumpled paper, tiny print and low-resolution scans lower the accuracy; the run reports a confidence score and warns below 60.
  • Complex layouts. Multi-column pages, forms with boxes and magazine layouts are read in a simplified order (see the IRS Form W-9 example: the text is all there, but columns can interleave). Tables without ruling lines are not detected as tables and stay as text.
  • Scanned tables are returned as OCR text, not as Markdown tables.
  • Old binary Office files (.doc, .xls, .ppt) and RTF are not supported: save as .docx, .xlsx, .pptx first. Images inside Word and PowerPoint files are not OCRed.
  • Formulas and charts: XLSX values come from the last calculation saved in the file; charts and shapes are ignored.
  • No web crawling. It reads the file links you give it. Links to private networks and cloud metadata addresses are refused.
  • Languages for OCR: English, German, French, Spanish, Italian, Portuguese, Dutch, Polish, Czech, Swedish, Russian, Turkish, Arabic, Hindi, Vietnamese, Japanese, Korean, Chinese (simplified, traditional). Pick every language that appears on the page.

Speed and memory

Measured in the Docker image with the CPU limited like the Apify platform gives it (about 1 core per 4 GB of memory; see TESTING.md):

  • OCR: about 2.6 s per dense A4 page (about 700 words) with 1 core / 4 GB, about 7 s with 0.5 core / 2 GB. Memory stays under 350 MB.
  • PDF with a text layer: about 0.3 s per page; Word, Excel, PowerPoint, HTML: under 1 s per file.
  • Default memory is 2048 MB (fine for most runs). For big OCR batches choose 4096 MB: twice the CPU, so a run finishes about 2.5x faster.

Safety

  • URLs are checked before and after every redirect, and the connection goes to the address that was checked. Loopback, private, link-local, carrier-grade NAT, multicast, reserved and cloud metadata addresses, localhost, .internal and .local names are refused.
  • Your files are processed in the run's container and stored only in the run's own key-value store and dataset. Nothing is sent to a third-party service.
  • Office files are checked against zip bombs (more than 400 MB expanded is refused).

Open-source components and licences

Components (licences checked at build time, versions pinned in requirements.txt): Tesseract OCR 5 (Apache-2.0), pdfplumber and pdfminer.six (MIT), pypdf (BSD-3), pypdfium2 (Apache-2.0 / BSD-3, PDFium), python-docx, openpyxl and python-pptx (MIT), Beautiful Soup (MIT), lxml (BSD-3), markdownify (MIT), Pillow (HPND), httpx (BSD-3), Apify SDK (Apache-2.0). No AGPL/GPL component (PyMuPDF and pymupdf4llm were deliberately not used).

FAQ

Is there a free way to try it? The prefilled input converts a public-domain PDF for a few cents of Apify credit.

Why is my OCR text wrong? Check metadata.ocrConfidence and warnings. Pick the right OCR languages, raise OCR render resolution to 300 for fine print, or send a better scan.

My PDF has text but it looks like garbage. Some PDFs embed fonts without a usable text map. Set OCR mode to force to OCR every page instead.

Can I get only the Markdown? Yes: turn off pages and tables; use markdown or the .md file at markdownUrl.

Do you keep my files? No. They live in the run's storage, which follows your Apify retention settings.

Development

See TESTING.md (tests, measurements), PRICING.md (price and cost), PUBLISHING.md (release notes).