PDF Text Extractor: tables, OCR, Markdown, JSON per page avatar

PDF Text Extractor: tables, OCR, Markdown, JSON per page

Pricing

from $0.50 / 1,000 page processed (text layer)s

Go to Apify Store
PDF Text Extractor: tables, OCR, Markdown, JSON per page

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

Brenton Keller

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 hours ago

Last modified

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"
}
FieldDescription
source_url, final_urlThe URL you gave, and where it redirected to (if it did)
document_idStable short hash of the source URL; use it to group pages back into documents
file_name, file_size_bytesFrom the Content-Disposition header or the URL path
title, author, subject, keywords, creator, producerPDF metadata (null when absent)
created_at, modified_atPDF dates normalized to ISO 8601 UTC
page_count, pages_extractedPages in the file, and how many this run processed (after pageRange / maxPagesPerDocument)
page_number, width_pt, height_pt, rotation1-based page number and page geometry in points
text, char_count, word_countPage text
extraction_methodtext (text layer), ocr (Tesseract), or none (blank page, or OCR disabled on a scanned page)
has_text_layerWhether the page had any text objects at all
ocr_confidenceMean Tesseract word confidence 0 to 100 on OCR pages; null otherwise
ocr_error, text_layer_textSet only when OCR failed on a page, or when OCR replaced a thin text layer (the original is kept here)
tables, table_countTables found on the page (see the table object above). strategy is lines (ruled) or text (alignment)
errorNull on success. Error rows have page_number: null and carry the reason (HTTP status, not a PDF, password, size cap, damaged file)
raw_metadataWith 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.

EventPriceWhen
Page processed (text layer)$0.50 per 1,000 pagesText and tables from the PDF text layer
Page processed (OCR)$6.00 per 1,000 pagesPage 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 pageRange or maxPagesPerDocument on long documents, and raise concurrency (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. Use ocr: "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: true keeps horizontal positions with spaces so columns stay aligned in the text.
  • Large files: maxFileSizeMb defaults to 50. Raise it (and the run memory) for scanned books.
  • Chaining: point inputDatasetId at the output of any crawler and set urlField to the field holding the PDF link (dot paths like file.url work).

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 password applies to every file in the run.
  • Remote URL lists (requestsFromUrl) are not supported yet; use inputDatasetId or 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.