# PDF Text and Markdown Extractor (`fetch_cat/pdf-text-markdown-extractor`) Actor

Extract public PDF URLs into clean text, Markdown, page content, OCR state, and document metadata for AI and automation workflows.

- **URL**: https://apify.com/fetch\_cat/pdf-text-markdown-extractor.md
- **Developed by:** [Hanna Nosova](https://apify.com/fetch_cat) (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 $2.40 / 1,000 pdf processeds

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?

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: Text and Markdown from Public PDFs

PDF Text and Markdown Extractor turns public PDF links into clean text, pragmatic Markdown, page-level content, and document metadata. Use this **PDF text extractor** when you need a repeatable dataset for RAG, AI agents, search, research, or document automation.

Provide one or more direct public PDF URLs. Each URL becomes one dataset row, including an explicit failure row when a download or document cannot be read. That makes batch workflows easier to retry without losing successful documents.

### What you get

Successful rows can contain:

- Full extracted text for indexing or analysis.
- LLM-ready Markdown for chunking and retrieval workflows.
- Selected page-level text, Markdown, OCR state, and warnings.
- PDF metadata such as title, author, subject, creator, producer, and dates.
- Character and word counts for quick filtering.
- Clear `success`, `partial`, or `failed` status with an error when applicable.

### Who is it for?

Use this Actor if you work with public reports, research papers, manuals, invoices, policy documents, or document archives and need structured text without manually copying from a PDF viewer.

- **AI and RAG teams:** prepare PDF text and Markdown for retrieval pipelines.
- **Researchers:** batch extract papers and reports for search or analysis.
- **Operations teams:** turn public manuals or compliance documents into usable records.
- **Developers:** call a PDF to Markdown workflow from the Apify API or an MCP client.

### Input recipes

#### Extract text and Markdown from one PDF

```json
{
  "pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],
  "includeMarkdown": true,
  "includePages": true,
  "maxPages": 20
}
```

#### Extract selected pages only

```json
{
  "pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],
  "pageRange": "1-3,5",
  "includeMarkdown": true,
  "includePages": true
}
```

#### Use OCR for a scanned PDF

```json
{
  "pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],
  "enableOcr": true,
  "ocrLanguage": "eng",
  "maxPages": 10
}
```

### Example output

```json
{
  "sourceUrl": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
  "fileName": "dummy.pdf",
  "status": "success",
  "pageCount": 1,
  "extractedPageCount": 1,
  "metadata": { "title": null, "author": null },
  "text": "…",
  "markdown": "…",
  "pages": [{ "page": 1, "text": "…", "markdown": "…", "ocrApplied": false, "warnings": [] }],
  "ocr": { "enabled": false, "language": null, "pagesOcred": 0 },
  "charCount": 123,
  "wordCount": 20,
  "warnings": []
}
```

### Input settings

| Input | Description |
|---|---|
| `pdfUrls` | One to 50 direct, public HTTP(S) PDF URLs. |
| `pageRange` | Optional 1-indexed range such as `1-3,5,8-`. |
| `includeMarkdown` | Creates a Markdown rendition from extracted text. |
| `includePages` | Includes selected per-page text, Markdown, and OCR state. |
| `enableOcr` | Attempts OCR for selected pages with no usable text layer. |
| `ocrLanguage` | Tesseract language code used when OCR is enabled. |
| `maxPages` | Per-document page limit; use a low value for a fast first run. |
| `maxConcurrency` | Number of PDF URLs handled in parallel (1–5). |
| `maxPdfSizeMb` | Rejects larger downloads before parsing. |

### Output fields

| Field | Description |
|---|---|
| `sourceUrl`, `fileName` | Requested URL and resolved file name. |
| `status`, `error`, `warnings` | Explicit success, partial, or failed lifecycle state. |
| `pageCount`, `extractedPageCount` | Total PDF pages and selected pages handled. |
| `metadata` | PDF title, author, subject, keywords, creator, producer, and dates when embedded. |
| `text`, `markdown`, `pages` | Full text, Markdown, and selected page-level content. |
| `ocr` | OCR setting, language, and number of OCRed pages. |
| `charCount`, `wordCount`, `processedAt` | Local output measurements and completion timestamp. |

### PDF to Markdown for AI workflows

PDF layouts do not reliably carry semantic structure, so Markdown is a practical text rendition rather than a visual reconstruction. Keep `includePages` on when an agent needs page context, and use `pageRange` to limit long documents before sending content to a model or vector store.

For scanned documents, enable OCR only when needed. This PDF OCR API option adds processing time but can recover readable text from pages without a native text layer.

### Pricing and limits

A valid run has a small start charge and each successfully processed PDF is charged once. See the [live Pricing tab](https://apify.com/fetch_cat/pdf-text-markdown-extractor/pricing) for current rates and tier discounts before a large batch.

This version accepts up to 50 public URLs and applies your configured page and file-size limits. It never bypasses logins, paywalls, password protection, or access controls. Use direct PDF download links rather than viewer pages.

### API usage

Run the Actor with the Apify API and read the default dataset for one row per URL.

#### cURL

```bash
curl "https://api.apify.com/v2/acts/fetch_cat~pdf-text-markdown-extractor/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pdfUrls":["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],"includeMarkdown":true}'
```

#### Node.js

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/pdf-text-markdown-extractor').call({
  pdfUrls: ['https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'],
  includeMarkdown: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("fetch_cat/pdf-text-markdown-extractor").call(run_input={
    "pdfUrls": ["https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"],
    "includeMarkdown": True,
})
print(client.dataset(run["defaultDatasetId"]).list_items().items)
```

### MCP and agent use

Use the same input in an MCP-enabled agent through the Apify MCP server: [open this Actor's tools](https://mcp.apify.com/?tools=fetch_cat/pdf-text-markdown-extractor). The result dataset provides text, Markdown, pages, and status fields for the next step in an automated workflow.

For Claude Code, add the scoped server with:

```bash
claude mcp add apify-pdf-text -- npx -y @apify/actors-mcp-server --tools fetch_cat/pdf-text-markdown-extractor
```

For a JSON MCP client configuration:

```json
{
  "mcpServers": {
    "apify-pdf-text": {
      "command": "npx",
      "args": ["-y", "@apify/actors-mcp-server", "--tools", "fetch_cat/pdf-text-markdown-extractor"]
    }
  }
}
```

Example prompts: “Extract the first five pages from this public PDF as Markdown” and “Run the PDF text extractor, then summarize only rows where status is success.”

### FAQ

**What data can I export with pdf text extractor?** You can export full text, Markdown, selected pages, OCR state, metadata, counts, warnings, and an explicit status for every requested URL.

**Can I run PDF Text and Markdown Extractor through an API, schedule, or MCP client?** Yes. The same JSON input works with the Apify API, scheduled Actor runs, and an MCP-enabled client.

**How much does it cost to use PDF Text and Markdown Extractor?** Pricing is per valid run and successfully processed PDF. See the live Pricing tab for current tier rates.

**Can it read scanned PDFs?** Yes. Enable `enableOcr`; pages without usable native text are sent to local OCR.

**What happens when one URL fails?** It receives a `failed` row while the remaining public URLs continue.

**Can I upload a private file or password?** No. This version deliberately supports public PDF URLs only.

### Tips

- Start with one direct URL and a low `maxPages` value to verify the output shape.
- Use `pageRange` for large documents when only a chapter or appendix matters.
- Preserve `sourceUrl` and `processedAt` when loading results into a downstream dataset.
- Filter on `status` before sending content into a production AI workflow.

### Related Actors

- [arXiv Paper Search Scraper](https://apify.com/fetch_cat/arxiv-paper-search-scraper)
- [Google Search Results Scraper](https://apify.com/fetch_cat/google-search-results-scraper)
- [Google Images Scraper](https://apify.com/fetch_cat/google-images-scraper)
- [Bulk URL Status Checker](https://apify.com/fetch_cat/bulk-url-status-checker)
- [Web Page to Markdown Extractor](https://apify.com/fetch_cat/web-page-to-markdown-extractor)

### Support

For a reproducible problem, include the public URL, input options, and the error row when opening an issue on the Actor page.

# Actor input Schema

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

Direct public HTTP(S) links to PDF files. Private, password-protected, and viewer-page URLs are not supported.

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

Optional 1-indexed range, such as 1-3, 5, or 8-.

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

Create LLM-ready Markdown from the extracted text.

## `includePages` (type: `boolean`):

Include the selected pages with text, Markdown, and OCR state.

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

Use local OCR only when a selected page has no usable text layer.

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

Tesseract language code used only when OCR is enabled.

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

Stop after this many selected pages to keep runs bounded.

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

Number of public URLs processed at once.

## `maxPdfSizeMb` (type: `integer`):

Reject larger downloads before parsing.

## Actor input object example

```json
{
  "pdfUrls": [
    "https://www.orimi.com/pdf-test.pdf"
  ],
  "includeMarkdown": true,
  "includePages": true,
  "enableOcr": false,
  "ocrLanguage": "eng",
  "maxPages": 20,
  "maxConcurrency": 2,
  "maxPdfSizeMb": 25
}
```

# Actor output Schema

## `overview` (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 = {
    "pdfUrls": [
        "https://www.orimi.com/pdf-test.pdf"
    ],
    "pageRange": "",
    "includeMarkdown": true,
    "includePages": true,
    "enableOcr": false,
    "ocrLanguage": "eng",
    "maxPages": 20,
    "maxConcurrency": 2,
    "maxPdfSizeMb": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetch_cat/pdf-text-markdown-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 = {
    "pdfUrls": ["https://www.orimi.com/pdf-test.pdf"],
    "pageRange": "",
    "includeMarkdown": True,
    "includePages": True,
    "enableOcr": False,
    "ocrLanguage": "eng",
    "maxPages": 20,
    "maxConcurrency": 2,
    "maxPdfSizeMb": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("fetch_cat/pdf-text-markdown-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 '{
  "pdfUrls": [
    "https://www.orimi.com/pdf-test.pdf"
  ],
  "pageRange": "",
  "includeMarkdown": true,
  "includePages": true,
  "enableOcr": false,
  "ocrLanguage": "eng",
  "maxPages": 20,
  "maxConcurrency": 2,
  "maxPdfSizeMb": 25
}' |
apify call fetch_cat/pdf-text-markdown-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetch_cat/pdf-text-markdown-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/4QpHVhrVdrw4S1m8C/builds/9MpaHvkayJuGwE8bZ/openapi.json
