# PDF Text and Table Extractor with OCR (`tiger19935/pdf-text-table-extractor`) Actor

Extract text, tables and Markdown from PDF files in bulk. Automatic OCR fallback for scanned pages, page ranges and URL lists. Clean output for RAG, search and data pipelines.

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

## Pricing

from $3.20 / 1,000 pdf page extracteds

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 & Table Extractor - OCR, Markdown for RAG

Turn PDF files into clean text, tables and Markdown. Paste direct PDF links, get structured data back: one row per page or one row per document. Scanned pages are recognised automatically with OCR in 25+ languages. Built for RAG pipelines, document search, data entry automation and research.

### What you get

- **Text of every page**, with the original layout preserved (columns stay aligned).
- **Tables as arrays of rows**, detected from the page layout, ready for CSV/Excel or a database.
- **Markdown** with joined paragraphs, headings and Markdown tables - ready to chunk for LLMs and vector search.
- **OCR for scanned pages** (Tesseract): English, German, French, Spanish, Italian, Portuguese, Russian, Ukrainian, Polish, Dutch, Turkish, Arabic, Chinese, Japanese, Korean, Hindi and more.
- **Metadata**: title, author, creation date, producer, page count, file size.
- **Page ranges** such as 1-5 or 3,7,10- and a cap on pages per file.
- Bulk mode: hundreds of PDFs in one run, processed in parallel.

### How it works

1. You pass direct links to PDF files.
2. The actor downloads each file and reads its text layer page by page.
3. Pages without a text layer (scans, photos) are rendered and recognised with OCR.
4. You receive the results in the dataset (JSON, CSV, Excel, XML, HTML) and via API.

### Input

| Field | Description |
|---|---|
| PDF URLs | Direct links to PDF files (required). |
| Page range | For example 1-5 or 1,3,10-20. Empty means all pages. |
| Output format | One row per page, or one row per document. |
| Detect tables / Return Markdown | Turn table detection and Markdown on or off. |
| OCR for scanned pages | On by default. Pages with almost no text layer are recognised with OCR. |
| Force OCR | Recognise every page, ignoring the embedded text. |
| OCR languages | For example eng or eng+deu. |

Example input:

```
{
    "startUrls": [{ "url": "https://arxiv.org/pdf/1706.03762" }],
    "pageRange": "1-3",
    "outputMode": "perPage"
}
```

### Output (one row per page)

```
{
    "url": "https://arxiv.org/pdf/1706.03762",
    "fileName": "1706.03762",
    "title": "Attention Is All You Need",
    "pageCount": 15,
    "page": 1,
    "ocrUsed": false,
    "charCount": 4120,
    "text": "...",
    "markdown": "...",
    "tables": [],
    "scrapedAt": "2026-10-14T08:00:00.000Z"
}
```

In the per-document mode you get one record with the whole text, the Markdown, all tables with their page numbers and a list of pages.

### Pricing

You pay only for pages that returned text. Pages with a text layer and OCR pages have separate prices; empty pages and failed files are free.

| Event | Price |
|---|---|
| PDF page with text layer | $0.004 per page |
| OCR page (scanned) | $0.008 per page |

Volume discounts apply automatically for Bronze, Silver and Gold Apify subscribers. A 20-page report costs about $0.08. Set a maximum cost per run in the run options to keep full control.

### Tips

- The link must return the PDF file itself. If a site shows a viewer page, copy the direct .pdf link.
- For scans in a language other than English, set the OCR languages, for example deu or eng+fra.
- For RAG, use the per-page output and chunk the Markdown field.
- Password-protected PDFs are not supported and are reported as errors.

### Limits and notes

- Table detection reads the text layout. It works well on reports, invoices and statements with text columns; borderless or heavily merged tables may need a manual check.
- OCR quality depends on the scan. Use 300 DPI for small print.
- Only publicly reachable files can be processed. Please make sure you have the right to process the documents you submit.

### Integrations

Run it from the Apify API, schedule it, or connect it to Make, Zapier, n8n, Google Sheets or your own code with the Apify client for JavaScript and Python.

### FAQ

**Does it work with scanned PDFs?** Yes. Pages without text are recognised with OCR automatically.

**Can I get tables as CSV?** Yes. Export the dataset as JSON or CSV; tables are returned as arrays of rows and can be converted in one line.

**What is the difference between page and document output?** Page output suits RAG and search; document output suits archiving and one-record-per-file workflows.

**Something looks wrong on my file.** Open an issue in the Issues tab with the PDF link and we will look at it.

### More tools by the same author

- [Image OCR Bulk](https://apify.com/tiger19935/image-ocr-bulk): Bulk OCR for images
- [Markdown & HTML to PDF](https://apify.com/tiger19935/paged-pdf-generator): Print-ready PDF from Markdown and HTML
- [Bulk Image and File Downloader](https://apify.com/tiger19935/bulk-image-file-downloader): Bulk download of images and files
- [Website Screenshot API](https://apify.com/tiger19935/website-screenshot-api): Full-page and mobile screenshots in bulk

# Actor input Schema

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

Direct links to PDF files, one per row. Public URLs only (the link must return the PDF itself, not a web page).

## `pageRange` (type: `string`):

Which pages to read, for example 1-5 or 1,3,10-20 or 5- (page 5 to the end). Leave empty for all pages. Applied to every PDF.

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

One dataset row per page (best for RAG chunking and search) or one row per document (full text, all tables and page list in one record).

## `extractTables` (type: `boolean`):

Find tables in the page layout and return them as arrays of rows. Works on PDFs with real text columns; for scanned pages tables are best-effort.

## `includeMarkdown` (type: `boolean`):

Add a cleaned Markdown version of each page: paragraphs joined, headings marked, tables as Markdown tables.

## `ocrFallback` (type: `boolean`):

Run OCR on pages that have no text layer (scanned documents, photos of paper). OCR pages are billed at the OCR page price.

## `forceOcr` (type: `boolean`):

Ignore the text layer and OCR all pages. Use it when the embedded text is garbled. Slower and billed at the OCR page price.

## `ocrLanguages` (type: `string`):

Tesseract language codes joined with a plus sign, for example eng or eng+deu. Available: eng, deu, fra, spa, ita, por, rus, ukr, pol, nld, tur, ara, chi_sim, chi_tra, jpn, kor, hin, ces, swe, heb, vie, tha, ron.

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

Rendering resolution for OCR. 200 is a good balance, 300 helps with small print.

## `maxOcrPagesPerPdf` (type: `integer`):

Safety limit for OCR pages in one PDF.

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

Only the first N selected pages of each PDF are processed.

## `maxConcurrency` (type: `integer`):

How many PDFs to process at the same time. Raise the actor memory for values above 3.

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

PDFs larger than this are skipped.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://arxiv.org/pdf/1706.03762"
    }
  ],
  "pageRange": "1-3",
  "outputMode": "perPage",
  "extractTables": true,
  "includeMarkdown": true,
  "ocrFallback": true,
  "forceOcr": false,
  "ocrLanguages": "eng",
  "ocrDpi": 200,
  "maxOcrPagesPerPdf": 100,
  "maxPagesPerPdf": 200,
  "maxConcurrency": 3,
  "maxFileSizeMb": 100
}
```

# Actor output Schema

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

No description

## `summary` (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://arxiv.org/pdf/1706.03762"
        }
    ],
    "pageRange": "1-3"
};

// Run the Actor and wait for it to finish
const run = await client.actor("tiger19935/pdf-text-table-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 = {
    "startUrls": [{ "url": "https://arxiv.org/pdf/1706.03762" }],
    "pageRange": "1-3",
}

# Run the Actor and wait for it to finish
run = client.actor("tiger19935/pdf-text-table-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 '{
  "startUrls": [
    {
      "url": "https://arxiv.org/pdf/1706.03762"
    }
  ],
  "pageRange": "1-3"
}' |
apify call tiger19935/pdf-text-table-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tiger19935/pdf-text-table-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/1YiKZkdqNHBMwiCWg/builds/cvqbq4VHwZEgdOtw0/openapi.json
