PDF to Markdown and Text: Tables, Pages, Metadata for RAG avatar

PDF to Markdown and Text: Tables, Pages, Metadata for RAG

Pricing

from $1.60 / 1,000 pdf extracteds

Go to Apify Store
PDF to Markdown and Text: Tables, Pages, Metadata for RAG

PDF to Markdown and Text: Tables, Pages, Metadata for RAG

PDF parser and text extractor: turn PDF URLs into clean Markdown, plain text, per-page text and detected tables. Fast, no browser, no proxy. Flags scanned pages that need OCR instead of charging for empty text. Built for RAG and document pipelines. USD 2 per 1,000 PDFs (up to 100 pages each).

Pricing

from $1.60 / 1,000 pdf extracteds

Rating

0.0

(0)

Developer

JT Palms

JT Palms

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 days ago

Last modified

Share

Give it PDF URLs, get one row per PDF with clean Markdown, plain text, optional per-page text and detected tables, plus metadata and an honest flag for pages that are scanned images. It runs on pure JavaScript: no browser, no proxy, no LLM, no OCR. Reading takes roughly 10 to 60 milliseconds per page depending on the machine.

USD 2 per 1,000 PDFs (up to 100 pages each), plus a tiny start fee per run. Failed downloads, non-PDF answers and PDFs without a text layer are free.

What people use it for

  • RAG and document pipelines. Reports, manuals, policies and filings become Markdown with real headings, paragraphs and lists, ready to chunk and embed. Turn on outputPages to chunk by page, and keep headings and title as chunk metadata.
  • Filings and statistics. Regulator and statistics-agency PDFs often hold their numbers in tables. With outputTables on, each table comes back as row arrays (for code) and as a Markdown table (for LLMs), with a confidence rating.
  • Tender and procurement documents. Pair it with Government Tenders Monitor: that actor returns documentsUrl and noticeUrl for each notice, and when those links point straight at a PDF, this actor turns the document into text you can search or summarise. Schedule both.
  • Price lists and supplier documents. Pull the text and tables out of a supplier's PDF price list every week and compare.
  • An agent tool. "Read this PDF" as one cheap, deterministic call that returns structured JSON.

Sample output

Real run on the IRS Form W-9 (https://www.irs.gov/pub/irs-pdf/fw9.pdf), default settings, markdown shortened:

{
"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
"finalUrl": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
"httpStatus": 200,
"contentType": "application/pdf",
"fileSizeBytes": 140815,
"pageCount": 6,
"pagesProcessed": 6,
"title": "Form W-9 (Rev. March 2024)",
"titleSource": "metadata",
"subject": "Request for Taxpayer Identification Number and Certification",
"keywords": "Fillable",
"creatorTool": "Designer 6.5",
"producer": "Designer 6.5",
"createdAt": "2024-03-06T13:18:13.000Z",
"modifiedAt": "2024-03-06T13:18:13.000Z",
"language": "en-US",
"isEncrypted": false,
"markdown": "Form W-9\n\n# Request for Taxpayer Identification Number and Certification\n\n...",
"wordCount": 6237,
"charCount": 37706,
"headings": [
{ "level": 1, "text": "Request for Taxpayer Identification Number and Certification", "page": 1 },
{ "level": 3, "text": "Part I Taxpayer Identification Number (TIN)", "page": 1 }
],
"links": [],
"ocrNeededPages": [],
"truncated": false,
"notes": [
"4 text item(s) at an angle (watermarks, side stamps) were left out.",
"11 repeated header, footer or page-number line(s) removed."
],
"error": null,
"errorCode": null,
"fetchedAt": "2026-10-06T19:27:29.851Z"
}

A table from the same run mode with outputTables on (Table A-8 of a Bureau of Labor Statistics release, first rows, as it appears in the Markdown):

| Category | Sept. | Aug. | Sept. | Sept. | May | June | July | Aug. | Sept. |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | 2025 | 2026 | 2026 | 2025 | 2026 | 2026 | 2026 | 2026 | 2026 |
| CLASS OF WORKER | | | | | | | | | |
| Agriculture and related industries | 2,209 | 2,551 | 2,636 | 2,206 | 2,261 | 2,291 | 2,216 | 2,444 | 2,596 |
| Wage and salary workers1 | 1,533 | 1,735 | 1,937 | 1,518 | 1,648 | 1,595 | 1,508 | 1,630 | 1,832 |

In the dataset the same table is tables[]: { "page": 2, "columns": 10, "rowCount": 26, "confidence": "high", "rows": [["Category", "Sept.", ...], ...] }. Dot leaders ("Revenue . . . . 1,200") are removed and the value after them is its own cell.

Input

FieldWhat it does
urlsPDF links, one per line (public http or https). Duplicates are read once. The default list is three small public PDFs from US government sites.
outputFormatmarkdown (default), text, or both.
outputPagesAdd pages[]: for every page read, its text (and Markdown unless the format is text), character count and needsOcr.
outputTablesDetect tables and add tables[] and pipe tables in the Markdown.
removeHeadersFootersOn by default. Drops repeated page headers and footers (text that repeats on more than 60% of the pages, also when odd and even pages differ) and bare page numbers. Needs 3 or more pages to spot repeats.
pageRangeFor example 1-5,9 or 10-. The same range is applied to every PDF. Empty reads everything up to maxPages.
maxPagesPages read per PDF: default 300, up to 2,000 (the prefill is 50). More pages than that set truncated: true.
maxFileMbLarger files are skipped and not charged. Default 50, up to 200.
passwordFor encrypted PDFs you are entitled to open. Used only to open the file, never output.
includeAuthorOff by default. Adds author, the PDF's Author field (which can be a person's name).
maxConcurrencyPDFs in parallel, 1 to 10 (default 4). Requests to one site are still at least one second apart.
timeoutSecsPer file: time to download it, and again to read it. At the limit you get the pages read so far with truncated: true.

Output fields

FieldMeaning
url, finalUrl, httpStatus, contentType, fileSizeBytesThe request and the answer.
pageCount, pagesProcessedPages in the PDF, and pages read.
title, titleSourceThe PDF's Title metadata (metadata). If it is missing or looks like a file name ("Microsoft Word - report.docx"), the first top-level heading is used (heading).
subject, keywords, creatorTool, producer, createdAt, modifiedAt, languagePDF metadata, or null. Dates are ISO 8601.
authorOnly with includeAuthor.
isEncryptedThe file is encrypted (some files are marked encrypted but open without a password, as in any PDF viewer).
markdown, textThe document, as requested by outputFormat.
wordCount, charCountSize of the extracted text.
headings[{ level, text, page }].
linksWeb links (http and https) found in the PDF's link annotations. Email and phone links are not output.
pagesWith outputPages.
tablesWith outputTables: [{ page, columns, rowCount, confidence, rows }].
ocrNeededPagesPages with almost no text (under 20 characters) that contain images: scans.
truncatedtrue when pages were left unread: maxPages, the time limit, or your maximum cost per run.
notesPlain-language remarks (pages cut, lines removed, scanned pages).
error, errorCodeWhy a row has no content, otherwise null. See below.
fetchedAtWhen the file was fetched.

The run's key-value store has a SUMMARY record with counts (rows, failures by code, PDFs without text, billed PDFs and extra pages) and request statistics.

Errors are rows, not crashes

errorerrorCodeCharged
not a PDF (an HTML page that answers 200, an empty body)NOT_PDFno
HTTP 404 and other HTTP errors, HTTP 403 (access denied), HTTP 429 (rate limited)HTTP_ERROR, ACCESS_DENIED, RATE_LIMITEDno
blocked by robots.txt, or robots.txt could not be readROBOTS_BLOCKED, ROBOTS_UNREADABLEno
file too large (...)TOO_LARGEno
password required, wrong passwordPASSWORD_REQUIRED, WRONG_PASSWORDno
no text found: the pages are scanned images and need OCR... or no extractable textNO_TEXTno
could not parse PDF: ...PARSE_FAILEDno
pageRange selects no pages (the PDF has N)BAD_PAGE_RANGEno
timeout after N s, domain not found, TLS error, connection refused, private or internal address, not allowed, bad redirectsTIMEOUT, DNS, TLS, CONNECTION_REFUSED, PRIVATE_ADDRESS, BAD_REDIRECT, FETCH_FAILED (and INTERNAL for anything unexpected)no
invalid URL, unsupported URL: only http and https are readINVALID_URLno

Scanned PDFs

This actor does not do OCR. A page with fewer than 20 characters of text that contains images is listed in ocrNeededPages (and has needsOcr: true in pages[]). A PDF is charged only when at least one page has 20 or more characters of text, so a pure scan is free and a mixed document is charged once, with its scanned pages flagged. Run OCR on the flagged pages with a tool of your choice.

What it does not do

  • No OCR (v1). Scanned pages come back empty and flagged, never guessed.
  • No form field values, no images, no figures. Only the page text. Text inside charts and figures is read as it is stored and can look odd.
  • Tables are a heuristic. Rows of text that line up in 3 or more columns become a table. Simple tables work well (the sample above is 10 columns by 26 rows, confidence: "high"), complex layouts with merged cells or wrapped cell text may not. confidence is high, medium or low: low means ragged columns, so check the result. Tables that continue over a page break are returned as one table per page.
  • Headings come from font size. Lines noticeably larger than the document's body text become headings (levels 1 to 4, largest first). A heading in bold at body size stays a paragraph, and a bold run-in heading is not split from its paragraph.
  • Complex layouts can read out of order. Pages with 2 to 4 plain text columns are read column by column; pages that mix boxes, sidebars, forms and columns (a fillable form is the usual example) may come out in a different order than a person would read them.
  • Hyphens at line ends. A hyphen at the end of a line followed by a lower-case letter is treated as hyphenation and removed ("interna-" and "tional" become "international"). A real compound broken over two lines ("English-" and "to-German") loses its hyphen. A hyphen followed by a capital or a digit is kept ("COVID-" and "19" become "COVID-19").
  • Rotated text. A page drawn sideways is turned upright. Text at other angles (watermarks, side stamps) is left out and noted.
  • Fonts without a text mapping. Some PDFs store text in fonts with no Unicode mapping; their text comes out as odd characters or as nothing, exactly as copy and paste from a viewer would.

Pricing

WhatPrice
One PDF with extracted text (up to 100 pages read)USD 0.002 (USD 2 per 1,000)
Each page read beyond 100 in one PDFUSD 0.0001
Run startUSD 0.001 per run
Failed downloads, non-PDF answers, errors, PDFs with no text layerFree

Worked examples on the free plan:

  • The default input (3 small PDFs): 3 x 0.002 + 0.001 = USD 0.007.
  • 1,000 PDFs of 20 pages: USD 2.00 (+ the start fee).
  • One 300-page report: 0.002 + 200 x 0.0001 = USD 0.022.
  • 10,000 PDFs of which 800 fail or are scans: 9,200 x 0.002 = USD 18.40.

Higher Apify plans get a discount (10% on Silver, 20% on Gold and above). You can set a maximum cost per run: the actor reads no more PDFs than that budget can pay for, reads fewer pages of a long PDF when the extra pages would not fit (the row says truncated: true), stops cleanly and keeps every row already written.

Speed and limits

  • Reading time is about 10 milliseconds per page on a laptop and roughly 50 milliseconds per page on the default 1 GB platform container (a 120-page, three-column IRS publication takes about 7 seconds there, a 6-page form well under a second), plus download time. The default three-PDF run finishes in about 4 seconds.
  • Requests to one website are at least one second apart, so a list of 1,000 PDFs that are all on the same site takes at least 17 minutes however many you read in parallel. Lists spread over many sites run in parallel.
  • Memory: the default is 1 GB. Several large files are held in memory at once, so with a large maxFileMb fewer PDFs are read in parallel. A row must fit in one Apify dataset item (under 9 MB): a row that would be larger loses pages[] first and then has its text cut at a paragraph, with a note.

Schedule it

Save your list as a task and schedule it: new filings, price lists or tender documents on the same URLs are read again on every run. Combine it with Government Tenders Monitor (daily bid alerts with links to documents) or RSS Feed Reader and Monitor (feeds that link to PDF reports): feed the document links into the urls field of this actor.

Rights, robots.txt and privacy

  • You are responsible for having the right to process a document. This actor reads files at addresses you supply. It does not crawl, log in, get past paywalls or bot protection, or use proxies.
  • robots.txt is respected for the host of every file (cached per site, also after redirects). A site that disallows automated access gets a blocked by robots.txt row. If robots.txt cannot be read at all (a server error), the file is skipped with a clear reason instead of being fetched blind.
  • The User-Agent is Mozilla/5.0 (compatible; pdf-to-markdown/1.0; +https://apify.com/JTPalms). Requests to one host are at least one second apart, and transient errors are retried twice with back-off.
  • Private and internal addresses (localhost, 10.x, 192.168.x and similar) are refused.
  • Author names are dropped by default. The PDF Author field can be a person's name, so it is output only with includeAuthor. The actor returns what the document itself contains and nothing else: no enrichment, no lookups. Email and phone links in annotations are not listed in links.
  • A password you give is used to open that file only. It is not written to the dataset, the summary or the log.
  • Encrypted files that need a password are read only with the password you provide; the actor never tries to guess or remove passwords.

FAQ

Why was my PDF not charged? Failed downloads, non-PDF answers, files over the size limit, password problems and PDFs without any text layer are free. The row explains why in error.

Can it read scanned PDFs? Not in this version. It tells you which pages need OCR and does not charge for empty text.

How do I get text per page? Set outputPages to true. pages[] has one entry per page read with its text and Markdown.

Can I read only part of a long PDF? Yes: pageRange (for example 1-20) or maxPages. Pages beyond 100 cost USD 0.0001 each, so a range keeps the price down.

A table came out wrong. Check confidence. Table detection is a heuristic; open an issue on the actor page with the PDF URL and the page number.