# PDF to Text Extractor: Bulk PDF Scraper & Parser for RAG (`johto.data/pdf-to-text`) Actor

Bulk PDF text extraction API. Give PDF URLs, get text, page count and metadata in one row per PDF for LLM, RAG and search pipelines. Text-layer PDFs only, no OCR. Failed PDFs are free. $5 per 1,000 PDFs.

- **URL**: https://apify.com/johto.data/pdf-to-text.md
- **Developed by:** [Johto Data](https://apify.com/johto.data) (community)
- **Categories:** Developer tools, AI, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 pdf extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## 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 to Text Extractor: Bulk PDF Scraper & Parser for RAG

Bulk PDF text extraction API: turn a list of PDF URLs into clean text, page counts and metadata, one row per PDF. Built for LLM, RAG, search indexing and document pipelines.

### What does PDF to Text do?

Extract **text, page count and document metadata** from a list of public PDF URLs. PDF to Text uses pypdf to read the existing text layer. It does not perform OCR, summarize documents or use a language model.

### Pricing

**$5.00 per 1,000 successfully extracted PDFs**, using the `pdf` pay-per-event event. A PDF is successful only when it produces nonempty text. Error rows, blocked URLs and documents without extractable text do not trigger that event.

Example: 2,000 successful PDFs cost $10.00 in PDF events. The intended Store configuration has no start event, no automatic dataset-item event and no additional platform-usage charge. Check the live Pricing tab before running.

### Quick start

1. Add PDF URLs to `startUrls`. Each entry can be a URL string or an object with a `url` field.
2. Keep the default file-size and page limits, or lower them for your documents.
3. Press **Start**. Read the dataset or export it as JSON, CSV or Excel.

Example input using a [Federal Register PDF](https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf):

```json
{
  "startUrls": [
    { "url": "https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf" }
  ],
  "maxFileSizeMb": 20,
  "maxPages": 300
}
```

The Actor downloads only the supplied URLs and their redirects. It does not crawl links inside documents. Identical input URLs are processed once per run. A comma inside a URL remains part of that URL.

### Output

One dataset item is written per unique input URL processed before a budget or run limit stops the run.

| Field | Meaning |
|---|---|
| `url`, `loadedUrl` | Supplied URL and final download URL; final URL is present on success |
| `status`, `error` | `success` or `error`, with an error code on failure |
| `text` | Extracted document text, with blank lines between pages |
| `pageCount` | Total number of PDF pages, including pages without text |
| `wordCount`, `characterCount` | Whitespace-delimited word count and extracted text length |
| `metadata` | Title, author, subject, creator, producer and creation/modification dates, where present |
| `fileSizeBytes` | Downloaded PDF byte count |
| `extractedAt` | Extraction timestamp, ISO 8601 |

Example item from a real run on Nov 8, 2026:

```json
{
  "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
  "status": "success",
  "fileSizeBytes": 13264,
  "text": "Dummy PDF file",
  "pageCount": 1,
  "metadata": {
    "title": null,
    "author": "Evangelos Vlachogiannis",
    "subject": null,
    "creator": "Writer",
    "producer": "OpenOffice.org 2.1",
    "creationDate": "D:20070223175637+02'00'",
    "modificationDate": null
  },
  "characterCount": 14,
  "wordCount": 3,
  "extractedAt": "2026-11-09T03:17:58.732482+00:00"
}
```

Metadata comes from the PDF itself, is not verified, and may be absent or inaccurate. PDF date strings are returned as stored rather than normalized.

An error item has `status: "error"`, a code such as `robots_disallowed`, `http_404`, `encrypted_pdf` or `no_extractable_text`, and null text, page count and metadata. Other URLs continue processing.

### Input options

| Field | Default | Limit |
|---|---|---|
| `startUrls` | Required | 1 to 1,000 URLs |
| `maxFileSizeMb` | 20 | 1 to 50 MiB per download |
| `maxPages` | 300 | 1 to 1,000 pages per PDF |

Files exceeding these limits are rejected, not partially extracted. Extraction is also limited to 2 million characters and an isolated worker with a 50-second wall-clock timeout, a 40-second CPU limit and a 512 MiB address-space limit. Downloads have a 60-second timeout and follow at most five redirects.

### API and use cases

Use the [Apify API](https://docs.apify.com/api/v2) or the Actor's API tab to submit the same JSON input and retrieve its dataset. Text can be passed to a search index, document archive or a separate RAG pipeline. The Actor does not create embeddings or guarantee an LLM context size.

### Use with AI agents and automation

**Apify MCP server (Claude, Cursor, ChatGPT, any MCP client).** Add `https://mcp.apify.com?tools=johto.data/pdf-to-text` as a remote MCP server. The agent gets one tool that takes the input below and returns one row per PDF with `text`, page count and metadata.

**API, one call.** Runs and returns the dataset in the same request:

```bash
curl -X POST "https://api.apify.com/v2/acts/johto.data~pdf-to-text/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf"}]}'
```

**LangChain (Python).**

```python
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("johto.data/pdf-to-text")
```

**n8n, Make, Zapier.** Use the Apify app or node, choose **Run Actor**, enter `johto.data/pdf-to-text` and paste the input JSON. Then map dataset fields into Sheets, a CRM or a database.

### FAQ

**How does the price compare?** $5.00 per 1,000 successful PDFs, no start fee, and failed PDFs are free. Other PDF text extractors in the Store list $5 to $20 per 1,000 PDFs plus start or page fees (checked Nov 8, 2026). Those include OCR, which this Actor does not.

**What about scanned PDFs?** They have no text layer, so they return an error row and are not charged.

**How long does a run take?** The prefilled input finishes in about 3 seconds.

### Limitations and responsible use

Scanned image-only PDFs need OCR and return an uncharged error here. Encrypted, damaged or unusually complex PDFs may also fail. Multi-column layouts, tables and font encodings can affect reading order and accuracy. The Actor does not preserve visual layout or produce structured tables.

Caller is responsible for the target site's terms. robots.txt is respected. Explicitly disallowed paths and robots server errors are skipped. A missing or unreachable robots file is treated as allowing access; that is not a content license. Robots rules are checked again at redirect destinations. Private-network destinations, URL credentials and nonstandard ports are blocked. There is no proxy or access-control bypass.

Process only documents you own, are licensed to use, or have permission to process. Public availability does not grant rights to redistribution or model training. Preserve source attribution and license notices. Text and PDF author metadata may contain personal data. Ensure a lawful basis before storing or reusing it. Transformed Federal Register text is not an official legal edition.

### Support

Open an issue in the **Issues** tab with a public example URL and the error code. Do not include API tokens, private documents or personal data. Built by [Johto Data](https://johtodata.com).

# Actor input Schema

## `startUrls` (type: `array`):

Public HTTP or HTTPS PDF URLs you have permission to process. Duplicates are skipped. Maximum 1,000 URLs.

## `maxFileSizeMb` (type: `integer`):

Larger downloads are skipped without a PDF event charge.

## `maxPages` (type: `integer`):

Documents exceeding this limit are skipped, not partially extracted.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf"
    }
  ],
  "maxFileSizeMb": 20,
  "maxPages": 300
}
```

# Actor output Schema

## `dataset` (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 = {
    "startUrls": [
        {
            "url": "https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("johto.data/pdf-to-text").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 = { "startUrls": [{ "url": "https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf" }] }

# Run the Actor and wait for it to finish
run = client.actor("johto.data/pdf-to-text").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 '{
  "startUrls": [
    {
      "url": "https://www.govinfo.gov/content/pkg/FR-2026-11-06/pdf/2026-22789.pdf"
    }
  ]
}' |
apify call johto.data/pdf-to-text --silent --output-dataset

```

## MCP server setup

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

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/nrHgrCpbODGkbrhdW/builds/XTr6waQ3b07I16Aj3/openapi.json
