PDF & Document to Markdown and Text: PDF, DOCX, PPTX, HTML
Pricing
from $1.00 / 1,000 document converteds
PDF & Document to Markdown and Text: PDF, DOCX, PPTX, HTML
Convert PDFs, Word, PowerPoint, Excel, CSV, text files and web pages from URLs into clean Markdown and plain text for LLMs, RAG and AI agents. Headings, lists, tables, metadata, page splits, scanned-PDF detection. $1 per 1,000 documents + $0.10 per 1,000 PDF pages.
Pricing
from $1.00 / 1,000 document converteds
Rating
0.0
(0)
Developer
Naveen Raja
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 hours ago
Last modified
Categories
Share
Turn PDFs, Word documents, PowerPoint decks, Excel sheets, CSV, text files and web pages into clean Markdown and plain text, ready for LLMs, RAG pipelines and AI agents. Paste links (or pick a key-value store with files), and get one row per document with the content, the title, author and other document metadata, page count, word count and language. The real file type is detected from the file itself, so links without a file extension work too. Headings, lists and tables are kept where the format has them; running headers, footers and page numbers are removed from PDFs; scanned PDFs are flagged instead of returning garbage.
| What you pay for | Price |
|---|---|
document: one converted document (any format) | $0.001 ($1 per 1,000 documents) |
page: one PDF page or PowerPoint slide with text, or 1,000 spreadsheet data rows (started; header rows are free) | $0.0001 ($0.10 per 1,000 pages) |
| Actor start (standard Apify event) | $0.00005 per GB of run memory, once per run ($0.00005 at the default 512 MB) |
| Example | Charged | Cost |
|---|---|---|
| 1 web page or Word file | 1 document | $0.001 |
A spreadsheet or CSV with up to 1,000 data rows (the default maxRowsPerSheet converts at most 1,000 per sheet) | 1 document + 1 page | $0.0011 |
A CSV with 2,500 data rows and maxRowsPerSheet 2,500 or more | 1 document + 3 pages | $0.0013 |
| A 15-page PDF (an arXiv paper) | 1 document + 15 pages | $0.0025 |
| A 100-page PDF report | 1 document + 100 pages | $0.011 |
| A 492-page PDF (NIST SP 800-53, tested) | 1 document + 492 pages | $0.050 |
| 1,000 web pages | 1,000 documents | $1.00 |
| 1,000 PDFs of 10 pages | 1,000 documents + 10,000 pages | $2.00 |
| Our mixed test batch: 5 PDFs (743 pages), 3 PowerPoint decks (13 slides), 2 Word files, an Excel workbook, 2 CSV files, a text file, a Markdown file and 4 web pages, plus 3 files that were free (2 scanned PDFs, 1 legacy .ppt) | 19 documents + 758 pages (755 pages and slides + 1 page each for the 3 spreadsheets) | $0.095 |
Apify platform costs are included. You don't pay for failed downloads (404, access denied, login pages, timeouts), files over your size limit, unsupported formats, empty documents, web pages that need JavaScript, scanned PDFs (also when they carry a stamp or header line), pages without text or with only a page number, the same document given twice (after redirects), or documents skipped at your spending limit. Set Maximum cost per run (maxTotalChargeUsd in the API) and the Actor stops cleanly at that amount; it never converts pages it can't charge for.
What you get
- One tool for the common formats: PDF, Word (
.docx,.docm,.dotx), PowerPoint (.pptx,.pptm,.ppsx), Excel (.xlsx,.xlsm), CSV / TSV, plain text, Markdown and any web page. - Viewer links work: GitHub / GitLab file pages, Dropbox share links and Google Drive / Docs links are rewritten to the file itself (public files only), with a note in the row.
- Markdown that keeps the structure: headings (
#,##...), bullet and numbered lists with their levels, tables as Markdown tables, bold and italic (Word), footnotes and endnotes ([^1]), text boxes, and optionally links. Or plain text, or both. - Clean PDF text: paragraphs re-joined across line breaks, words split by end-of-line hyphens repaired, headings detected from font sizes, bold numbered titles ("3.1 Methods") and the PDF's bookmarks, bullets turned into lists, superscripts kept on their line, and repeated page headers, footers and page numbers removed.
- Web pages: only the main content (navigation, menus, cookie banners, footers and ads dropped), with title, author, publish date, site name and description.
- PowerPoint: one section per slide (
## Slide 3: Title) in reading order, bullet levels, tables, chart titles and the speaker notes. - Excel and CSV: every sheet as a Markdown table (header row first, formulas as their saved values), with a row limit per sheet so huge sheets stay usable. Charged per document plus one
pageper started 1,000 data rows (the header row is free); each row shows itsmetadata.rowsandpageEvents. - Metadata: title, author, subject, keywords, created / modified dates, creating application, page count, word count, character count, table count and language (ISO 639-1).
- One row per page if you want it (
splitPages): page-level rows withpageNumberfor citations and RAG chunking. - Page selection:
pageRange("1-5, 8, 10-") andmaxPagesto convert only what you need (and pay only for that). - Scanned PDFs are detected: a page that is an image with no text, or only a stamp / header line (court headers, Bates numbers), is reported with
needsOcr: trueand listed inpagesWithoutText; a document made only of such pages getsstatus: "needs_ocr". Not charged. - Clear errors per document: every input gets a row with
status(ok,needs_ocr,empty,failed,skipped) and, if it wasn't converted, anerrorKind(not_found,access_denied,login_required,too_large,unsupported_type,encrypted,timeout,duplicate,charge_limit...) and a readableerror. One bad link never stops the others, and a run whose links are all bad still succeeds with the error rows. - Safe on long runs: progress is saved in the run's key-value store, so if Apify moves the run to another server it continues where it stopped, without returning or charging a document twice.
- Built for automation and AI agents: small, predictable rows, pay-per-event pricing without usage fees, limited permissions, and a
SUMMARYrecord per run.
Use cases
- RAG and knowledge bases: convert manuals, policies, reports, papers and help-center pages into Markdown chunks (one row per page with
splitPages) for your vector database. - AI agents (MCP): give an agent one tool for "read this PDF / this deck / this page" that returns clean Markdown and says clearly when a file can't be read.
- LLM pipelines: summarise, classify or extract data from documents without writing a parser per format.
- Document search and analytics: word counts, languages, page counts and metadata for a list of document links.
- Content migration: Word and PowerPoint to Markdown for docs sites, wikis and static site generators.
How to use
- Add Document URLs: direct links to files or web pages, one per line.
- Or select a Key-value store with files (optionally only some Record keys) to convert files you uploaded to Apify.
- Choose the Output format (Markdown, plain text or both) and, if you want, One row per page, a Page range or Max pages per document.
- Run it and download the results as JSON, CSV or Excel, or read them through the API. The dataset has the views Documents, Content and Status & errors; the run's key-value store has a
SUMMARYrecord.
Input examples
The prefilled input (the IRS Form W-9 PDF and a W3C page):
{"urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf","https://www.w3.org/WAI/fundamentals/accessibility-intro/"]}
Page-level rows of the first 20 pages of a long PDF, as Markdown and plain text:
{"urls": ["https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r5.pdf"],"splitPages": true,"pageRange": "1-20","outputFormat": "both"}
Files you uploaded to one of your key-value stores:
{"keyValueStore": "<your store ID or name>","keyValueStoreKeys": ["contract.docx", "slides.pptx"]}
Output example
A real row from the prefilled run (Markdown shortened):
{"url": "https://www.w3.org/WAI/fundamentals/accessibility-intro/","finalUrl": "https://www.w3.org/WAI/fundamentals/accessibility-intro/","status": "ok","error": null,"errorKind": null,"fileType": "html","contentType": "text/html","fileName": null,"fileSizeBytes": 57249,"title": "Introduction to Web Accessibility","author": null,"language": "en","pageCount": null,"pagesProcessed": null,"pageNumber": null,"wordCount": 996,"charCount": 6750,"tableCount": 0,"needsOcr": false,"pagesWithoutText": [],"truncated": false,"notes": [],"metadata": {"description": "Accessibility resources free online from the international standards organization: W3C Web Accessibility Initiative (WAI).","siteName": "Web Accessibility Initiative (WAI)","publishedAt": "2026-02-03","canonicalUrl": "https://www.w3.org/WAI/fundamentals/accessibility-intro/"},"markdown": "# Introduction to Web Accessibility\n\n## Accessibility in Context\n\nThe power of the Web is in its universality.\n\nAccess by everyone regardless of disability is an essential aspect.\n\nThe Web is fundamentally designed to work for all people, whatever their hardware, software, language, location, or ability. When the Web meets this goal, it is accessible to people with a diverse range of hearing, movement, sight, and cognitive ability.\n\nThus the impact of disability is radically changed on the Web because the Web removes barriers to communication and interaction that many people face in the physical world. However, when websites, applications, technologies, or tools are badly designed, they can create barriers that exclude people from using the Web.\n\n**Accessibility is essential for developers and organizations that want to create high-quality websites and web tools, and not exclude people from using their products and services.**\n\n## What is Web Accessibility\n\nWeb accessibility means that websites, tools, and technologies are designed and developed so that people with disabilities can use them. More specifically, people can:\n\n- perceive, understand, navigate, and interact with the Web\n- contribute to the Web\n\n...","text": null,"markdownUrl": null,"textUrl": null,"processedAt": "2026-10-18T16:03:34Z"}
The PDF of the same run (Markdown shortened):
{"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf","finalUrl": "https://www.irs.gov/pub/irs-pdf/fw9.pdf","status": "ok","error": null,"errorKind": null,"fileType": "pdf","contentType": "application/pdf","fileName": "fw9.pdf","fileSizeBytes": 140815,"title": "Form W-9 (Rev. March 2024)","author": "SE:W:CAR:MP","language": "en","pageCount": 6,"pagesProcessed": 6,"pageNumber": null,"wordCount": 6391,"charCount": 37712,"tableCount": 0,"needsOcr": false,"pagesWithoutText": [],"truncated": false,"notes": [],"metadata": {"subject": "Request for Taxpayer Identification Number and Certification","keywords": "Fillable","createdAt": "2024-03-06T13:18:13Z","modifiedAt": "2024-03-06T13:18:13Z","creatorTool": "Designer 6.5","producer": "Designer 6.5"},"markdown": "Form W-9 (Rev. March 2024)\n\nRequest for Taxpayer Identification Number and Certification Department of the Treasury Internal Revenue Service Go to www.irs.gov/FormW9 for instructions and the latest information.\n\nGive form to the requester. Do not send to the IRS.\n\n...","text": null,"markdownUrl": null,"textUrl": null,"processedAt": "2026-10-18T16:03:34Z"}
A link that couldn't be converted (not charged):
{"url": "https://github.com/settings/profile","finalUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fsettings%2Fprofile","status": "failed","error": "The URL returned a login page (password form), not a document. Only public pages can be converted.","errorKind": "login_required","contentType": "text/html; charset=utf-8","markdown": null}
Output fields
| Field | Meaning |
|---|---|
url, finalUrl | The input URL and the URL after redirects |
status | ok (converted, charged), needs_ocr (scanned, no usable text layer), empty (no text), failed, skipped (spending limit reached, or the same document as another input) |
error, errorKind | Why a document failed, in words and as a stable code |
fileType | pdf, docx, pptx, xlsx, csv, html, markdown or txt (detected from the content) |
contentType, fileName, fileSizeBytes | As sent by the server (file name from the URL or Content-Disposition) |
title, author, language | From the document metadata (or the first heading); language detected from the text |
pageCount, pagesProcessed, pageNumber | Pages / slides / sheets in the document, how many were converted, and the page of a page row |
wordCount, charCount, tableCount | Size of the converted content |
needsOcr, pagesWithoutText | Scanned pages that have no text layer |
pageEvents | page events for this row as planned when it was stored: PDF pages / slides with text, or one per started 1,000 spreadsheet data rows; 0 for free rows. In page-row mode (splitPages) PDF / PowerPoint page rows show 1 or 0 and a workbook's events are on its first sheet row. Rows are stored before their page events are charged, so a failed row never costs anything; the run's SUMMARY (chargedEvents, perDocument.billedPages, pageChargesCut) is the source of truth for what was charged. It only differs if a charge is cut at the limit (the status message then says so). |
truncated, notes | Whether something was left out (page range, limits) and why |
metadata | Subject, keywords, description, created / modified / published dates, creating application, producer, site name |
markdown, text | The content (null for the format you didn't ask for) |
markdownUrl, textUrl | Links to the full content in the key-value store when it is too large for one dataset row (over 5 MB) |
Use it from the API, an app or an AI agent
Run synchronously and get the rows in one call (keep your API token in the APIFY_TOKEN environment variable):
curl -X POST "https://api.apify.com/v2/acts/fairfetch~document-to-markdown/run-sync-get-dataset-items?maxTotalChargeUsd=0.10" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"], "outputFormat": "markdown"}'
Python (pip install "apify-client>=3"):
import osfrom decimal import Decimalfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("fairfetch/document-to-markdown").call(run_input={"urls": ["https://www.irs.gov/pub/irs-pdf/p17.pdf"], "splitPages": True, "maxPages": 30},max_total_charge_usd=Decimal("0.05"),)for row in client.dataset(run.default_dataset_id).iterate_items():print(row["pageNumber"], row["wordCount"], row["markdown"][:80])
The Actor runs with limited permissions and pay-per-event pricing without usage fees, so AI agents can call it through the Apify MCP server and pay per run. Rows have a fixed set of fields, failures come back as rows with a clear errorKind, and maxPages / pageRange keep long documents from flooding an agent's context.
Performance and limits
- From our test runs on Apify: the prefilled input (a 6-page PDF and a web page) takes 5-9 seconds at the default 512 MB; a single web page about 3 seconds. A batch of 22 mixed files with 764 pages took 18 seconds at 1,024 MB and 41-93 seconds at 512 MB. A 492-page PDF converts in about 3 seconds of CPU; memory stayed around 100-225 MB.
- For big batches of large PDFs or long web pages, give the run 1,024-2,048 MB: Apify gives more CPU to more memory, so it runs several times faster for about the same platform cost.
- Downloads run in parallel (
maxConcurrency, default 4); documents are converted one at a time in a separate process, so a damaged file that crashes a parser or a document that takes longer than about 5 minutes fails alone and the run continues. - Files are limited to
maxFileSizeMb(default 50 MB, up to 200 MB), checked fromContent-Lengthbefore downloading and again while downloading;requestTimeoutSecslimits each download, retries included. Plain text and web pages are converted up to about 30 MB per GB of run memory (about 15 MB at the default 512 MB); longer files are cut there and markedtruncatedwith a note. Spreadsheets and CSV files are cut atmaxRowsPerSheet(default 1,000) rows per sheet and 100 columns; if you raise it to tens of thousands of rows, give the run 2 GB or more (a 45,000-row x 65-column workbook peaked at about 760 MB). - No OCR: scanned PDFs and images are reported (
needs_ocr/unsupported_type), not read. A page counts as scanned when it has no text of its own and images cover at least 30% of it, or when images cover at least 90% of it and its few characters (under 100, after running headers and page numbers are removed) are stamp-like: in the top or bottom 12% of the page, or vertical, or, only when the covering image looks like a scanner's output (1-bit or grayscale, JBIG2 or CCITT compression), in small type (12 pt or less) anywhere on the page, like a mid-page "RECEIVED" stamp. Born-digital pages are not scans: photo slides with a caption, and full-page colour photos with a small caption (portfolios, brochure covers), are converted and billed as text pages. A colour scan with a small mid-page stamp and no other text is therefore billed as a one-line text page. - PDF tables come out as text lines in reading order; there is no table reconstruction for PDFs (Word, PowerPoint, Excel, CSV and HTML tables are real Markdown tables). Multi-column PDFs follow the order of the text in the file, which is the reading order for most generated PDFs.
- Not supported: legacy
.doc/.xls/.ppt, OpenDocument, RTF, EPUB, ZIP archives, images, audio and video (reported with a clear error, not charged). Password-protected PDFs are reported asencrypted. - Web pages are downloaded, not rendered: pages that build their content with JavaScript come back
emptywith a note (not charged). Pages behind a login are reported aslogin_required. Links to local or private network addresses (localhost,10.x,169.254.x...) are refused, also after redirects (blocked_host). - The Actor identifies itself with the User-Agent
fairfetch-document-to-markdown/1.0; some sites refuse automated downloads (access_denied). - Content over 5 MB per row (whole document or one page row) is stored in the run's key-value store and linked from the row (
markdownUrl,textUrl); the row keeps the first 1.5 MB of each. - The run ends SUCCEEDED when documents were converted or when every failure was the input's own problem (404, unsupported, too large, invalid link, empty, scanned); the status message and the error rows say what happened. It FAILS only when nothing could be converted because every download was blocked by the sources or because of an internal error.
FAQ
Which file types are supported? PDF, DOCX / DOCM / DOTX, PPTX / PPTM / PPSX, XLSX / XLSM, CSV / TSV, TXT, Markdown and HTML web pages. The type is detected from the file content (magic bytes and the parts inside Office files), then from the Content-Type header and the file name, so https://example.com/download?id=123 works.
Can it read scanned PDFs? It detects them (needsOcr: true), including scans with a stamped header line, but doesn't run OCR, and you don't pay for them. PDFs that already have a text layer (including scans that were OCR'd before) are converted normally.
How are pages counted? Each PDF page and PowerPoint slide that has text is one page event, the same with or without splitPages. Pages without text, with only a page number or running header, or scanned pages are free. Excel and CSV files count one page per started 1,000 converted data rows, all sheets together, header rows not counted (1-1,000 data rows = 1 page; 2,500 data rows = 3 pages if you raise maxRowsPerSheet to 2,500, since the default converts at most 1,000 rows per sheet). Every row shows the page events it was charged in pageEvents. Word, text and web pages are charged per document only.
How do I convert my own files? Upload them to a key-value store in Apify Console (Storage → Key-value stores) and select that store in Key-value store with files (Apify then lets the run read it), or link them from any public URL, including GitHub, Dropbox and Google Drive / Docs share links of public files.
Why is my Markdown different from what I see in the PDF? PDFs store positioned text, not structure. The Actor rebuilds paragraphs, headings and lists from fonts and positions; complex layouts (tables, sidebars, forms) can come out in a different order. Word, PowerPoint and HTML keep their real structure.
Does it follow robots.txt? It downloads only the URLs you give it (no crawling), follows redirects, and sends a clear User-Agent. Use it only for documents you are allowed to access.
Can I limit the cost? Yes: maxPages, pageRange and maxFileSizeMb per document, and Maximum cost per run for the whole run.
Legal
This Actor downloads only the documents and pages whose links you provide and converts them; it does not log in, bypass paywalls or access controls, or crawl other pages. You are responsible for having the right to access and process the documents, and for complying with their licenses, the sites' terms and the laws that apply to you, including data protection laws if documents contain personal data. The open-source libraries used (PDFium via pypdfium2, python-docx, python-pptx, openpyxl, trafilatura) are under permissive licenses (BSD, MIT, Apache-2.0). This Actor is not affiliated with Adobe, Microsoft or any website whose documents you convert; product names are used only to describe file formats.