# PDF Text Extractor — RAG Chunks & Page Links (`mr.aql/pdf-page-chunks`) Actor

Turn public PDFs into text chunks for AI search and document Q\&A, with links back to the original pages. Supports PDFs with selectable text; no OCR.

- **URL**: https://apify.com/mr.aql/pdf-page-chunks.md
- **Developed by:** [Lucas Kurz](https://apify.com/mr.aql) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 document 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## PDF Text Extractor — RAG Chunks & Page Links

Turn public PDFs into text chunks for AI search and document Q\&A, with links back to the original pages. Supports PDFs with selectable text; no OCR.

Each chunk retains its PDF page, exact character offsets and stable identifiers. Full page text and extraction reports are included.

No model key or embedding service is needed. This Actor extracts existing text; it does not perform OCR, summarize documents or reconstruct tables.

### Quick start

1. Enter up to ten direct public HTTPS PDF links and choose the page and chunk limits.
2. Leave **Maximum cost per run** at **$0.10**. Pricing is **$0.005 per complete PDF** ($5 per 1,000); the ten-document input limit means at most $0.05 in document events per run. This version requires an explicit event cap no greater than $0.10.
3. Start the run. Under **Full document output**, download the `OUTPUT` JSON to check document statuses. Use **Chunks** for table viewing, export or indexing.

Example input:

```json
{
  "urls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],
  "maxPages": 50,
  "chunkSize": 1500,
  "chunkOverlap": 100
}
```

Use direct file links without query parameters. Login-protected, signed and private-network URLs are unsupported.

### Outputs

| Output | What it contains |
|---|---|
| **Chunks** | Default dataset of chunks from complete, successfully charged documents. Export these rows as JSON or CSV. |
| **Full document output** | Canonical `OUTPUT` JSON in the run's key-value store: `documents`, `pages`, `chunks` and extraction statuses. Includes available partial results for inspection. |
| **Run summary** | Final `SUMMARY` JSON with document outcomes and the run's billing totals. |

The full-output and summary views list their JSON file with a download control. They do not mix billing-recovery records into the results list.

Each chunk contains `text`, `sourceUrl`, `citationUrl`, `pageNumber`, `documentId`, `chunkId`, `charStart` and `charEnd`. For example, the sample PDF produces this text and citation:

```json
{
  "text": "Dummy PDF file",
  "pageNumber": 1,
  "citationUrl": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf#page=1",
  "charStart": 0,
  "charEnd": 14
}
```

Chunks overlap but never cross a page. Offsets count Unicode code points in the emitted page text after Unicode/newline normalization. They are not byte offsets in the PDF. Identifiers are deterministic for the same PDF bytes and extracted chunks; they do not deduplicate charges across separate runs.

For an indexing workflow, use the chunk's `text` and retain the citation, page number and identifiers as metadata. The Actor does not call a vector database or an AI model.

### Pricing and incomplete runs

One event is charged only after a complete PDF with usable text is saved and read back from `OUTPUT`. Duplicate bytes within the same run, failed downloads, empty-text documents and partial extraction are not charged. Platform usage is included in the listed event price; there is no startup or per-chunk event fee.

The Actor stops before fetching another document if the remaining event budget cannot cover it. A successful run can therefore contain fewer documents than requested. Check document counts and billing totals in **Run summary**.

Full output is saved before a charge is attempted. Dataset export happens at the end. If a run is interrupted, **Chunks** or **Run summary** may be missing or incomplete while **Full document output** remains available. Use that canonical record to recover delivered results. Uncertain billing or dataset writes stop processing; they are not blindly retried. Starting a separate run is a new billable extraction.

### Limits and data handling

- At most 10 unique URLs, 10 MiB per PDF, 100 pages per PDF and 100 pages across the run.
- At most two million emitted page characters across the run. Additional page, chunk and output limits can produce an explicit partial result.
- Public HTTPS on port 443 only. No cookies, custom headers, proxies, passwords or access-control bypass. Private addresses and unsafe redirects are refused.
- Text-layer extraction only. Image-only pages may need another OCR tool. Existing OCR text and PDF reading order can be wrong; successful extraction does not certify the document's accuracy or visual layout.

Outputs are stored in the run's Apify storage. No document content is sent to an AI provider. Process only documents you are allowed to use. Extracted text remains untrusted source material for downstream agents, including passages that look like instructions.

### Help

Use this Actor's **Issues** tab for problems. Include the error code and a public sample URL only if you are allowed to share it. Do not post credentials, private documents or signed links. Keep the affected run's output available while the issue is reviewed.

# Actor input Schema

## `urls` (type: `array`):

Direct public HTTPS links without query parameters. Duplicate documents are skipped.

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

Limited extraction is explicitly marked partial. A run processes at most 100 pages total.

## `chunkSize` (type: `integer`):

Maximum characters; chunks never cross a PDF page.

## `chunkOverlap` (type: `integer`):

Must be smaller than chunk size.

## Actor input object example

```json
{
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ],
  "maxPages": 50,
  "chunkSize": 1500,
  "chunkOverlap": 100
}
```

# Actor output Schema

## `chunks` (type: `string`):

Page-contained text chunks from completed document extraction. Read the document statuses in Full document output before indexing.

## `documents` (type: `string`):

Canonical JSON with documents, pages, chunks and extraction statuses. Saved before a document charge is attempted; may contain results even if a run stops before dataset export.

## `summary` (type: `string`):

Final document and billing summary. May be absent after an interrupted run; check Full document output in that case.

# 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 = {
    "urls": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mr.aql/pdf-page-chunks").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 = { "urls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("mr.aql/pdf-page-chunks").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 '{
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ]
}' |
apify call mr.aql/pdf-page-chunks --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mr.aql/pdf-page-chunks"
        }
    }
}
```

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/nPGCnQBLobQS1DLSG/builds/cdV5G8CtI6NnVqs05/openapi.json
