# PDF to Markdown for AI & RAG (Tables + OCR) (`dofunbiz/pdf-to-markdown`) Actor

Convert PDFs to clean Markdown or text for LLMs and RAG: headings, paragraphs, Markdown tables, OCR for scanned pages, page ranges, metadata and ready-made chunks.

- **URL**: https://apify.com/dofunbiz/pdf-to-markdown.md
- **Developed by:** [Scot C](https://apify.com/dofunbiz) (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

from $1.00 / 1,000 text pages

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 Markdown for AI & RAG (Tables + OCR)

Turn PDFs into **clean, LLM-ready Markdown**, with no layout junk and no broken words. Paste links, and get back Markdown you can feed directly into ChatGPT, Claude, embeddings or a RAG pipeline.

### What you get, per PDF

- **Clean Markdown**: headings detected from font sizes, wrapped lines merged into proper paragraphs, rotated margin text removed.
- **Tables as Markdown tables**: ruled tables become `| col | col |` tables you can read and query.
- **OCR for scanned pages**: pages with no text layer are read automatically with OCR. Choose from 7 languages.
- **Page ranges**: process only the pages you need (`1-5,9,12-`).
- **Page markers**: `<!-- page N -->` comments, so your AI answers can cite page numbers.
- **RAG chunks**: optional chunking on paragraph boundaries, with overlap, ready for embedding.
- **Metadata**: title, author, creation date, producer.
- A **.md file per document**, plus a structured JSON row with page, OCR and table counts.

### Who it's for

- **AI and RAG builders**: ingest manuals, reports, papers and contracts into a vector database.
- **Automation workflows** (Make, Zapier, n8n, LangChain): turn a PDF link into text in one API call.
- **Researchers and analysts**: pull readable text out of papers, filings and scanned archives.

### Input

| Field | Example |
|---|---|
| PDF URLs | `https://arxiv.org/pdf/1706.03762` |
| Pages | `1-5,9` (empty = all) |
| OCR for scanned pages | Auto, Always or Off |
| RAG chunk size | `2000` characters (0 = off) |

### Example output (excerpt)

From "Attention Is All You Need" (arXiv), page 1:

```markdown
<!-- page 1 -->

### Attention Is All You Need

#### Abstract

The dominant sequence transduction models are based on complex recurrent or convolutional
neural networks that include an encoder and a decoder. The best performing models also
connect the encoder and decoder through an attention mechanism...
```

Each result row also includes: `pages`, `textPages`, `ocrPages`, `tables`, `characters`, `metadata`, `chunks` (optional) and `markdownFile`.

### Pricing

Pay per event, and only for pages you actually process:

- **Text page**: a fraction of a cent per page.
- **OCR page** (scanned pages only): a small per-page fee.

Failed downloads are never charged. You can cap spend per run with Apify's maximum-charge setting, and the Actor stops cleanly when the cap is reached.

### Notes and limits

- PDFs up to 100 MB each. Use "Max pages per document" to control cost on very large files.
- Table detection works on tables with ruling lines. Borderless tables come out as text.
- OCR uses Tesseract, which works well on clean scans. Handwriting and very low-quality scans give weaker results.
- Password-protected PDFs aren't supported.
- Only process documents you have the right to use.

# Actor input Schema

## `pdfUrls` (type: `array`):

Direct links to PDF files (http/https). Up to 100 MB each.

## `pages` (type: `string`):

Optional page selection applied to every document, e.g. '1-5,9,12-'. Empty = all pages.

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

'auto' runs OCR only on pages with no text layer (scans/images). 'always' OCRs every page. 'off' never uses OCR.

## `ocrLanguage` (type: `string`):

Tesseract language code(s), e.g. 'eng', 'deu', 'fra', 'spa', or 'eng+deu'.

## `includeTables` (type: `boolean`):

Detect ruled tables and output them as Markdown tables.

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

If > 0, also split each document into chunks of about this many characters on paragraph boundaries (for embeddings/RAG). 0 = no chunks.

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

Characters repeated between consecutive chunks.

## `pageMarkers` (type: `boolean`):

Insert  comments so you can cite page numbers.

## `outputText` (type: `boolean`):

Add a plain-text version (no Markdown heading marks) to each result.

## `maxPagesPerDocument` (type: `integer`):

Safety cap on pages processed per document (controls cost).

## Actor input object example

```json
{
  "pdfUrls": [
    "https://arxiv.org/pdf/1706.03762"
  ],
  "ocrMode": "auto",
  "ocrLanguage": "eng",
  "includeTables": true,
  "chunkSize": 0,
  "chunkOverlap": 200,
  "pageMarkers": true,
  "outputText": false,
  "maxPagesPerDocument": 500
}
```

# Actor output Schema

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

One row per PDF: Markdown, metadata, page/OCR/table counts, optional plain text and RAG chunks.

## `markdownFiles` (type: `string`):

Full Markdown file per document.

# 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 = {
    "pdfUrls": [
        "https://arxiv.org/pdf/1706.03762"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dofunbiz/pdf-to-markdown").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 = { "pdfUrls": ["https://arxiv.org/pdf/1706.03762"] }

# Run the Actor and wait for it to finish
run = client.actor("dofunbiz/pdf-to-markdown").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 '{
  "pdfUrls": [
    "https://arxiv.org/pdf/1706.03762"
  ]
}' |
apify call dofunbiz/pdf-to-markdown --silent --output-dataset

```

## MCP server setup

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

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/3lpKuTJ8c8okJzkZd/builds/8BifxV0c9WjUslRQl/openapi.json
