PDF to Text & Markdown Extractor (offline, RAG chunks)
Pricing
from $2.00 / 1,000 pdf extracteds
PDF to Text & Markdown Extractor (offline, RAG chunks)
Extracts plain text, Markdown with headings and lists, per-page text, metadata and RAG-ready chunks from PDFs you link or upload as base64. Runs offline with pdfminer.six: no AI, no third-party API. Respects robots.txt and PDF permissions. Flags scanned pages (no OCR).
Pricing
from $2.00 / 1,000 pdf extracteds
Rating
0.0
(0)
Developer
WrenTools
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 hours ago
Last modified
Categories
Share
Turn PDFs into clean text and Markdown you can feed to a search index, an LLM or a spreadsheet. Give it links to PDF files, or send files inline as base64, and get back for each one: plain text, Markdown with headings and lists inferred from the layout, optional per-page text, optional RAG-ready chunks with page ranges, and the document's metadata.
Everything runs inside the Actor with pdfminer.six (MIT licence). Your files are not sent to any AI model or third-party API, and the result for the same file is the same every time.
Code example, in Python and Node: PDF to Markdown and RAG chunks.
What you get
- Plain text, page by page, with paragraph breaks kept.
- Markdown: the most common font size is the body text; short lines set clearly larger become
#,##and###headings, bullet lines become-items, and words hyphenated across a line break are rejoined. - Per-page text (
includePages), for citing page numbers. - RAG chunks (
chunkSize): Markdown split at paragraph boundaries into pieces of at most that many characters, each withpageStartandpageEnd, with an optional overlap. - Metadata: title, author, subject, keywords, creator, producer, creation and modification dates.
- Scanned-page detection: pages with no text layer are listed in
pagesWithoutText, andlikelyScannedis set when half or more of the pages have none. This Actor does not run OCR: send those pages to Image & Scanned PDF OCR.
Failed files are reported in the dataset with a reason and are not charged: fetch-failed, file-too-large,
not-a-pdf, unreadable-pdf, robots-disallowed, password-required, extraction-not-permitted,
invalid-base64.
Respectful by design
- Only the files you name are downloaded, one request each. The site's robots.txt is read first and obeyed, and downloads from one site are spaced (500 ms by default). No proxy, no browser, no login.
- PDF permissions are honoured. A PDF that needs a password is refused (the Actor takes no password), and so is a PDF whose owner has forbidden copying or extracting its text.
- Only public internet addresses are fetched: a URL or redirect into a private, loopback or link-local network is refused.
Process only documents you have the right to use.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
pdfUrls | array | - | Links to PDF files. |
pdfBase64 | array | - | Inline files: base64 strings, or {"name": "invoice.pdf", "data": "<base64>"}. A data: URL prefix is fine. |
outputFormat | string | both | both, markdown or text. |
includePages | boolean | false | Adds pages: [{"page": 1, "text": "..."}]. |
chunkSize | integer | 0 | Characters per RAG chunk; 0 is off, otherwise at least 200. |
chunkOverlap | integer | 200 | At most half the chunk size. |
maxPagesPerPdf | integer | 500 | Longer files are marked truncated. |
maxFileSizeMb | integer | 50 | Up to 200. |
requestDelayMs | integer | 500 | Pause between downloads from one site. |
Output
One dataset item per PDF, in input order:
{"source": "https://example.com/reports/q3.pdf", "url": "https://example.com/reports/q3.pdf","finalUrl": "https://example.com/reports/q3.pdf", "fileName": "q3.pdf", "status": "ok", "error": null,"pageCount": 3, "pagesExtracted": 3, "truncated": false,"metadata": {"title": "Quarterly Field Report", "author": "Field Team", "creationDate": "2026-10-01T09:00:00"},"pagesWithoutText": [3], "likelyScanned": false, "charCount": 512, "wordCount": 88,"text": "Quarterly Field Report\n\n1. Summary\n\nThe survey covered ...","markdown": "# Quarterly Field Report\n\n## 1. Summary\n\nThe survey covered ...","chunks": [{"index": 0, "text": "# Quarterly Field Report ...", "pageStart": 1, "pageEnd": 1, "charCount": 287}]}
A failed file:
{"source": "https://example.com/locked.pdf", "status": "error","error": {"code": "extraction-not-permitted", "message": "the PDF's owner forbids copying or extracting its text, so it is not extracted"}}
A result too large for one dataset item (over 8 MB) keeps its counts and metadata in the dataset; the text, Markdown,
pages and chunks are stored in the run's key-value store, at fullOutputKey / fullOutputUrl.
Key-value store record SUMMARY: PDFs requested, extracted and failed, pages extracted, and why the run stopped early
if it did.
Pricing
Pay per event, no start fee, and nothing for files that fail:
| Event | Price | Per 1,000 |
|---|---|---|
pdf-processed (one PDF extracted) | $0.002 | $2.00 |
page-extracted (each page of it) | $0.0001 | $0.10 |
A 10-page PDF costs $0.003; a 100-page PDF costs $0.012. When you set a maximum charge for a run, the Actor stops
before a file it cannot pay for, and extracts only the pages the remainder covers (the item is marked truncated).
Limits
- No OCR: scanned pages come back empty and are listed in
pagesWithoutText. - Tables come out as text lines; their cell structure is not rebuilt. Multi-column layouts follow pdfminer's reading order, which is usually but not always right.
- Markdown headings are inferred from font size, so a document that sets headings in body-size bold reads as text.