# PDF Text Extractor with OCR (`ridgeline_apps/pdf-text-extractor`) Actor

PDF to text: extract clean text from PDF files by URL or upload. Reads the PDF's own text layer and runs OCR only on scanned pages. Per-page output for RAG and AI pipelines. Blank and failed pages are free.

- **URL**: https://apify.com/ridgeline_apps/pdf-text-extractor.md
- **Developed by:** [Promise Land Provision LLC](https://apify.com/ridgeline_apps) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 ocr pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Text Extractor with OCR

Extract clean text from PDF files: paste PDF links or upload files and get the text of every page back as JSON, CSV or XLSX. Normal PDFs are read directly from their text layer, which is fast and cheap. Scanned pages are detected automatically and read with OCR. You only pay for OCR on the pages that need it.

**Built for:** RAG and AI pipelines, document search, contract and invoice processing, research archives, and anyone who needs PDF text without copy-pasting.

### What you get

- **Smart OCR.** Each page is checked. Pages with real text are read directly. Scanned or image-only pages, and pages with broken font encoding, go through OCR (Tesseract).
- **Mixed PDFs handled.** A PDF with typed pages and scanned pages is read correctly page by page.
- **One result per PDF or one per page.** Per-page output drops straight into embeddings, vector databases and spreadsheets.
- **Page numbers, method and confidence.** Every page says whether it was read from text or OCR, with an OCR confidence score.
- **7 OCR languages:** English, Spanish, French, German, Portuguese, Italian and Dutch, mixable in one run.
- **Page ranges and limits.** Read pages 5–20 only, cap pages per PDF, cap file size.
- **PDF metadata:** title, author, creator, producer and dates when present.
- **Fair billing.** Blank pages, failed pages and files that can't be opened are never charged. The run stops cleanly at your maximum cost per run.

### How to use

1. Add PDF links (one per line) or upload PDF files in **PDF files**.
2. Leave **OCR for scanned pages** on **Auto**, or choose Never to skip OCR entirely.
3. Pick your **OCR languages** if documents aren't in English.
4. Choose **One result per PDF** or **One result per page**.
5. Click **Start**, then download results as JSON, CSV, XLSX or HTML, or fetch them with the API.

#### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/ridgeline_apps~pdf-text-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"files": ["https://example.com/report.pdf"], "outputMode": "page"}'
```

It also works from Make, Zapier, n8n and the Apify MCP server for AI agents.

### Input

| Field | Description | Default |
|---|---|---|
| `files` | PDF URLs or uploaded files | required |
| `ocrMode` | `auto`, `never` or `always` | `auto` |
| `ocrLanguages` | Any of `eng`, `spa`, `fra`, `deu`, `por`, `ita`, `nld` | `["eng"]` |
| `outputMode` | `document` (one result per PDF) or `page` (one per page) | `document` |
| `includePageDetails` | Per-page list inside each document result | `true` |
| `pageFrom` / `pageTo` | Page range to read | all pages |
| `maxPagesPerPdf` | Safety cap on pages per PDF | 500 |
| `maxFileSizeMb` | Larger files are skipped (free) | 50 |
| `ocrDpi` | OCR resolution, 150–400 | 300 |

### Output

One result per PDF (shortened):

```json
{
  "url": "https://example.com/contract.pdf",
  "fileName": "contract.pdf",
  "status": "ok",
  "pageCount": 3,
  "pagesProcessed": 3,
  "textPages": 1,
  "ocrPages": 1,
  "emptyPages": 1,
  "wordCount": 412,
  "text": "MASTER SERVICES AGREEMENT\nThis agreement is made between...",
  "metadata": { "title": "Contract", "producer": "Example Writer 2.1" },
  "truncated": false,
  "pages": [
    { "pageNumber": 1, "method": "text", "text": "MASTER SERVICES AGREEMENT...", "ocrConfidence": null },
    { "pageNumber": 2, "method": "ocr", "text": "Signed by both parties...", "ocrConfidence": 94.1 },
    { "pageNumber": 3, "method": "empty", "text": "", "ocrConfidence": null }
  ]
}
```

One result per page:

```json
{ "url": "https://example.com/contract.pdf", "fileName": "contract.pdf", "pageNumber": 2, "pageCount": 3, "method": "ocr", "text": "Signed by both parties...", "wordCount": 210, "ocrConfidence": 94.1, "status": "ok" }
```

Files that fail come back with `"status": "error"` and a plain-English `error` such as "This PDF is password-protected." They are never charged.

### Pricing

Pay per page, with no subscription:

- **Text page** (read from the PDF's own text): charged per page.
- **OCR page** (scanned page read with OCR): charged per page.
- **Blank pages, failed pages and unreadable files: free.**

The exact prices are shown on the Pricing tab. A 10-page typed PDF costs a fraction of a cent, and you can set a maximum cost per run in the run options.

### FAQ

**Does it work on scanned PDFs?** Yes. With OCR on Auto, image-only pages are detected and read with OCR. OCR accuracy depends on scan quality; clean 300 DPI scans usually score above 90% confidence.

**Does it keep tables and columns?** Text keeps its line breaks and reading order as stored in the PDF. Tables come out as text lines, not as structured cells.

**Password-protected PDFs?** They're reported as errors and not charged.

**Handwriting?** OCR is designed for printed text. Handwriting results are poor.

**Where do my files go?** Files are downloaded into your own Apify run and processed there. Nothing is sent to any third-party service. Results stay in your Apify storage under your account's retention settings.

**Limits?** Up to 200 MB per file and 5,000 pages per PDF. For large batches, give the run more memory for faster OCR.

### Legal

Only process documents you have the right to use. You're responsible for the documents you submit and how you use the extracted text. Not intended for medical records (PHI) or other regulated data that requires a signed processing agreement.

Built on open-source software: PDFium (BSD-3-Clause / Apache-2.0, via pypdfium2), Tesseract OCR (Apache-2.0), Pillow (MIT-CMU) and httpx (BSD-3-Clause).

Questions or a feature request? Open an issue on the **Issues** tab.

# Actor input Schema

## `files` (type: `array`):

Paste PDF URLs (one per line) or upload PDF files. Each PDF becomes one result, or one result per page if you choose page output.

## `ocrMode` (type: `string`):

Auto reads the PDF's own text and runs OCR only on pages that are scanned images. Never skips OCR entirely (cheapest). Always runs OCR on every page.

## `ocrLanguages` (type: `array`):

Languages used when a page needs OCR. Pick every language that appears in your documents.

## `outputMode` (type: `string`):

One result per PDF (with page details inside), or one result per page (best for RAG, embeddings and spreadsheets).

## `includePageDetails` (type: `boolean`):

In 'one result per PDF' mode, also include a list of pages with their text, method (text or OCR) and OCR confidence.

## `pageFrom` (type: `integer`):

Start at this page (1 = first page).

## `pageTo` (type: `integer`):

Stop at this page. Leave empty to read to the end.

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

Safety limit on pages read from each PDF.

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

Larger files are skipped and not charged.

## `ocrDpi` (type: `integer`):

Higher values read small print better but run slower. 300 suits most scans.

## Actor input object example

```json
{
  "files": [
    "https://raw.githubusercontent.com/mozilla/pdf.js/master/test/pdfs/tracemonkey.pdf"
  ],
  "ocrMode": "auto",
  "ocrLanguages": [
    "eng"
  ],
  "outputMode": "document",
  "includePageDetails": true,
  "pageFrom": 1,
  "maxPagesPerPdf": 500,
  "maxFileSizeMb": 50,
  "ocrDpi": 300
}
```

# Actor output Schema

## `results` (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 = {
    "files": [
        "https://raw.githubusercontent.com/mozilla/pdf.js/master/test/pdfs/tracemonkey.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ridgeline_apps/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 = { "files": ["https://raw.githubusercontent.com/mozilla/pdf.js/master/test/pdfs/tracemonkey.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("ridgeline_apps/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 '{
  "files": [
    "https://raw.githubusercontent.com/mozilla/pdf.js/master/test/pdfs/tracemonkey.pdf"
  ]
}' |
apify call ridgeline_apps/pdf-text-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ridgeline_apps/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/zjBOfsuVT6YTepVOv/builds/tunXdae60b1fOfduo/openapi.json
