PDF Text Extractor with OCR, Tables & Markdown
Pricing
from $0.30 / 1,000 text pages
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
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):
| Field | What it is |
|---|---|
fileName, url, fileType, fileSizeBytes, sha256 | The file |
status | ok, partial (some pages failed, or reading stopped early: budget, timeout; the reason is in error) or error |
error, errorCode | What went wrong, in plain words (password-required, http-error, file-too-large...) |
pageCount, pagesRead, pagesOcr, pagesNotRead, tableCount | Counts (pagesNotRead includes pages left out on purpose by "Pages to read" or "Max pages per file") |
title, author, createdAt, modifiedAt | From the PDF's metadata |
text | All text, in reading order |
markdown | The same as Markdown (headings, lists, tables) |
tables | Every table: page, rows (a list of rows of cells), csv, rowCount, columnCount, bbox |
formFields | Filled-in form fields: page, name, type, value (and checked for ticked boxes) |
pages | Per page: text, source (text, ocr, blank, empty or error), ocrConfidence, ocrRotated, ocrSeconds, size, notes |
notes | Anything to know about the file (for example an XFA form) |
metadata | Producer, creator, PDF version, encryption, tagged PDF, form type, attachments, outline (bookmarks) |
billed | The 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
| Option | Default | What it does |
|---|---|---|
| PDF or image URLs | Links to files (or upload a list) | |
| Upload files | Files from your computer | |
| OCR mode | Auto | Auto: OCR only pages without text. Always: every page. Never: no OCR |
| OCR languages | English | Up to 3 of 124 languages; the first is the main one |
| OCR resolution | 300 DPI | 400 for very small print (US Legal pages then count as 2 OCR pages), 200 for large print |
| Tables | Ruled tables | Tables with drawn borders; also tables aligned by spaces (experimental); or off |
| Markdown | On | Also return Markdown |
| Text with the page layout kept | Off | Text placed as on the page (columns side by side) |
| One row per | Document | Or one row per page |
| Pages to read | All | For example 1-5, 8, 10- |
| Max pages per file | 1,000 | Up to 5,000 |
| Max file size | 100 MB | Up to 500 MB |
| PDF password | For password-protected PDFs |
Pricing
Pay per event, no subscription:
| Event | Price | Per 1,000 |
|---|---|---|
| Run start | USD 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.001 | USD 1 per 1,000 files |
| Page read from the text layer (text, tables, Markdown) | USD 0.0003 | USD 0.30 per 1,000 pages |
| Page or image read with OCR | USD 0.003 | USD 3 per 1,000 pages |
| Each MB of a file past the first 2 MB | USD 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
partialrow). 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 ApifyClientclient = 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.