PDF to Structured Markdown Converter
Pricing
from $7.64 / 1,000 document extracteds
PDF to Structured Markdown Converter
Convert PDFs into page-aware Markdown with typed headings, paragraphs, lists, links, simple tables, bounding boxes, and embedded-image references.
Pricing
from $7.64 / 1,000 document extracteds
Rating
0.0
(0)
Developer
Stas Persiianenko
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Turn public PDF URLs and uploaded PDF files into clean, page-aware Markdown and typed layout metadata.
This pdf to markdown converter runs fully inside your Apify Actor container. It reads PDF text and layout locally, identifies likely headings, paragraphs, list items, table rows, links, and embedded-image references, and returns one integration-friendly record per document.
Use it for repeatable RAG ingestion, knowledge-base preparation, document publishing, archive migration, and PDF content analysis without sending document contents to a third-party conversion API.
What does this Actor do?
For each supplied PDF, the Actor:
- downloads an anonymous public PDF URL or reads a PDF from the run's default key-value store;
- validates its size and PDF signature;
- extracts page text and positioned text items;
- infers headings, paragraphs, list items, and simple tables;
- collects PDF link annotations and embedded-image references;
- creates combined Markdown with optional page markers;
- emits detailed page and block metadata to the default dataset;
- optionally saves a
.mdfile in the default key-value store.
Each successful document produces one charged document result. Failed inputs produce diagnostic dataset rows but are not charged as documents. Fields such as error, warnings, links, tables, and image references are included in the document record and are not separately charged.
Who is it for?
RAG and AI engineers
Prepare PDFs for chunking, embeddings, vector databases, document Q&A, and retrieval pipelines while retaining page references.
Data and knowledge teams
Normalize document collections into consistent Markdown and JSON-compatible block metadata on scheduled Apify runs.
Publishers and technical writers
Move text-first PDFs into editable Markdown while preserving useful document structure and links.
Automation developers
Call one Actor from JavaScript, Python, cURL, Apify Tasks, schedules, webhooks, or MCP tools.
Why use this PDF to Markdown converter?
- Local conversion: no external conversion API key is required.
- Batch input: combine multiple public URLs and uploaded storage keys in one run.
- Page-aware output: Markdown can include
<!-- page: N -->markers. - Typed blocks: inspect page, type, Markdown, plain text, bounding box, list marker, heading level, table cells, and image reference.
- Integration-ready: the full record is available in the default dataset.
- File-ready: optional
.mdartifacts are saved to the default key-value store. - Bounded failures: one invalid PDF does not discard successful conversions in the same batch.
- SSRF protection: URL inputs must resolve to publicly routable addresses.
What data is extracted?
| Field | Meaning |
|---|---|
status | succeeded or failed for this input |
sourceType | url or key-value-store |
source | Original URL or storage key |
finalUrl | URL after redirects, when applicable |
fileName | Sanitized PDF file name |
byteSize | PDF size in bytes |
title, author | PDF metadata when available |
pageCount | Total pages in the PDF |
processedPageCount | Pages processed under your safety limit |
markdown | Combined Markdown for processed pages |
markdownKey | Key of the generated .md artifact |
pages | Page-level text, Markdown, blocks, links, and image references |
headings | Document-wide heading index with levels and pages |
links | Document-wide external-link index |
tables | Inferred table rows plus Markdown |
imageReferences | Stable references to image paint operations |
warnings | Non-fatal limits or metadata issues |
error | Per-document failure explanation |
convertedAt | ISO 8601 conversion time |
Nullable fields are expected when a PDF does not contain the corresponding metadata.
Getting started
- Open the Actor input page.
- Add one or more direct PDF URLs under PDF URLs.
- Optionally add keys for PDFs already uploaded to the default key-value store.
- Choose document, page, file-size, and timeout limits.
- Keep Include page markers enabled for page-aware RAG workflows.
- Keep Save Markdown files enabled when you need downloadable artifacts.
- Start the run.
- Open Results for structured records or Markdown files for
.mdartifacts.
A safe first input is:
{"pdfUrls": [{ "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" }],"maxDocuments": 1,"maxPagesPerDocument": 20,"includePageMarkers": true,"saveMarkdownFiles": true}
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
pdfUrls | array | sample PDF | Anonymous public HTTP(S) PDF URLs |
pdfFiles | array | [] | Default key-value store keys and optional file names |
maxDocuments | integer | 10 | Unique PDFs to process, from 1 to 100 |
maxPagesPerDocument | integer | 200 | Page safety limit, from 1 to 1,000 |
maxFileSizeMb | integer | 25 | Per-PDF size limit, from 1 to 100 MB |
requestTimeoutSecs | integer | 45 | Per-attempt URL timeout, from 5 to 180 seconds |
includePageMarkers | boolean | true | Add page comments to combined Markdown |
saveMarkdownFiles | boolean | true | Save generated .md artifacts |
At least one item is required across pdfUrls and pdfFiles. Duplicate URLs and duplicate storage keys are processed once.
How to convert an uploaded PDF file
Upload the binary PDF to the run's default key-value store with content type application/pdf, then reference its key:
{"pdfFiles": [{"key": "quarterly-report","fileName": "quarterly-report.pdf"}],"saveMarkdownFiles": true}
The storage value must be the binary PDF, not a JSON wrapper or a URL string.
Output example
A real one-page sample produces the following shape (long arrays shortened):
{"status": "succeeded","sourceType": "url","source": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf","finalUrl": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf","fileName": "dummy.pdf","contentType": "application/pdf","byteSize": 13264,"title": null,"author": null,"pageCount": 1,"processedPageCount": 1,"markdown": "<!-- page: 1 -->\n\nDummy PDF file","markdownKey": "markdown-3d7d1b17f7597eed.md","pages": [{"pageNumber": 1,"markdown": "Dummy PDF file","text": "Dummy PDF file","blocks": [{"type": "paragraph","pageNumber": 1,"markdown": "Dummy PDF file","text": "Dummy PDF file"}],"links": [],"imageReferences": []}],"headings": [],"links": [],"tables": [],"imageReferences": [],"warnings": [],"error": null}
How headings, lists, and tables are detected
The converter uses PDF text coordinates and font sizes rather than visual HTML semantics, because PDFs normally do not contain HTML-like heading tags.
- Larger, bounded text lines become inferred Markdown headings.
- Bullet and numbered prefixes become list items.
- Lines with at least three positionally separated cells become simple Markdown table rows.
- Other lines become paragraphs in page reading order.
The original text, approximate bounding box, page number, and inferred type remain available in pages[].blocks[] so downstream code can refine decisions.
Links and image references
PDF link annotations are exported with target URL, page number, and annotation rectangle when available.
Embedded images are represented as stable references such as page-2-image-1. The Actor does not export image bytes or perform image OCR. References let downstream pipelines preserve figure positions without claiming that image contents were understood.
RAG ingestion workflow
A practical recurring workflow is:
- collect or upload the latest source PDFs;
- run this Actor on an Apify schedule;
- split
markdownby page markers orpages[].blocks[]; - attach
source,pageNumber,title, and block type as chunk metadata; - generate embeddings;
- upsert chunks into your vector database;
- compare source hashes or file metadata before replacing older chunks.
The Actor produces conversion output; it does not call an embedding model or vector database by itself.
Publishing workflow
For Markdown publishing:
- enable
saveMarkdownFiles; - retrieve each
markdownKeyfrom the run's key-value store; - review inferred headings and complex tables;
- rewrite image-reference anchors for your publishing platform;
- commit the resulting Markdown to your content repository.
This is especially useful for text-first manuals, reports, policies, and papers.
How much does it cost to convert PDF documents to Markdown?
Pay-per-event pricing has two parts:
- Run start: $0.005 once per run.
- PDF converted: BRONZE tier currently $0.012737 per successful document, with lower per-document prices at higher Apify tiers.
Examples at the BRONZE event price:
| Successful PDFs | Estimated Actor charge |
|---|---|
| 1 | $0.017737 |
| 10 | $0.13237 |
| 100 | $1.2787 |
Failed documents are included in the dataset for diagnosis but do not emit the document charge event. Platform compute usage is governed by Apify's applicable plan and the active pricing shown in Console; check the live pricing panel before large runs.
JavaScript API example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('automation-lab/pdf-to-structured-markdown-converter').call({pdfUrls: [{ url: 'https://arxiv.org/pdf/1706.03762' }],maxDocuments: 1,maxPagesPerDocument: 15,includePageMarkers: true,saveMarkdownFiles: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items[0].markdown);
Python API example
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('automation-lab/pdf-to-structured-markdown-converter').call(run_input={'pdfUrls': [{'url': 'https://www.irs.gov/pub/irs-pdf/fw9.pdf'}],'maxDocuments': 1,'maxPagesPerDocument': 6,'saveMarkdownFiles': True,})items = client.dataset(run['defaultDatasetId']).list_items().itemsprint(items[0]['processedPageCount'])
cURL API example
curl -X POST \"https://api.apify.com/v2/acts/automation-lab~pdf-to-structured-markdown-converter/runs?token=$APIFY_TOKEN&waitForFinish=300" \-H 'Content-Type: application/json' \-d '{"pdfUrls": [{"url":"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"}],"maxDocuments": 1,"saveMarkdownFiles": true}'
Use the returned defaultDatasetId to fetch structured output from the Dataset API.
Use with MCP and AI agents
Add the Apify MCP endpoint to Claude Code:
claude mcp add --transport http apify \"https://mcp.apify.com?tools=automation-lab/pdf-to-structured-markdown-converter"
Claude Desktop
Add this server to Claude Desktop's MCP configuration:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=automation-lab/pdf-to-structured-markdown-converter"}}}
Cursor
Add the same apify HTTP server URL in Cursor's MCP settings.
VS Code
Add the same apify HTTP server URL to your VS Code MCP server configuration.
Example prompts:
- “Convert this public PDF to page-aware Markdown and summarize its headings.”
- “Extract table metadata from the IRS W-9 PDF and return the page numbers.”
- “Prepare this technical paper as Markdown blocks for a RAG pipeline.”
Scheduling and automation
Save a tested input as an Apify Task, then attach a schedule for recurring document processing. Webhooks can trigger downstream embedding, publishing, or archival jobs after successful runs.
For changing URLs, keep the source list in the Task input. For changing uploaded files, update the default key-value store keys before starting the Task.
Limits and expected behavior
- Only PDF inputs are supported.
- URLs must be anonymous HTTP(S) endpoints on public network addresses.
- Redirects are limited to five and revalidated against private addresses.
- Transient downloads receive bounded retries; deterministic HTTP errors do not.
- Password-protected and malformed PDFs may fail.
- Scanned image-only PDFs require OCR and are not supported.
- Multi-column reading order is inferred and may need review.
- Borderless or irregular tables may remain paragraphs or separate table rows.
- Image bytes, captions, and OCR text are not extracted.
maxPagesPerDocumenttruncation is reported inwarnings.- One failed document does not stop other valid inputs, but a run with no successful conversion fails visibly.
Troubleshooting
“Input is not a PDF”
Confirm the URL returns a real PDF rather than an HTML login page, consent page, or download landing page. Direct responses must begin with the %PDF- signature.
“Only publicly routable PDF URLs are allowed”
Private, loopback, link-local, and credential-bearing URLs are blocked. Upload private files to the default key-value store and use pdfFiles instead.
The output contains little or no text
The source may be a scanned image-only PDF. This Actor does not perform OCR. Use a text-layer PDF or an OCR-focused Automation Lab workflow before conversion.
A table is split into paragraphs
PDFs store positioned glyphs, not semantic tables. Use pages[].blocks[].bbox and text values to add source-specific post-processing for complex layouts.
A large PDF times out
Raise requestTimeoutSecs for slow downloads, increase the run timeout when needed, or lower maxPagesPerDocument. Do not raise maxFileSizeMb beyond what your memory allocation can safely parse.
Legality and responsible use
Process only PDFs you are authorized to access and transform. Respect copyright, contractual restrictions, privacy obligations, and applicable data-protection law.
Do not use this Actor to bypass authentication, access controls, paywalls, or private networks. URL inputs intentionally reject embedded credentials and non-public destinations.
Review generated Markdown before public redistribution. Structural inference is automated and does not transfer rights in the source document.
Related Automation Lab Actors
- Layout-Aware Document Text Extractor — use when you need plain text from public PDF, image, and web-page URLs rather than Markdown document records.
- Bulk Image Format Converter — convert extracted or separately downloaded images between common formats.
- HTML Table to Excel Exporter — export native HTML tables to XLSX when the source is a web page rather than a PDF.
FAQ
Does it support batch PDF conversion?
Yes. Supply up to 100 unique URL and key-value-store inputs, bounded by maxDocuments.
Does it preserve pages?
Yes. Every block has a page number, every page has separate Markdown, and combined Markdown can contain page comments.
Does it extract tables?
It conservatively infers simple rows from positioned text columns. Complex layouts are not guaranteed to reconstruct perfectly.
Does it extract images?
It emits stable embedded-image references. It does not save image bytes or interpret image content.
Does it use AI?
No external model is required. Conversion uses deterministic local PDF parsing and layout heuristics.
Can it convert PDF to JPG, Excel, DOCX, or EPUB?
No. Those are separate file-conversion jobs. This Actor specifically converts PDF content to Markdown and structured metadata.
Can I process private documents?
Yes, by uploading the binary PDF to the run's default key-value store and referencing its key. Do not expose private files through public URLs.
What happens when one PDF fails?
The Actor writes a failed dataset record with a diagnostic message, continues with remaining inputs, and does not charge the document event for that failure.
What happens when every PDF fails?
The run fails after diagnostic rows are written, so schedules and webhooks can detect that no useful conversion was produced.
Can I use the output with LangChain or LlamaIndex?
Yes. Consume markdown directly or create chunks from pages[].blocks[], then attach source and page metadata in your framework.