PDF to Text & Markdown: Extract PDF Content by URL
Pricing
from $1.52 / 1,000 document processed (up to 20 pages)s
PDF to Text & Markdown: Extract PDF Content by URL
PDF text extraction for a list of PDF URLs: extract text or Markdown from PDFs by URL, from a crawl, a Sheet or a CRM export. Rebuilds paragraphs and headings, best-effort tables, for a RAG pipeline, an LLM prompt or Google Sheets, via API or n8n. No OCR: scanned PDFs are flagged, not charged.
Pricing
from $1.52 / 1,000 document processed (up to 20 pages)s
Rating
0.0
(0)
Developer
Adriana Voss
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
3
Monthly active users
6 days ago
Last modified
Categories
Share
Give it a list of PDF URLs and get back clean text or Markdown for each one —
headings and paragraphs rebuilt from the PDF's own font sizes, a best-effort
Markdown table for simple aligned tables, and metadata (title, author, page
count). Built for feeding a RAG pipeline, an LLM prompt, or a row to Google
Sheets — anywhere you'd otherwise hand-copy text out of a PDF. No OCR yet: a
scanned, image-only PDF is flagged (isScanned) and never charged.
Who it's for
Anyone who has a list of PDF URLs — from a web crawl, a Sheet, a CRM export, or a document management system — and needs a plain PDF to Markdown conversion, not a raw byte stream. Common uses: preparing PDFs to embed for RAG or as LLM context, converting a folder of reports from PDF to Markdown for a wiki, or piping extracted text to Google Sheets or Airtable via an integration.
How to use
- In the Apify Console. Open the actor page and click Start — the
pdfUrlsfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~pdf-text-extractor/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"pdfUrls":["https://www.irs.gov/pub/irs-pdf/fw4.pdf"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
Input
{"pdfUrls": ["https://www.irs.gov/pub/irs-pdf/fw4.pdf"]}
One direct PDF URL per line, for a list of PDF URLs from a crawl, a Sheet, or a CRM export. Accepted formats: https://www.irs.gov/pub/irs-pdf/fw4.pdf, https://arxiv.org/pdf/1706.03762.
{"pdfUrls": ["https://www.irs.gov/pub/irs-pdf/fw4.pdf","https://arxiv.org/pdf/1706.03762"],"pages": "","outputFormat": "markdown","includePageBreaks": false}
pdfUrls is one direct PDF URL per line — for a list of PDF URLs from a
crawl, a Sheet, or a CRM export. A URL pasted without its https:// (common
when copied from a spreadsheet cell) is filled in automatically.
pages(optional) — a page range like"1-5", or a single page like"3". Leave empty to extract every page.outputFormat—"markdown"(default) rebuilds#/##/###headings from font sizes and renders any detected table as a best-effort Markdown table;"text"keeps the same paragraphs with no Markdown syntax.includePageBreaks— inserts a marker between each page's content (an invisible<!-- page N -->comment in Markdown,"--- Page N ---"in plain text) so a downstream chunker can split by page.
Output
One row per PDF, for example:
| query | found | status | url | title | author | pageCount | pagesExtracted | outputFormat | content | wordCount | isScanned | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| https://www.irs.gov/pub/irs-pdf/fw4.pdf | true | OK | <title (from pdf metadata)> | <author (from pdf metadata)> | <extracted text/markdown> | <scanned (no text layer)> | 1970-01-01T00:00:00.000Z |
A URL that isn't a PDF, doesn't exist, or is larger than the 50 MB limit
comes back as a row with "found": false and is never charged. A scanned,
image-only PDF (isScanned: true) is also never charged — see "No OCR in
this version" below.
How this works
- Download — up to 50 MB per PDF, streamed with a hard cap so one huge file can't run away with your run's memory or your bill.
- Extract — pdfjs-dist reads the text layer page by page, with each character's font size and position.
- Reconstruct — lines are grouped by vertical position, a two-column
academic layout is detected and read left-column-then-right-column
instead of line-by-line across the gutter, consecutive lines of similar
size are merged into paragraphs, and a line noticeably bigger than body
text becomes a heading (
#/##/###, biggest first). A run of 3+ consecutive lines that each split into well-separated clusters is rendered as a best-effort Markdown table. - No OCR in this version — if a PDF's text layer is almost empty (a
scanned page with no embedded text),
isScannedistrue,contentisnull, and the row is never charged.
This is a best-effort reconstruction, not a layout-perfect one:
- Two-column detection works well for the common single-gutter academic layout. An exotic multi-region magazine layout, or a page where both columns happen to align to the exact same text baseline throughout, can read out of order.
- Table detection requires at least 3 consecutive lines with clearly separated columns. A 1-2 row table, or a table with merged or empty cells in irregular places, may render as plain paragraph text instead.
- Line-wrap dehyphenation (joining a word split across two lines by a hyphen) can't always tell a soft line-break hyphen from a real one in a compound word (e.g. "English-to-German" broken exactly at a hyphen can come out as "Englishto-German"). This is a known limitation of automatic PDF text extraction generally, not specific to this actor.
Pricing
- Document processed (up to 20 pages): $2 per 1,000 PDF documents
- Extra page beyond 20: $0.3 per 1,000 PDF documents
Plus a $0.003 start fee per run. Each event above is billed independently, only when it actually returns data — misses (found:false) are never charged.
One document event covers up to 20 extracted pages; a longer document also
bills one page event for each page beyond 20, so a 200-page report doesn't
cost the same as a 2-page memo. A scanned PDF with no text layer bills
nothing at all, even though it still returns a row telling you so.
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~pdf-text-extractor/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"pdfUrls":["https://www.irs.gov/pub/irs-pdf/fw4.pdf"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~pdf-text-extractor/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"pdfUrls":["https://www.irs.gov/pub/irs-pdf/fw4.pdf"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~pdf-text-extractor/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"pdfUrls":["{{PDF document}}"]}, mapping the row's PDF document into the pdfUrls array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "PDF to Text & Markdown | Apify" — the agent will find and run this actor.
A common pattern: run this actor on a list of PDF URLs, then send each row's
content field to Google Sheets (one row per PDF) as a lightweight PDF-to-
Google-Sheets pipeline, or straight into a RAG pipeline's document loader —
the Markdown output chunks cleanly on its own #/## headings.
Data & privacy
This actor only reads the PDF at the URL you give it. Nothing is stored beyond the run's own dataset; no PDF content is retained after the run ends.
FAQ
Does it do OCR on scanned PDFs? Not in this version. A scanned or
image-only PDF is flagged (isScanned: true) and never charged — no
extracted text is fabricated.
What's the file size limit? 50 MB per PDF. A larger file comes back as a
free BAD_FORMAT miss.
Can I extract just a few pages from a huge PDF? Yes — set pages to a
range like "1-10". Only the requested pages count toward parsing time and
billing (pagesExtracted, not pageCount); the whole file still has to be
downloaded first, since PDF pages aren't independently fetchable over HTTP.