PDF Text Extractor: tables, OCR, Markdown, JSON per page
Pricing
from $0.50 / 1,000 page processed (text layer)s
PDF Text Extractor: tables, OCR, Markdown, JSON per page
Turn PDF URLs into clean data: per-page text, tables as real rows (CSV/Excel-ready, with page numbers and Markdown), document metadata, and OCR for scanned pages with confidence scores. Chain from any dataset of URLs. Pay per page, no per-file fee.
Pricing
from $0.50 / 1,000 page processed (text layer)s
Rating
0.0
(0)
Developer
Brenton Keller
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 hours ago
Last modified
Categories
Share
PDF Text Extractor with Tables & OCR
Turn any list of PDF URLs into clean, structured data: per-page text, tables as real rows (with page numbers, detected headers and a Markdown rendering), document metadata, and OCR for scanned pages with a confidence score. Batch hundreds of files, or chain the actor after a crawler by pointing it at a dataset of URLs. Pure compute: no target website, no proxies, nothing that breaks when a site changes.
Why this one and not the others: most PDF actors give you text only, or tables only, or OCR only. This actor does all three in one run, bills per page with no per-file or per-run fee, and ships tables in a shape you can open in Excel or feed to an LLM without post-processing.
What it does
- Downloads each PDF (size cap, retries, redirects followed) and checks it really is a PDF; HTML login walls and landing pages come back as a clear error row instead of a failed run.
- Extracts text page by page from the PDF text layer (reading order, or layout-preserving with
keepLayout). - Detects tables on every page with pdfplumber: ruled tables first, borderless tables by text alignment as a fallback, with a filter that rejects prose masquerading as a grid. Each table comes with
header,rows,markdown,bbox,row_count,col_count. - Runs OCR (Tesseract) on pages that have no text layer, so scanned PDFs and mixed documents just work. Every OCR page carries
ocr_confidence(0 to 100) so you can route low-confidence pages for review. - Returns metadata: title, author, subject, keywords, creator, producer, created/modified timestamps (ISO 8601), page count, page size and rotation.
- Three output shapes: one row per page, one row per document, or one row per table row (flat, CSV-ready).
- Page ranges (
1-3,7,10-), per-document page caps, encrypted PDFs with a password, and URL lists from another actor's dataset.
Who it's for
- RAG and LLM pipelines: per-page text with page numbers for citations, tables as Markdown so models read them correctly.
- Finance, procurement and research teams: pull the tables out of reports, invoices and filings straight into Excel.
- Document automation (n8n, Make, Zapier, Clay): one HTTP call turns a PDF link into JSON fields.
- Crawler post-processing: crawl a site, collect the PDF links, hand the dataset to this actor.
- AI agents: a single MCP tool that reads any PDF an agent encounters, including scans.
Input examples
A few PDFs, one row per page (default):
{ "startUrls": [{ "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf" }, { "url": "https://arxiv.org/pdf/1706.03762" }] }
Whole document as one row (full text + all tables), first 20 pages only:
{ "startUrls": [{ "url": "https://example.com/annual-report.pdf" }], "outputMode": "documents", "maxPagesPerDocument": 20 }
Only the tables, one row per table row, ready for CSV:
{ "startUrls": [{ "url": "https://example.com/price-list.pdf" }], "outputMode": "tableRows" }
Scanned invoices in German and English at 300 DPI:
{ "startUrls": [{ "url": "https://example.com/scan.pdf" }], "ocr": "auto", "ocrLanguages": "deu+eng", "ocrDpi": 300 }
Chain after a crawler: read PDF URLs from its dataset:
{ "inputDatasetId": "aBcDeFgHiJkLmNoPq", "urlField": "url", "outputMode": "documents" }
Pages 2 to 5 of a password-protected file, layout-preserving text, no tables:
{ "startUrls": [{ "url": "https://example.com/locked.pdf" }], "password": "s3cret", "pageRange": "2-5", "keepLayout": true, "extractTables": false }
Output
pages mode (default): one row per page
{"source_url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf","document_id": "3f1c9a7e2b8d4c05","file_name": "fw9.pdf","file_size_bytes": 171243,"title": "Form W-9 (Rev. March 2024)","author": "SE:W:CAR:MP","created_at": "2024-03-06T14:51:09Z","page_count": 6,"pages_extracted": 6,"page_number": 3,"width_pt": 612.0,"height_pt": 792.0,"text": "Form W-9 (Rev. 3-2024) Page 3\nIF the entity/individual on line 1 is a(n) . . . THEN check the box for . . .\n...","char_count": 7654,"word_count": 1284,"extraction_method": "text","has_text_layer": true,"ocr_confidence": null,"table_count": 1,"tables": [{"table_index": 0,"page_number": 3,"row_count": 4,"col_count": 2,"header": ["IF the entity/individual on line 1 is a(n) . . .", "THEN check the box for . . ."],"rows": [["Corporation", "Corporation."], ["Individual or Sole proprietorship", "Individual/sole proprietor."]],"markdown": "| IF the entity/individual on line 1 is a(n) . . . | THEN check the box for . . . |\n| --- | --- |\n| Corporation | Corporation. |","bbox": [36.0, 75.4, 300.2, 210.9],"strategy": "lines"}],"error": null,"fetched_at": "2026-09-02T05:30:12Z"}
| Field | Description |
|---|---|
source_url, final_url | The URL you gave, and where it redirected to (if it did) |
document_id | Stable short hash of the source URL; use it to group pages back into documents |
file_name, file_size_bytes | From the Content-Disposition header or the URL path |
title, author, subject, keywords, creator, producer | PDF metadata (null when absent) |
created_at, modified_at | PDF dates normalized to ISO 8601 UTC |
page_count, pages_extracted | Pages in the file, and how many this run processed (after pageRange / maxPagesPerDocument) |
page_number, width_pt, height_pt, rotation | 1-based page number and page geometry in points |
text, char_count, word_count | Page text |
extraction_method | text (text layer), ocr (Tesseract), or none (blank page, or OCR disabled on a scanned page) |
has_text_layer | Whether the page had any text objects at all |
ocr_confidence | Mean Tesseract word confidence 0 to 100 on OCR pages; null otherwise |
ocr_error, text_layer_text | Set only when OCR failed on a page, or when OCR replaced a thin text layer (the original is kept here) |
tables, table_count | Tables found on the page (see the table object above). strategy is lines (ruled) or text (alignment) |
error | Null on success. Error rows have page_number: null and carry the reason (HTTP status, not a PDF, password, size cap, damaged file) |
raw_metadata | With includeRaw: the untouched PDF metadata dictionary |
documents mode: one row per PDF
Same document fields, plus text (all pages joined), pages (array of {page_number, text, extraction_method, ocr_confidence, char_count, table_count}), tables (all tables, each with its page_number), text_pages, ocr_pages, empty_pages, and truncated (true if the run's charge limit cut the document short).
tableRows mode: one row per table row
source_url, document_id, file_name, title, page_number, table_index, row_index, col_count, header, cells, and record (a {header: cell} object when a header row was detected). Export to CSV or Excel and every table row is one spreadsheet row. In this mode OCR is skipped and only pages that contain tables are billed.
Export any of these as JSON, CSV, Excel or via the API like any Apify dataset.
Pricing
Pay per page processed. No per-run fee, no per-file fee. Failed downloads and error rows are free.
| Event | Price | When |
|---|---|---|
| Page processed (text layer) | $0.50 per 1,000 pages | Text and tables from the PDF text layer |
| Page processed (OCR) | $6.00 per 1,000 pages | Page had no text layer and was rendered and read with Tesseract |
Examples: a 40-page report costs $0.02. A 6-page form with tables costs $0.003. A 10-page scanned invoice batch of 50 files (500 OCR pages) costs $3.00. A crawler dataset of 1,000 single-page PDF brochures costs $0.50.
Set Maximum total charge on the run to cap spend; the actor stops cleanly at the cap and only pushes the pages it charged for. In tableRows mode, pages without tables are not billed.
Tips
- Speed: text-layer pages take well under a second each; OCR pages take a few seconds at 200 DPI. Use
pageRangeormaxPagesPerDocumenton long documents, and raiseconcurrency(with more memory) for large batches. - Scanned PDFs:
ocr: "auto"(default) only OCRs pages with no usable text layer, so mixed documents are billed at the cheap rate for their text pages. Useocr: "always"when a PDF has a bad embedded text layer (e.g. from a poor OCR pass) and you want a fresh read. - Borderless tables:
tableStrategy: "auto"looks for ruled tables first and falls back to text alignment. If a page shows tables that were missed, try"text"; if prose is being picked up as tables, use"lines". - Forms and multi-column layouts:
keepLayout: truekeeps horizontal positions with spaces so columns stay aligned in the text. - Large files:
maxFileSizeMbdefaults to 50. Raise it (and the run memory) for scanned books. - Chaining: point
inputDatasetIdat the output of any crawler and seturlFieldto the field holding the PDF link (dot paths likefile.urlwork).
Limits and notes
- Tables are detected on the text layer only. OCR pages return text, not tables.
- Table detection is heuristic. Ruled tables are reliable; borderless tables depend on consistent column alignment. LaTeX-style tables with only horizontal rules are often not detected.
- OCR languages installed:
eng,deu,fra,spa,ita,por,nld. Ask on the Issues tab for others. - Password protection: one
passwordapplies to every file in the run. - Remote URL lists (
requestsFromUrl) are not supported yet; useinputDatasetIdor paste the URLs. - Only publicly reachable URLs (or Apify key-value store record URLs) can be fetched. The actor does not log in to anything.
- You are responsible for having the right to process the documents you submit.
Use from an AI agent (MCP)
Every Apify actor is available as a tool through the Apify MCP server. Add it to Claude, Cursor or any MCP client and call this actor with the JSON input above. Suggested pattern: outputMode: "documents" with maxPagesPerDocument set, so the agent gets one object per PDF with the text and every table as Markdown.
Support
Open an issue on the actor page with the run ID and the PDF URL. If a file parses in your PDF viewer but fails here, attach it to the issue and it will be looked at.