# PDF Text & Table Extractor: OCR, DOCX, PPTX to Data, RAG Chunks (`ntriqpro/pdf-text-extractor`) Actor

Extract text from PDF, DOCX, PPTX, HTML, TXT, MD and EML by URL. One document in, hundreds of rows out: typed elements (titles, paragraphs, lists, tables), RAG-ready chunks and a per-document summary. Unofficial wrapper around unstructured (Apache-2.0).

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

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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 — OCR, PDF, DOCX & PPTX to Structured Data + RAG Chunks

**Turn any document URL into clean, structured data.** Give this Actor one or more public document URLs — **PDF, DOCX, PPTX, HTML, TXT, Markdown, EML, or PNG/JPG/TIFF/BMP images** — and it returns a flat dataset of typed elements (titles, paragraphs, list items, tables), **RAG-ready text chunks** and one summary row per document. **Scanned PDFs are OCR'd automatically** (Tesseract) when no text layer is found, and image URLs are read with OCR directly. No manual copy-paste, no file uploads: paste URLs, get rows.

Powered by [unstructured](https://github.com/Unstructured-IO/unstructured) (Apache-2.0), the open-source document-parsing engine with 15,000+ GitHub stars that backs many production RAG pipelines. This is an **unofficial** wrapper; see the disclaimer below.

### What does PDF Text Extractor do?

For every document URL you provide, three kinds of rows are produced:

| Row type | What it is | Typical volume |
|---|---|---|
| `document-summary` | One row per document: page count, element counts by type, table count, languages, total characters | 1 per document |
| `chunk` | Section-aware text chunks (chunk-by-title) sized for embedding into a vector DB — RAG-ready | 10–60 per document |
| `element` | Optional (off by default): one row per structural element — `Title`, `NarrativeText`, `ListItem`, `Table` (with HTML), page number, hierarchy (`parentId`) | 100–600 per document |

By default a 15-page research paper yields **~30 rows** (1 summary + ~29 chunks); with `includeElements` on it yields **400+ rows**. Tables keep their structure as `textAsHtml`.

### Why use it?

- **RAG pipelines** — skip the preprocessing step: URLs in, embedding-ready chunks out, on a schedule, via API.
- **Research & analysis** — batch-convert reports, papers and filings into rows you can filter in Excel or a database.
- **Content workflows** — pull structured text out of decks (PPTX), articles (HTML) and docs (DOCX) with one tool instead of five.
- **Apify platform** — run on a schedule, call via API, pipe results into any integration, download as JSON/CSV/Excel.

### How to use it

1. Open the **Input** tab.
2. Paste one or more document URLs (up to 50 per run).
3. Optionally toggle element rows / chunk rows and set the chunk size.
4. Click **Start**. Download the dataset as JSON, CSV, Excel or HTML, or read it via the API.

### Input example

```json
{
    "documentUrls": [
        "https://arxiv.org/pdf/1706.03762",
        "https://example.com/report.docx"
    ],
    "includeChunks": true,
    "chunkMaxChars": 1800,
    "maxResults": 500
}
```

### Output example

```json
{
    "rowType": "element",
    "sourceUrl": "https://arxiv.org/pdf/1706.03762",
    "fileType": "pdf",
    "elementIndex": 12,
    "elementType": "NarrativeText",
    "text": "The dominant sequence transduction models are based on complex recurrent...",
    "textLength": 312,
    "pageNumber": 1,
    "elementId": "8c2035…",
    "parentId": "1b6f4a…",
    "languages": ["eng"]
}
```

### Pricing

Four charge events:

| Event | When it is charged |
|---|---|
| Run start | Once per run, when the run starts |
| Document summary | Per delivered `document-summary` row (one per parsed document) |
| RAG chunk | Per delivered `chunk` row |
| Structured element | Per delivered `element` row (only when `includeElements` is on) |

Typical run cost (measured on a 15-page research paper):

| Scenario | Rows | What you pay |
|---|---|---|
| 1 paper, default settings (summary + chunks) | ~30 | **≈ $0.32** (1 start + 1 summary + 29 chunks) |
| 1 paper with `includeElements` on | ~423 | **≈ $0.52** (adds 393 element rows) |

Control your spend with:

- `maxResults` — a hard cost ceiling per run (default 500 rows),
- `includeElements` / `includeChunks` — pick the row types you need,
- the run's **maximum charge limit** in Run options.

Fetch status and quality information (HTTP status, page counts, truncation flags) are provided as data fields so you can judge every row yourself.

**Free plan**: runs parse up to 3 documents and return up to 25 rows per run — prioritised so you get the document summaries and RAG chunks first, then sample elements.

### OCR (scanned PDFs & images)

- **Scanned/image-only PDFs**: when a PDF has no text layer, the Actor automatically re-reads it with OCR (Tesseract, built into the image — nothing downloads at runtime). The document's summary row carries `"ocrApplied": true` so you can tell OCR'd text apart.
- **Image URLs** (PNG, JPG, TIFF, BMP) are always read with OCR — paste a receipt or screenshot URL and get its text as rows.
- **Languages**: English (`eng`, default) and Korean (`kor`) — set `"ocrLanguages": ["eng", "kor"]`. Other codes are ignored.
- Turn OCR off entirely with `"enableOcr": false`.
- OCR rows are ordinary result rows — they are charged under the same events as any other row (no OCR surcharge).

### Limitations

- OCR accuracy depends on scan quality; OCR output has no styling-based structure, so most OCR'd text arrives as paragraph elements.
- Legacy binary formats (`.doc`, `.ppt`) are not supported — convert them to DOCX/PPTX first.
- Files are fetched by URL (up to 50 MB each); there is no direct file upload.
- Only publicly accessible URLs — documents behind logins cannot be fetched.

### FAQ & disclaimers

**Is this the official unstructured Actor?** No. This is an **unofficial** wrapper around the open-source [unstructured](https://github.com/Unstructured-IO/unstructured) library (Apache-2.0). This Actor is **not affiliated with, endorsed by, or sponsored by Unstructured Technologies, Inc.** All trademarks belong to their respective owners.

**Legal** — you are responsible for having the right to access and process the documents you submit, for complying with each source's Terms of Service and applicable copyright law, and you act as the data controller for any personal data contained in the documents you process.

Found a bug or need a feature? Open an issue on the **Issues** tab — it is checked regularly.

# Actor input Schema

## `documentUrls` (type: `array`):

One or more public URLs of documents to parse. Supported: PDF, DOCX, PPTX, HTML, TXT, Markdown, EML, plus PNG/JPG/TIFF/BMP images (read via OCR). Scanned PDFs without a text layer are OCR'd automatically. Each document is broken into typed elements (titles, paragraphs, lists, tables), RAG-ready chunks and one summary row. Max 50 per run.

## `includeElements` (type: `boolean`):

Off by default. Turn on to also receive one row per structural element — title, paragraph, list item, table. This is the detailed, high-volume view of each document (hundreds of rows per document, billed per row).

## `enableOcr` (type: `boolean`):

On by default. Scanned/image-only PDFs (no text layer) are automatically re-read with OCR (Tesseract), and PNG/JPG/TIFF/BMP image URLs are read with OCR. Turn off to skip OCR entirely.

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

Languages Tesseract should read. Available: "eng" (English, default) and "kor" (Korean). Other codes are ignored.

## `includeChunks` (type: `boolean`):

Smart chunks that respect section boundaries (chunk-by-title), ready to embed into a vector database for RAG pipelines.

## `chunkMaxChars` (type: `integer`):

Upper bound on the size of each RAG chunk. 500-8000.

## `perFileTimeoutSecs` (type: `integer`):

How long a single document may take to parse before it is abandoned. 30-600.

## `maxRunSecs` (type: `integer`):

Stop parsing new documents after this many seconds. Everything already parsed stays in the dataset. 60-21600.

## `maxResults` (type: `integer`):

Upper bound on billable result rows for this run — your cost ceiling. Free-plan runs return at most 25 rows regardless of this value.

## `disclaimerAck` (type: `boolean`):

Required. By checking this you confirm that (1) you only process publicly accessible documents you are authorized to access; (2) you will respect each source's Terms of Service and applicable copyright; (3) you are responsible for any personal data contained in the documents you process.

## Actor input object example

```json
{
  "documentUrls": [
    "https://arxiv.org/pdf/1706.03762",
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ],
  "enableOcr": true,
  "ocrLanguages": [
    "eng"
  ],
  "includeChunks": true,
  "chunkMaxChars": 1800,
  "perFileTimeoutSecs": 120,
  "maxRunSecs": 900,
  "maxResults": 500,
  "disclaimerAck": true
}
```

# 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 = {
    "documentUrls": [
        "https://arxiv.org/pdf/1706.03762",
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    ],
    "includeElements": false,
    "enableOcr": true,
    "ocrLanguages": [
        "eng"
    ],
    "includeChunks": true,
    "chunkMaxChars": 1800,
    "perFileTimeoutSecs": 120,
    "maxRunSecs": 900,
    "maxResults": 500,
    "disclaimerAck": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/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 = {
    "documentUrls": [
        "https://arxiv.org/pdf/1706.03762",
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    ],
    "includeElements": False,
    "enableOcr": True,
    "ocrLanguages": ["eng"],
    "includeChunks": True,
    "chunkMaxChars": 1800,
    "perFileTimeoutSecs": 120,
    "maxRunSecs": 900,
    "maxResults": 500,
    "disclaimerAck": True,
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/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 '{
  "documentUrls": [
    "https://arxiv.org/pdf/1706.03762",
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ],
  "includeElements": false,
  "enableOcr": true,
  "ocrLanguages": [
    "eng"
  ],
  "includeChunks": true,
  "chunkMaxChars": 1800,
  "perFileTimeoutSecs": 120,
  "maxRunSecs": 900,
  "maxResults": 500,
  "disclaimerAck": true
}' |
apify call ntriqpro/pdf-text-extractor --silent --output-dataset

```

## MCP server setup

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