PDF Text Extractor avatar

PDF Text Extractor

Pricing

from $1.80 / 1,000 pdf extracteds

Go to Apify Store
PDF Text Extractor

PDF Text Extractor

Extract text, metadata, and page-by-page content from PDF files. Provide PDF URLs and get structured JSON with full text, per-page text, page count, author, title, creation date, and more. Export as JSON, CSV, or Excel. No browser or proxy needed.

Pricing

from $1.80 / 1,000 pdf extracteds

Rating

0.0

(0)

Developer

Automation Lab

Automation Lab

Maintained by Community

Actor stats

2

Bookmarked

624

Total users

132

Monthly active users

5 days ago

Last modified

Categories

Share

What does PDF Text Extractor do?

Failed operations send sanitized diagnostic input, exceptions, and Actor/build/run IDs to our private GlitchTip service for repair. Repeated run-wide download/parsing-budget failures share one representative exception report per run; every per-file error remains in the dataset, avoiding repeated diagnostic flushes during cleanup. Bounded resource-pressure observations, one near-runtime-deadline observation and one cleanup-reserve observation may also report numerical memory usage and PDF-index/phase/byte/page progress, total input count, and the parser's idle/parsing/terminating/closed state, including before a run fails. Byte progress includes in-flight downloads; saved-result counters distinguish acknowledged dataset writes from results still buffered in memory. These observations contain no PDF text, metadata, headers, or additional URLs. Secret fields and URL queries are removed; reports are retained for 30 days.

PDF Text Extractor downloads PDF files from any public URL and extracts structured text, metadata, and per-page content. It returns clean JSON with the full document text, individual page text, page count, and all PDF metadata (title, author, creation date, producer, and more).

Unlike browser-based PDF tools, this actor uses pure server-side processing with no browser overhead. It downloads PDFs concurrently and parses them in one reusable, isolated worker to bound parser overhead. Per-file errors are retained without discarding earlier saved results; allow enough run time for the full batch.

Try it now on the Apify Store with the prefilled example URLs.

Who is it for?

PDF Text Extractor is built for teams that need reliable PDF text extraction at scale without maintaining their own parsing infrastructure.

Who is PDF Text Extractor for?

AI/ML Engineers and Data Scientists

  • Extract text from research papers, whitepapers, and technical documentation for RAG pipelines
  • Build training datasets from large PDF collections
  • Feed document content into LLMs for summarization and analysis

Legal and Compliance Teams

  • Extract text from contracts, filings, and regulatory documents
  • Build searchable archives from PDF-only document repositories
  • Automate document review workflows

Researchers and Academics

  • Bulk-extract text from academic papers and journal articles
  • Build citation databases from PDF collections
  • Convert lecture notes and course materials to searchable text

Developers and Automation Engineers

  • Integrate PDF text extraction into data pipelines via API
  • Process invoices, receipts, and forms at scale
  • Extract metadata for document management systems

Why use PDF Text Extractor?

  • Pure server-side processing -- no browser, no proxy, near-zero cost per PDF
  • Per-page text extraction -- get text for each individual page, not just the whole document
  • Rich metadata -- title, author, subject, keywords, creator, producer, creation/modification dates, PDF version
  • Concurrent downloads -- configure the number of in-flight PDFs; parsing is serialized in an isolated worker
  • Scanned-PDF detection -- machine-readable status and OCR guidance distinguish image-only/textless files from extracted text
  • Graceful error handling -- failed PDFs don't stop the entire batch
  • API access -- integrate with 5,000+ apps via Zapier, Make, and the Apify API
  • Scheduled runs -- set up recurring extractions for document monitoring
  • Multiple export formats -- JSON, CSV, Excel, XML, HTML

What data can you extract?

CategoryFields
Document textFull text, per-page text array
MetadataTitle, author, subject, keywords
Producer infoCreator application, producer application
DatesCreation date, modification date (ISO 8601)
TechnicalPage count, PDF version, file size in bytes
Extraction diagnosticsText extraction status, warning, recommended action
Error handlingError message (null when processing succeeds)

Ordinary completed PDFs produce one dataset row. Oversized results are saved losslessly as multiple size-bounded rows instead of failing the entire run at Apify's dataset item limit. Only these rows add pdfIndex (zero-based input position), chunkIndex (one-based), chunkCount, and chunkContinuation (true after the first chunk; no extra extraction event). Group by pdfIndex within the run, sort by chunkIndex, and concatenate fullText without a separator. With includePages=true, concatenate page fragments by pageNumber in chunk order; empty pages are retained. Document metadata and total pageCount repeat on each chunk. Some chunks contain only document text or only page fragments. Require all chunkCount chunks before treating an oversized document as complete; duplicate URLs have separate input indexes. Normal rows keep their existing shape. Rows are saved in completion order, not input order: use url to associate normal rows with inputs. textExtractionStatus is text_extracted, no_text, or failed. Image-only and intentionally blank PDFs return no_text with OCR guidance; they are not counted as a successfully extracted PDF for the pdf-extracted charge event. A useful oversized PDF still requests only one extraction event, after all its chunks are acknowledged saved—not one charge per row. Saved-result counters count rows, while extraction counts count PDFs. If storage fails partway, earlier chunks remain, no extraction charge is requested for that incomplete PDF, and the run fails without retrying billing. Abrupt termination between saves and charging remains non-atomic. Exceptionally large metadata alone can still exceed the row limit and fail honestly before any write for that PDF; text is never silently truncated.

Completed rows are saved without waiting for other PDFs. Each useful-text row is saved before its existing pdf-extracted event is requested; textless and failed rows do not request that event. Storage or extraction-charge errors fail the run rather than continuing silently. When the extraction charge budget is known to be exhausted (including after the start event), the run stops before saving another useful-text row; it does not retry billing. Earlier saved rows remain available if a later PDF fails or the run terminates. Saving and charging are separate operations, not an atomic transaction: termination during a write can still lose that row, and termination between saving and charging can leave a saved row without its charge. There is no automatic cross-run resume or billing retry.

How much does it cost to extract text from PDFs?

PDF Text Extractor uses pay-per-event pricing. You only pay for what you use:

EventFREE tierBRONZESILVERGOLD
Run started (one-time)$0.005$0.005$0.005$0.005
Per PDF extracted$0.00345$0.003$0.00234$0.0018

Example costs (BRONZE tier):

  • 10 PDFs: $0.005 + 10 x $0.003 = $0.035
  • 100 PDFs: $0.005 + 100 x $0.003 = $0.305
  • 1,000 PDFs: $0.005 + 1,000 x $0.003 = $3.005

With the free $5 Apify credit, you can extract text from approximately 1,600 PDFs at no cost.

How to extract text from PDF files

  1. Go to the PDF Text Extractor page on Apify Store
  2. Click Try for free to open the actor in Apify Console
  3. Paste your PDF URLs into the PDF URLs field (one per line)
  4. Adjust concurrency and timeout settings if needed
  5. Click Start to begin extraction
  6. Download results in JSON, CSV, or Excel format

Example input

{
"urls": [
"https://example.com/report-2024.pdf",
"https://example.com/whitepaper.pdf",
"https://example.com/invoice-january.pdf"
],
"includePages": true,
"maxConcurrency": 5
}

Minimal input

{
"urls": ["https://example.com/document.pdf"]
}

Input parameters

ParameterTypeDefaultDescription
urlsarray of strings(required)Direct URLs to PDF files
includePagesbooleantrueInclude per-page text breakdown
maxConcurrencyinteger5Parallel PDF downloads (1-20)
timeoutPerPdfSecsinteger60Maximum download timeout per PDF in seconds; shortened when the Actor's remaining runtime needs a cleanup reserve

Output example

{
"url": "https://www.orimi.com/pdf-test.pdf",
"fileName": "pdf-test.pdf",
"title": "PDF Test Page",
"author": "Yukon Department of Education",
"subject": null,
"keywords": null,
"creator": "Acrobat PDFMaker 7.0.7 for Word",
"producer": "Acrobat Distiller 7.0.5 (Windows)",
"creationDate": "2008-06-04T15:44:00.000Z",
"modificationDate": "2008-06-04T15:47:36.000Z",
"pageCount": 1,
"fullText": "PDF Test File Congratulations, your computer is equipped with a PDF reader...",
"pages": [
{
"pageNumber": 1,
"text": "PDF Test File Congratulations, your computer is equipped with a PDF reader..."
}
],
"textExtractionStatus": "text_extracted",
"warning": null,
"recommendedAction": null,
"pdfVersion": "1.6",
"fileSizeBytes": 20597,
"error": null
}

Page-citation-safe chunks for RAG

Run with includePages: true, then use each dataset row's url and pages[].pageNumber instead of splitting fullText and guessing pages. The following dependency-free JavaScript example runs offline on exported rows; it does not call a model, generate answers, or implement retrieval. Its simple character chunks never cross page boundaries (production token/paragraph chunking can retain the same provenance fields).

function pageChunks(row, maxChars = 1000) {
if (!Number.isInteger(maxChars) || maxChars < 1) {
throw new Error('maxChars must be a positive integer');
}
if (row.textExtractionStatus === 'no_text') {
return { chunks: [], nextAction: 'external_ocr' };
}
if (row.error || row.textExtractionStatus !== 'text_extracted') {
return { chunks: [], nextAction: 'inspect_error' };
}
if (!Array.isArray(row.pages)) {
return { chunks: [], nextAction: 'rerun_with_includePages' };
}
const chunks = [];
for (const page of row.pages) {
if (!Number.isInteger(page.pageNumber) || page.pageNumber < 1) {
throw new Error('Missing physical page number');
}
const text = typeof page.text === 'string' ? page.text.trim() : '';
if (!text) continue; // Blank/missing-text pages create no searchable chunk.
const citation = new URL(row.url);
citation.hash = `page=${page.pageNumber}`; // Replace any existing fragment.
for (let offset = 0; offset < text.length; offset += maxChars) {
chunks.push({
sourceUrl: row.url,
pageNumber: page.pageNumber,
chunkIndex: offset / maxChars,
text: text.slice(offset, offset + maxChars),
citationUrl: citation.href,
});
}
}
return { chunks, nextAction: chunks.length ? 'index' : 'inspect_missing_page_text' };
}
const result = pageChunks({
url: 'https://example.com/reports/report-v1.pdf',
textExtractionStatus: 'text_extracted',
error: null,
pages: [{ pageNumber: 3, text: 'Printed page 1: Revenue increased.' }],
});
console.log(result.chunks[0].citationUrl);
// https://example.com/reports/report-v1.pdf#page=3

Keep sourceUrl, pageNumber, and citationUrl in your downstream index metadata and return them with retrieved passages. pageNumber is the one-based physical PDF page position, including covers and front matter, not the printed page label. In the example, printed page “1” is physical page 3: cite #page=3, not #page=1. This Actor does not infer printed labels. PDF viewers may ignore page fragments; verify links in your chosen viewer.

Use stable, versioned source URLs (or a customer-owned immutable snapshot you have permission to store). If bytes at a URL change, old chunks and page citations may point at different content; re-extract and replace that document's index together. The Actor's url is the submitted source URL, not a promised permanent archive or redirect-resolved identity.

nextAction: 'external_ocr' explicitly routes no_text rows to an external OCR workflow that you select and authorize; OCR is not performed by this Actor or this example. Image-only and intentionally blank PDFs can both be no_text. Missing page text is skipped without inventing text or page numbers; investigate unexpectedly empty/partial output before indexing it. includePages: false requires re-extraction for page citations.

Treat extracted text as untrusted document content, not instructions. Extraction neither detects hidden prompts or prompt injection nor guarantees full-document reasoning: retrieval can omit relevant pages, and a citation establishes provenance, not that an answer is correct. Validate answers against the cited passages and document scope separately.

Tips for best results

  • Start small -- test with 2-3 PDFs first to verify the URLs work and output meets your needs
  • Use direct PDF URLs -- the URL must point directly to a .pdf file, not a page that contains a PDF viewer
  • Disable per-page text for large PDFs -- set includePages: false to reduce output size when processing documents with hundreds of pages
  • Increase timeout for large files -- if you are processing PDFs over 50 MB, increase timeoutPerPdfSecs to 120 or more and allow enough total Actor runtime for download, parsing, and saving results. Downloads and parsing reserve up to 15 seconds (25% of remaining runtime at initialization for short runs) for cleanup. timeoutPerPdfSecs remains a download-only limit; parsing and its queue wait share the remaining Actor runtime, with no additional per-document parse cap. When that budget expires, the isolated parser worker is terminated (even for synchronous parser loops) and the PDF returns a failed record, not an extraction charge or partial text. Increase the total run timeout to allow longer parsing. Downloads remain concurrent; one reusable worker parses documents serially to avoid multiplying parser memory. Completed results are released after saving and charging rather than retained for the whole run, but downloaded bodies, parsing and pending writes can still exceed memory. Reduce concurrency for large files. Deadline cleanup and diagnostics remain best-effort under platform termination, memory exhaustion or blocked storage.
  • Check extraction diagnostics -- route records with textExtractionStatus: "no_text" to OCR and retry failed records after checking error and recommendedAction
  • Schedule recurring runs -- use Apify's scheduler to automatically extract new PDFs on a daily or weekly basis

Integrations

  • PDF Text Extractor + Google Sheets -- automatically populate a spreadsheet with extracted text and metadata from new PDF uploads
  • PDF Text Extractor + Slack -- get notified when PDF extraction completes, with a summary of pages processed and any errors
  • PDF Text Extractor + Make/Zapier -- trigger PDF extraction when new files are uploaded to Google Drive, Dropbox, or S3
  • PDF Text Extractor + OpenAI/LLM -- chain extraction with AI summarization to create document summaries from PDF collections
  • Scheduled runs -- monitor a document repository and extract text from newly published PDFs on a schedule
  • Webhooks -- trigger downstream processing immediately when extraction completes

API usage

Use PDF Text Extractor from code with the Apify API whenever you need automated PDF text extraction in a data pipeline, RAG workflow, document archive, or scheduled monitoring job.

Using the Apify API

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('automation-lab/pdf-text-extractor').call({
urls: [
'https://example.com/report.pdf',
'https://example.com/whitepaper.pdf',
],
includePages: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
console.log(`${item.fileName}: ${item.pageCount} pages, ${item.fullText.length} chars`);
});

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_APIFY_TOKEN')
run = client.actor('automation-lab/pdf-text-extractor').call(run_input={
'urls': [
'https://example.com/report.pdf',
'https://example.com/whitepaper.pdf',
],
'includePages': True,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
for item in items:
print(f"{item['fileName']}: {item['pageCount']} pages, {len(item['fullText'])} chars")

cURL

curl -X POST "https://api.apify.com/v2/acts/automation-lab~pdf-text-extractor/runs?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com/report.pdf"],
"includePages": true
}'

Use with AI agents via MCP

PDF Text Extractor is available as a tool for AI assistants that support the Model Context Protocol (MCP).

Use the actor-scoped MCP endpoint https://mcp.apify.com/?tools=automation-lab/pdf-text-extractor to give your AI client direct access to this actor:

Setup for Claude Code

$claude mcp add --transport http apify "https://mcp.apify.com/?tools=automation-lab/pdf-text-extractor"

Setup for Claude Desktop, Cursor, or VS Code

Add this to your MCP config file:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=automation-lab/pdf-text-extractor"
}
}
}

Your AI assistant will use OAuth to authenticate with your Apify account on first use.

Example prompts

Once connected, try asking your AI assistant:

  • "Use automation-lab/pdf-text-extractor to extract all text from this research paper: https://arxiv.org/pdf/1706.03762"
  • "Extract metadata and page count from these 5 PDF invoices and summarize the results"
  • "Download and extract text from all PDFs linked on this page, then create a summary of each document"

Learn more in the Apify MCP documentation.

Data handling, dependencies, and support

The actor downloads each user-supplied public PDF directly and parses it inside the Actor run with pdf-parse. PDF processing does not call an AI model, OCR provider, proxy, or external document-processing service. PDF bytes and extracted text are not copied to a separate external document cache. Datasets, key-value-store records, and run logs follow your Apify account retention settings and can be deleted with Apify storage controls.

Separately, failed operations send sanitized diagnostic input, exceptions, and Actor/build/run IDs to our private GlitchTip service for repair, using the Sentry SDK and terminal failure webhooks. Secret fields and URL queries are removed; reports are retained for 30 days. These operational reports are an external diagnostic copy, not a PDF-processing service. Deleting Apify run storage or datasets does not delete GlitchTip reports; their separate 30-day retention applies.

The dataset stores documented PDF text, metadata, diagnostics, source URLs, and optional page text. Do not submit confidential documents through public URLs. For help, use the Issues tab on the Actor's Apify Store page and include a reproducible public PDF URL when possible.

PDF Text Extractor processes publicly accessible PDF files that you provide URLs for. The actor downloads files the same way a web browser would. Always ensure you have the right to access and process the documents you are extracting text from.

For personal data, comply with GDPR and applicable privacy laws. Review the terms of service for any document repositories you are accessing. Apify provides a general web scraping legality guide for reference.

FAQ

How fast is PDF Text Extractor? Processing speed depends on PDF file size and download speed. A typical 1 MB PDF takes 1-3 seconds to download and parse. With maxConcurrency: 10, you can process 100 average-sized PDFs in under a minute.

How much does it cost to extract text from 1,000 PDFs? At BRONZE tier pricing: $0.005 (start) + 1,000 x $0.003 (per PDF) = $3.005 total. With the free $5 credit, you can process about 1,600 PDFs at no cost.

Does it work with scanned PDFs? This actor extracts embedded text rather than performing OCR. Image-only scans return textExtractionStatus: "no_text", a warning, and a recommendation to route the file to an OCR service. Parsed textless PDFs are not charged as successful pdf-extracted events.

Why are some PDF fields returning null? Not all PDFs include metadata. The title, author, subject, and keywords fields depend on what the PDF creator set when generating the document. Many auto-generated PDFs leave these fields empty.

Why did a PDF fail with "Invalid PDF structure"? The URL may not point to an actual PDF file. Ensure the URL returns a direct PDF download, not an HTML page with an embedded PDF viewer. Some servers also require specific headers or authentication.

Can I extract text from password-protected PDFs? No. Password-protected (encrypted) PDFs cannot be parsed without the password. The actor will return an error for these files.