PDF to Markdown Scraper | Text, Tables & OCR
Pricing
from $1.00 / 1,000 extracted pages
PDF to Markdown Scraper | Text, Tables & OCR
Convert public PDF links into Markdown, text, tables and source-cited chunks for AI search. Optional English OCR and paid AI cleanup. Export page-level JSON or download complete Markdown files.
Pricing
from $1.00 / 1,000 extracted pages
Rating
0.0
(0)
Developer
Inus Grobler
Maintained by CommunityActor stats
1
Bookmarked
14
Total users
0
Monthly active users
10 days ago
Last modified
Categories
Security
Limited permissionsShare
Convert PDF links and uploaded files into Markdown, text, tables and source-cited chunks for AI search. Download complete Markdown documents or export one structured row per extracted page as JSON, CSV or Excel. Use it for research reports, document search, knowledge bases and automated document pipelines.
Paste a PDF link or upload a PDF and start. Standard extraction needs no AI API key. Optional table extraction, local English OCR and chunks for retrieval-augmented generation (RAG) also work with AI cleanup off. Paid AI cleanup is a separate option for difficult pages.
Quick start
- Open the input form.
- Paste PDF links or choose files in Upload PDFs. Uploaded files replace the links, including the prefilled sample.
- Optionally enter Pages to extract, such as
1-5,12,20-25. Leave AI cleanup off for standard extraction. Open Extraction options if you need tables, scanned-page reading, chunks or a page limit. - Start the run and open Structured page results for exported data.
- Open Document downloads for each document's Markdown link and processing status. This works for single PDFs and batches.
The prefilled example is a one-page public PDF. It is a small extraction check, not a demonstration of complex-table or scanned-document accuracy. Start with a few pages of your own document before processing a large batch.
{"pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],"mode": "no_llm"}
Repeated copies of the same URL are processed once. Different URLs pointing to the same file are not assumed to be duplicates.
Choose the output you need
- Markdown and text: turn readable PDF pages into content for search, prompts, reports and downstream processing.
- Tables: retain available table content as Markdown and structured table records. Financial statements, grids and complex layouts still need review.
- Scanned pages: enable local English OCR when a PDF contains page images or weak text extraction. OCR quality depends on resolution, orientation and legibility.
- AI-search chunks: split extracted content into overlapping chunks with source URL and page references. Chunk creation does not call an AI model, generate embeddings or add a separate chunk charge.
- Optional AI cleanup: attempt to repair difficult page formatting through OpenRouter. Review cleaned output against the source when wording and numbers matter.
The Actor processes PDF links or uploaded PDF files supplied by you. It does not crawl websites to discover PDF links, download web pages as PDFs, read live websites, or extract every document format.
Simple input controls
| Control | API field | Behaviour |
|---|---|---|
| PDF links | pdfUrls | One public HTTP or HTTPS PDF URL per entry; up to 100 links. |
| Upload PDFs | pdfFiles | Upload local PDFs in Console. API clients supply uploaded file URLs; uploads replace PDF links. Up to 100 files. |
| Pages to extract | pageRange | Optional selection such as 1-5,12,20-25 or 12-. Blank means all pages. |
| Maximum pages per PDF | maxPages | Caps the number of selected pages attempted. Blank means all selected pages within run and spending limits. |
| Extract tables | extractTables | Enable local table extraction. |
| Read scanned pages | ocrFallback | Enable local English OCR when extraction needs it. |
| Create chunks for AI search | includeRagChunks | Create overlapping chunks with page references. |
| AI cleanup | mode | Off: no_llm; Standard: llm_cheap; Advanced: llm_premium. |
Optional controls can be left unset. Existing API mode defaults and legacy aliases remain supported. Selecting AI cleanup on an older integration can retain that mode's existing automatic OCR, table and chunk defaults; send explicit booleans to control those features independently.
For a sample with tables and chunks, without paid AI cleanup:
{"pdfUrls": ["https://example.com/report.pdf"],"mode": "no_llm","maxPages": 10,"extractTables": true,"ocrFallback": false,"includeRagChunks": true}
Upload a PDF directly
In Console, use Upload PDFs to select files from your computer. Apify stores the uploaded files and passes their URLs to the Actor. When uploads are present, the Actor processes those files only; it ignores the PDF links above. Leave uploads empty to use links. Files must be accessible to the run under Apify's storage permissions. Uploading does not enable AI cleanup.
For API uploads, store a PDF in an Apify key-value store, then pass its record URL in pdfFiles:
{"pdfFiles": ["https://api.apify.com/v2/key-value-stores/YOUR_STORE_ID/records/report.pdf"],"pageRange": "2,5-7","mode": "no_llm"}
Select pages and control costs
Selections use original, one-based PDF page numbers and apply to each document. 1-5,12,20-25 selects those pages; 12- selects page 12 onward. Copied ranges using an en dash, such as 1–5, are accepted too. Repeated pages are extracted once in ascending order. pageRange: "5-10" with maxPages: 3 attempts pages 5, 6 and 7. Requested pages beyond a document's length are ignored with a warning; a selection containing no existing pages fails that document.
Tables, page images, Markdown downloads and search chunks retain original page references. Chunks do not bridge gaps between selected pages. Intentional page selection is not reported as missing content.
Replace the example URL with a direct link to your PDF. An HTML landing page containing a download button is not a PDF URL.
What you receive
The default dataset contains one result per delivered PDF page. Page rows retain the source URL, final download URL, page number, Markdown, text, available metadata, tables, warnings and matching chunks. pageCount is the original document length. processedPageCount counts attempted selected pages, including blank or unreadable pages; pageSelection lists original selected, attempted, blank and unreadable page numbers; the document manifest additionally lists confirmed delivered page numbers. Document page counts and processed page counts describe extraction; the run summary separately reports confirmed delivery.
Selected fields from a page result look like this:
{"sourceUrl": "https://example.com/report.pdf","recordType": "page","status": "success","pageNumber": 2,"pageCount": 2,"markdownText": "## Quarterly Financial Table\n\n| Metric | USD |\n| --- | --- |\n| Revenue | 120000 |\n| Expenses | 80000 |\n| Profit | 40000 |","outputKeys": {"markdown": "OUTPUT_MARKDOWN"},"warnings": []}
The headings and values above come from a two-page demonstration report used for extraction checks. This is an illustrative selection of fields, not a promise that every financial PDF preserves every table correctly.
A chunk includes text, markdown, sourceUrl, pageStart, pageEnd, chunkId and a token estimate. The default chunk target is 1,000 characters with 150 characters of overlap. API users can change chunkSize and chunkOverlap. These are character-based chunks and estimates, not semantic embeddings or exact tokenizer counts. A chunk spanning two pages can appear in both matching page rows; deduplicate by chunkId when building a vector index.
Download complete Markdown and inspect a batch
Open Document downloads for document status, source and delivered page counts, a Markdown key and a direct download URL. Single-document runs retain OUTPUT_MARKDOWN; batches retain keys such as OUTPUT_MARKDOWN_001 and OUTPUT_MARKDOWN_002.
Run summary reports requested and unique documents, ignored duplicate links, successful and partial documents, failures, skipped documents, confirmed delivered pages and charged AI-cleanup pages. These summary records do not create additional paid page rows.
If a later PDF fails, earlier successful results remain available. A PDF stopped by a page limit or spending limit is marked partial with a reason. Unreadable selected pages also make the document partial; genuinely blank pages are listed without marking the document partial. Blank and unreadable pages remain in page diagnostics and do not create dataset rows or page fees. If all selected pages are blank or unreadable, the document fails clearly without a billed page. If a dataset write has an uncertain outcome, the run fails explicitly rather than retrying the write and risking duplicates.
Failed URLs are recorded separately in PDF failure diagnostics (FAILURES), with a reason and error code. Failure diagnostics are not billed as extracted pages. A run in which every attempted PDF fails reports failure; mixed batches preserve their successful pages.
Pricing: pages, not documents
Check the Pricing tab for your effective rate. Basic extraction is billed for each usable page delivered to the default dataset. Unselected, blank and unreadable pages have no page fee. The run start fee still applies. A 100-page PDF can produce 100 billed page rows.
| Apify tier | Basic fee per 1,000 extracted pages |
|---|---|
| Free | $1.25 |
| Starter | $1.15 |
| Scale | $1.05 |
| Business and higher | $1.00 |
The start fee is $0.00005 per GB of allocated memory, with a minimum of one event. A run using 512 MB incurs one start event. Platform usage is included in these published event prices.
At the Free-tier basic rate and default memory, one ten-page PDF costs $0.01255 and 100 ten-page PDFs in one run cost $1.25005, assuming every page is delivered and paid AI cleanup is off. Retries started as separate runs incur another start fee. Rates shown here are Actor fees, excluding any account subscription or taxes.
Local tables, English OCR and chunks have no separate feature event. They can increase runtime, and source or processing limits may reduce what is delivered. Use maxPages and Apify's maximum run cost to control the sample.
Standard AI cleanup adds $0.0222 per successfully enhanced page. Advanced AI cleanup adds $0.04 per successfully enhanced page. Basic page fees still apply. Pages not enhanced do not receive an AI-cleanup fee. Customer API keys are not required; cleanup depends on the Actor's configured provider availability. If cleanup is unavailable, original extraction is retained with a warning.
Use through the Python API
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("thescrapelab/Apify-PDF-url-scraper").call(run_input={"pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],"mode": "no_llm","includeRagChunks": True,# Optional: "pageRange": "1-5,12",})if run is None:raise RuntimeError("No run metadata returned")for page in client.dataset(run["defaultDatasetId"]).iterate_items():print(page["sourceUrl"], page["pageNumber"], page["markdownText"])store = client.key_value_store(run["defaultKeyValueStoreId"])documents = store.get_record("DOCUMENTS")for document in documents["value"]:print(document["status"], document.get("markdownUrl"))
For a local PDF, upload the file to Apify storage first and pass its record URL. Use this in place of the link-based call above:
from pathlib import Pathfrom apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")upload_store = client.key_value_stores().get_or_create(name="pdf-inputs")client.key_value_store(upload_store["id"]).set_record(key="report.pdf", value=Path("report.pdf").read_bytes(),content_type="application/pdf",)run_input = {"pdfFiles": [f"https://api.apify.com/v2/key-value-stores/{upload_store['id']}/records/report.pdf"],"pageRange": "2,5-7","mode": "no_llm",}run = client.actor("thescrapelab/Apify-PDF-url-scraper").call(run_input=run_input)
Use the page dataset for structured exports and integrations. Use the document manifest when an application needs complete Markdown files. Apify can export the dataset as JSON, CSV or Excel; nested tables and chunks are easiest to consume as JSON.
Limits, troubleshooting and support
- Direct HTTP/HTTPS PDF links and PDFs uploaded through Apify are supported. Password-protected and encrypted PDFs are unsupported.
- Local OCR supports English and checks selected pages independently, including documents mixing readable text and scans. The OCR fallback limit applies to pages needing OCR. Inspect diagnostics for unreadable pages, failures or OCR limits.
- Layout, reading order, nested tables, handwriting and mathematical notation can require manual review. AI cleanup can introduce interpretation.
- Large documents, download limits, page caps and spending limits can stop a sample early. Processing fewer pages is preferable when validating a new source.
- For blocked downloads, API clients can use existing
proxyConfiguration,requestHeaders,sessionInitUrlandskipHeadPreflightcontrols. Provider and storage access restrictions still apply. - Existing
pdfUrl, advanced modes and API aliases remain supported. The public Actor URL is unchanged.
If a source fails, check that its URL returns a PDF directly, then open the failure diagnostics and run summary. For help, use the Actor's Issues tab and include the run link, expected page numbers and a public sample where possible. Avoid posting credentials or private document links.