# PDF Text Extractor — Text & Metadata from URLs (`darknezz/pdf-text-extractor`) Actor

Extract clean text and metadata from any PDF by URL: full text, page count, title, author, dates as JSON. Perfect for AI pipelines, RAG ingestion, document search and content analysis. No API key needed.

- **URL**: https://apify.com/darknezz/pdf-text-extractor.md
- **Developed by:** [Oaida Adrian](https://apify.com/darknezz) (community)
- **Categories:** Developer tools, AI
- **Stats:** 1 total users, 1 monthly users, 93.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PDF Text Extractor — Text & Metadata from Any PDF URL

Extract **clean plain text and full document metadata from any PDF** — just paste the URLs. No API keys, no login, no proxies, no OCR setup. Point it at a list of PDF links and get back structured, LLM-ready text plus title/author/date/page metadata for every file.

Built for developers and data teams who need to turn scattered PDF documents — research papers, financial reports, whitepapers, manuals, invoices, legal filings — into clean structured data at scale.

### Why this Actor

- **Zero configuration** — no credentials, no proxy budget, no browser. Paste URLs, press run.
- **RAG-ready output** — optional `includePageTexts` mode returns per-page text so you can chunk documents for embeddings without re-splitting.
- **Resilient by design** — unreadable or password-protected files are skipped and logged, never crashing the run. A batch of 500 PDFs with 3 bad links still returns 497 clean items.
- **Handles big documents** — multi-hundred-page files up to 100 MB each, including "secured" PDFs encrypted with an empty password.

### How it works

Give it a list of direct PDF URLs. For each file the Actor downloads it, parses it with a battle-tested PDF engine, and outputs **one dataset item per PDF** with the full extracted text and all document metadata. Set `maxPagesPerPdf` to cap long files, or `includePageTexts: true` to also get an array with each page's text separately.

### Input

```json
{
  "pdfUrls": [
    "https://arxiv.org/pdf/1706.03762",
    "https://bitcoin.org/bitcoin.pdf"
  ],
  "maxPagesPerPdf": 0,
  "includePageTexts": false
}
```

| Field | Type | Description |
|---|---|---|
| `pdfUrls` | array | Direct URLs of PDF files (**required**) |
| `maxPagesPerPdf` | integer | Max pages to extract per PDF; `0` = all pages |
| `includePageTexts` | boolean | Also output a per-page text array — ideal for RAG chunking |

### Output

One item per PDF:

```json
{
  "url": "https://arxiv.org/pdf/1706.03762",
  "fileName": "1706.03762",
  "fileSizeBytes": 2215244,
  "numPages": 15,
  "pagesExtracted": 15,
  "text": "Attention Is All You Need ...",
  "textLength": 39432,
  "wordCount": 6120,
  "title": "Attention Is All You Need",
  "author": null,
  "creator": "LaTeX with hyperref",
  "producer": "pdfTeX-1.40.25",
  "creationDate": "D:20240410010203Z",
  "modDate": null,
  "encrypted": false,
  "pageTexts": null
}
```

With `includePageTexts: true`, `pageTexts` becomes `["page 1 text...", "page 2 text...", ...]`.

### Use cases

- 🤖 **AI / RAG pipelines** — turn PDFs into LLM-ready text; use `pageTexts` as natural chunk boundaries for embeddings.
- 🔎 **Document search & indexing** — full text plus title/author/date metadata to power search over a PDF corpus.
- 📊 **Content & compliance analysis** — word counts, page counts, and document properties across large batches.
- 📚 **Bulk research ingestion** — pull hundreds of arXiv / SSRN papers or vendor whitepapers in one run.
- 🧾 **Report & invoice processing** — extract the text layer from financial reports, statements, and structured invoices.

### Run it from the API

Trigger the Actor and get results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/darknezz~pdf-text-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pdfUrls":["https://bitcoin.org/bitcoin.pdf"],"includePageTexts":true}'
```

Or from Python with the Apify SDK:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR-APIFY-TOKEN")

run = client.actor("darknezz/pdf-text-extractor").call(
    run_input={"pdfUrls": ["https://arxiv.org/pdf/1706.03762"], "includePageTexts": True}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["wordCount"], "words", "-", item["url"])
```

**Scheduling:** attach an Apify Schedule (e.g. hourly) to keep a folder of report URLs continuously ingested into a dataset that feeds your pipeline.

**Worked example:** a run with `{"pdfUrls": ["https://bitcoin.org/bitcoin.pdf", "https://arxiv.org/pdf/1706.03762"]}` returned **2 clean items in seconds**. The Bitcoin whitepaper resolved to 9 pages (184 KB download) with the full text starting at the real title — "Bitcoin: A Peer-to-Peer Electronic Cash System", Satoshi Nakamoto — while the arXiv paper "Attention Is All You Need" (2.2 MB) extracted all 15 pages of text and metadata ready for chunking and embeddings. No failed fetches, no proxies.

### Pricing

**Free to use on the Apify Store** — no pay-per-event charges. You only pay Apify's standard platform compute costs for running it, not per file. No monthly minimum.

### Companion tools

Extracting **one PDF at a time**? **[Vertical Corpora Builder](https://apify.com/darknezz/vertical-corpus-builder)** (pay-per-event) discovers and ingests whole document corpora — legal, medical, financial — from seed lists, then dedupes and normalises the text for LLM fine-tuning and RAG evaluation.

### FAQ

**Does it OCR scanned PDFs?** No — it extracts the embedded text layer. Scanned image-only PDFs return empty `text` (the item still includes metadata and page counts, so you can detect and route them to an OCR step).

**Password-protected PDFs?** Files encrypted with an empty password (common "secured" PDFs) are extracted automatically. User-password-protected files are skipped with a warning rather than failing the run.

**What's the file size limit?** 100 MB per file.

**Can I limit pages for very long documents?** Yes — set `maxPagesPerPdf` to any number; `0` extracts everything.

**Do I need a proxy?** No. The Actor downloads PDFs directly over HTTPS — no proxy or residential IP budget required.

**What if one URL is broken?** That file is skipped and logged; every other PDF in the batch still returns normally.

**Which engines are supported?** Any server-rendered PDF served over HTTPS — arXiv, government filings, corporate reports, manuals. If a URL redirects to a login wall or an HTML page, it's logged as a failed fetch and skipped.

### Limitations

- Only the embedded text layer is extracted — scanned (image-only) PDFs yield empty `text` and need an OCR step (see FAQ).
- Files behind interactive JS viewers (e.g. some document portals) aren't supported — use the direct `.pdf` URL.
- Extraction quality depends on the PDF's own text layer; poorly generated files may have garbled ordering, which is a property of the source document, not the extractor.

Enjoying the extractor? A quick review on the Apify Store helps others find it.

# Actor input Schema

## `pdfUrls` (type: `array`):

Direct URLs of the PDF files to extract text from.

## `maxPagesPerPdf` (type: `integer`):

Maximum number of pages to extract per PDF. Set 0 to extract all pages.

## `includePageTexts` (type: `boolean`):

Also output an array with the text of each individual page (useful for chunking / RAG pipelines).

## Actor input object example

```json
{
  "pdfUrls": [
    "https://arxiv.org/pdf/1706.03762",
    "https://bitcoin.org/bitcoin.pdf"
  ],
  "maxPagesPerPdf": 0,
  "includePageTexts": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `url` (type: `string`):

No description

## `fileName` (type: `string`):

No description

## `fileSizeBytes` (type: `string`):

No description

## `numPages` (type: `string`):

No description

## `pagesExtracted` (type: `string`):

No description

## `textLength` (type: `string`):

No description

## `wordCount` (type: `string`):

No description

## `title` (type: `string`):

No description

## `author` (type: `string`):

No description

## `creationDate` (type: `string`):

No description

## `modDate` (type: `string`):

No description

## `encrypted` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "pdfUrls": [
        "https://arxiv.org/pdf/1706.03762",
        "https://bitcoin.org/bitcoin.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("darknezz/pdf-text-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "pdfUrls": [
        "https://arxiv.org/pdf/1706.03762",
        "https://bitcoin.org/bitcoin.pdf",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("darknezz/pdf-text-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "pdfUrls": [
    "https://arxiv.org/pdf/1706.03762",
    "https://bitcoin.org/bitcoin.pdf"
  ]
}' |
apify call darknezz/pdf-text-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,darknezz/pdf-text-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rbkAbMJ9H8aky1jNN/builds/JaiCRrI6z01bLWcpe/openapi.json
