PDF Text Extractor with OCR, Tables & Markdown avatar

PDF Text Extractor with OCR, Tables & Markdown

Pricing

from $0.30 / 1,000 text pages

Go to Apify Store
PDF Text Extractor with OCR, Tables & Markdown

PDF Text Extractor with OCR, Tables & Markdown

Extract text, tables and metadata from any PDF, digital or scanned. Built-in OCR in 124 languages reads scanned pages automatically. Get Markdown for AI and RAG, tables as CSV, filled form fields and per-page results. USD 0.30 per 1,000 text pages, USD 3 per 1,000 OCR pages.

Pricing

from $0.30 / 1,000 text pages

Rating

0.0

(0)

Developer

Useful API

Useful API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Get the text out of any PDF: born-digital or scanned, one file or ten thousand. Text pages are read from the PDF's own text layer; scanned pages are read with OCR in 124 languages, automatically. Tables come out as rows and CSV, and every document also comes as Markdown, ready for AI and RAG pipelines.

Images work too (PNG, JPEG, TIFF including multi-page, WebP, GIF, BMP).

Why this one

  • Scans and text PDFs in one run. Each page is checked: pages with a text layer are read directly (fast, exact), pages without one are read with OCR. Mixed files (a typed contract with a scanned signature page) just work.
  • OCR at USD 3 per 1,000 pages. Text pages cost USD 0.30 per 1,000. You pay OCR only for the pages that need it.
  • Tables as data. Tables with drawn cell borders come out as rows, as CSV and as Markdown tables, with their page number and position. Tables ruled only every few rows are split back into one row per line.
  • Filled-in forms. The values typed into fillable PDF forms come out as formFields (name, type, value).
  • Markdown for AI. Headings from font sizes, lists, paragraphs joined back together, tables in place.
  • Hard scans handled. A page scanned sideways or upside down is turned and read again; old book scans with dark edges or grey paper are read with a second, local thresholding pass.
  • Dead links and failed pages are free. A link that does not answer, or a page the engine cannot read, is not billed (as long as it did not hold the run for long). Blank pages are billed as cheap text pages, not OCR pages. Every file and every page says what happened in plain words.
  • One bad file never stops the run. Each file is read in a separate process. A broken, encrypted or huge file gets a clear error in its own row, and the run goes on with the next one.
  • Big files. Up to 5,000 pages and 500 MB per file (long scans need a longer run timeout, see Good to know).
  • Private. Documents are read inside the run with open-source software (PDFium, pdfplumber, Tesseract). Nothing is sent to any OCR or AI service.

What you get

One row per file (or one row per page, if you prefer):

FieldWhat it is
fileName, url, fileType, fileSizeBytes, sha256The file
statusok, partial (some pages failed, or reading stopped early: budget, timeout; the reason is in error) or error
error, errorCodeWhat went wrong, in plain words (password-required, http-error, file-too-large...)
pageCount, pagesRead, pagesOcr, pagesNotRead, tableCountCounts (pagesNotRead includes pages left out on purpose by "Pages to read" or "Max pages per file")
title, author, createdAt, modifiedAtFrom the PDF's metadata
textAll text, in reading order
markdownThe same as Markdown (headings, lists, tables)
tablesEvery table: page, rows (a list of rows of cells), csv, rowCount, columnCount, bbox
formFieldsFilled-in form fields: page, name, type, value (and checked for ticked boxes)
pagesPer page: text, source (text, ocr, blank, empty or error), ocrConfidence, ocrRotated, ocrSeconds, size, notes
notesAnything to know about the file (for example an XFA form)
metadataProducer, creator, PDF version, encryption, tagged PDF, form type, attachments, outline (bookmarks)
billedThe events this file was billed for

Example: the default input (the IRS Form W-9 PDF), shortened:

{
"fileName": "fw9.pdf",
"status": "ok",
"pageCount": 6,
"pagesRead": 6,
"pagesOcr": 0,
"tableCount": 2,
"title": "Form W-9 (Rev. March 2024)",
"createdAt": "2024-03-06T08:18:13-05:00",
"text": "Form W-9\n(Rev. March 2024)\nRequest for Taxpayer\nIdentification Number and Certification\n...",
"tables": [
{ "page": 3, "rowCount": 6, "columnCount": 2,
"rows": [["IF the entity/individual on line 1 is a(n) . . .", "THEN check the box for . . ."],
["• Corporation", "Corporation."]] }
],
"pages": [{ "page": 1, "source": "text", "text": "Form W-9\n(Rev. March 2024)\n..." }],
"billed": { "document": 1, "page": 6 }
}

The run's OUTPUT record sums it up: files read, pages read with and without OCR, errors and events billed.

A document too large for one dataset row (about 9 MB of results, roughly 800 text pages or 300 pages full of tables) comes as one summary row followed by one row per page.

How to use it

Paste PDF or image links, upload a text file of links, or upload the files themselves. Google Drive and Dropbox share links work when the file is shared publicly. For a file already in your own Apify storage, use its shareable link (the record URL with ?signature=...): the Actor runs with limited permissions and cannot open your other storages with a plain link.

Read a batch of PDFs, scans included:

{ "startUrls": [{ "url": "https://example.com/report.pdf" }, { "url": "https://example.com/scan.pdf" }] }

Scanned documents in French and German, one row per page:

{ "startUrls": [{ "url": "https://example.com/scan.pdf" }], "ocrLanguages": ["fra", "deu"], "outputMode": "page" }

Only the first two pages of each file (cheap triage of a big archive):

{ "startUrls": [{ "url": "https://example.com/a.pdf" }], "pageRange": "1-2" }

Also look for tables lined up by spaces only (experimental: finds some tables the default misses, and skips anything that looks like a paragraph):

{ "startUrls": [{ "url": "https://example.com/report.pdf" }], "tables": "text" }

OCR every page (for text inside pictures, or PDFs with a broken text layer; the exact text layer is then replaced by OCR text and every page is billed as an OCR page):

{ "startUrls": [{ "url": "https://example.com/brochure.pdf" }], "ocrMode": "always" }

Input options

OptionDefaultWhat it does
PDF or image URLsLinks to files (or upload a list)
Upload filesFiles from your computer
OCR modeAutoAuto: OCR only pages without text. Always: every page. Never: no OCR
OCR languagesEnglishUp to 3 of 124 languages; the first is the main one
OCR resolution300 DPI400 for very small print (US Legal pages then count as 2 OCR pages), 200 for large print
TablesRuled tablesTables with drawn borders; also tables aligned by spaces (experimental); or off
MarkdownOnAlso return Markdown
Text with the page layout keptOffText placed as on the page (columns side by side)
One row perDocumentOr one row per page
Pages to readAllFor example 1-5, 8, 10-
Max pages per file1,000Up to 5,000
Max file size100 MBUp to 500 MB
PDF passwordFor password-protected PDFs

Pricing

Pay per event, no subscription:

EventPricePer 1,000
Run startUSD 0.00075 per GB of memory: USD 0.003 per run (it always runs at 4 GB)
File read (download, open, metadata; also a file that turns out locked or broken)USD 0.001USD 1 per 1,000 files
Page read from the text layer (text, tables, Markdown)USD 0.0003USD 0.30 per 1,000 pages
Page or image read with OCRUSD 0.003USD 3 per 1,000 pages
Each MB of a file past the first 2 MBUSD 0.0004

Two things make an OCR page count as more than one, because they take longer to read:

  • Chinese, Japanese and Korean: x2.
  • Very large pages (over 16 megapixels as rendered: A3, newspaper and drawing scans, or US Legal at 400 DPI; A4, US Letter and Legal at 300 DPI and A4 or Letter at 400 DPI stay at 1): x2 up to 32 megapixels, x3 above.

Each file's billed field and the run's summary show exactly what was counted.

Examples:

  • One 10-page text PDF in its own run: 0.003 + 0.001 + 10 x 0.0003 = USD 0.007
  • 1,000 ten-page text PDFs in one run (10,000 pages): 0.003 + 1,000 x 0.001 + 10,000 x 0.0003 = USD 4.00
  • One 200-page scanned book in English, 30 MB: 0.003 + 0.001 + 200 x 0.003 + 28 x 0.0004 = USD 0.62
  • Links that do not answer, pages that fail: free (as long as they do not hold the run for long)

Set "Maximum cost per run" on the run and it stops cleanly just before that amount, keeping everything read so far: a file cut short gets a partial row with the pages it read.

Good to know

  • Accuracy. Text-layer pages are exact (what the PDF contains). OCR is Tesseract 5 (LSTM models): very good on clean print, weaker on handwriting, low-quality photos and decorative fonts. Each OCR page has a confidence score (0 to 100) so you can flag pages to check.
  • Reading order follows the PDF's own order, which is right for papers, reports and most documents. For forms and tables, switch on "Text with the page layout kept" (on very tightly set text it can run words together).
  • Tables are found on pages with a text layer and drawn cell borders. Tables without borders, tables on rotated pages and tables on scanned pages come out as text, not as rows.
  • Which pages get OCR (auto mode): pages with (almost) no text layer and a picture on them, pages whose text layer is unreadable, and pages that are one full-page picture with only a stamp or header on top (fewer than 200 characters).
  • Vertical Chinese, Japanese or Korean (old books and newspapers): pick the "vertical" language models (chi_tra_vert, jpn_vert...); the normal models read vertical print poorly and slowly.
  • Not read: handwriting recognition is not offered; XFA forms show only what PDF readers without a form engine show (often a "Please wait" page; filled-in values still come out in formFields); encrypted PDFs need their password.
  • Long runs: the run stops starting new pages shortly before its timeout and saves what it read (the file in progress gets a partial row). For long scans, raise the run timeout.
  • Limits per page: each page has a time limit. A very dense or noisy page (old newspapers, complex drawings) can reach it: OCR then returns the text read so far with ocrTimedOut: true, and a text page that runs over is skipped with a note, instead of holding the whole run.
  • Low-resolution scans are read at up to twice their own resolution (never blown up to 300 DPI), which is faster and reads just as well.

Use it from code

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("usefulapi/pdf-text-ocr").call(run_input={
"startUrls": [{"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf"}],
})
for doc in client.dataset(run["defaultDatasetId"]).iterate_items():
print(doc["fileName"], doc["status"], len(doc.get("text") or ""))

Licences

Built on open-source software: PDFium through pypdfium2 (BSD-3-Clause / Apache-2.0), pdfplumber and pdfminer.six (MIT), Tesseract 5 (Apache-2.0) through tesserocr (MIT), Tesseract language models from tessdata_fast (Apache-2.0), Pillow (MIT-CMU), httpx (BSD-3-Clause).

Questions and problems

Open an issue in the Issues tab with the link to the file (if it is public) and what you expected.