# PDF, Audio & Video to Markdown: OCR + Transcripts (`benexe/pdf-to-markdown-ocr`) Actor

PDFs, scans, audio and video to clean, LLM-ready Markdown: tables preserved, auto OCR, timestamped transcripts with SRT/VTT subtitles (Whisper), video keyframes, RAG chunks. Pay per page or minute.

- **URL**: https://apify.com/benexe/pdf-to-markdown-ocr.md
- **Developed by:** [Marcel Tomas](https://apify.com/benexe) (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 $0.60 / 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.
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, Audio & Video to Markdown: OCR + Transcripts

**Turn PDFs, scans, recordings and videos into clean, LLM-ready Markdown — from $1 per 1,000 pages and $0.48 per hour of audio.**

Feed your AI agents, RAG pipelines and automations with text they can actually use, from one Actor:

- **PDFs and images:** text pages are read directly from the PDF (fast and exact); **scanned pages and images are OCR'd automatically, only where needed**, so you never pay OCR prices for pages that already contain text.
- **Audio and video:** MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM, MKV → timestamped transcript (Whisper large-v3 turbo, 99+ languages), segments, **SRT/VTT subtitles** and optional **video keyframes** as images.

✅ Headings, lists and tables preserved as Markdown  ✅ Automatic OCR in 9 languages  ✅ Transcripts with timestamps + subtitles  ✅ Keyframes from videos  ✅ Ready-made RAG chunks  ✅ No subscription

### Why this Actor

| | This Actor | Typical PDF extractors |
|---|---|---|
| Price | **$0.001 per text page, $0.003 per OCR page** (lower on paid plans) | $0.003–0.02 per PDF, $0.002–0.015 per OCR page |
| OCR | Only on pages that need it (auto) | Every page, or not at all |
| Output | Markdown with headings, lists, tables, page markers + optional chunks | Plain text |
| Words broken across lines | Re-joined (`custo-`/`mers` → `customers`), real hyphens kept | Left broken |
| Failed files | **Free** | Often charged |
| Transcription | **$0.008 per audio minute** ($0.48/hour), $0.003 with your own Groq key | $0.01–0.04 per minute |

### Example

Input:

```json
{
  "sources": ["https://arxiv.org/pdf/1706.03762"],
  "includeChunks": true
}
```

Output (shortened):

```json
{
  "source": "https://arxiv.org/pdf/1706.03762",
  "status": "ok",
  "pageCount": 15,
  "textLayerPages": 15,
  "ocrPages": 0,
  "markdown": "<!-- page 1 -->\n...\n## Abstract\n\nThe dominant sequence transduction models are based on complex recurrent or convolutional neural networks ...",
  "chunks": [{ "index": 0, "pageFrom": 1, "pageTo": 1, "text": "...", "chars": 1480 }],
  "processingMs": 799
}
```

15 pages in under a second, 35 RAG chunks, cost **$0.015**.

Audio/video input:

```json
{
  "sources": ["https://example.com/podcast-episode-42.mp3"],
  "includeSubtitles": true
}
```

Output (shortened):

```json
{
  "source": "https://example.com/podcast-episode-42.mp3",
  "status": "ok",
  "mediaType": "audio",
  "durationSec": 1834.2,
  "minutesTranscribed": 31,
  "language": "english",
  "markdown": "**[00:00]** Welcome back to the show. Today we talk about ...",
  "segments": [{ "start": 0, "end": 4.2, "text": "Welcome back to the show." }],
  "srt": "1\n00:00:00,000 --> 00:00:04,200\nWelcome back to the show.\n..."
}
```

### Use cases

- **RAG & AI agents:** index reports, manuals, papers and contracts with page-level citations.
- **Invoices, receipts and scans:** get searchable text from scanned PDFs and photos.
- **Podcasts, meetings, webinars, lectures:** transcripts for search, summaries and show notes; subtitles for publishing.
- **Video for AI:** transcript + keyframes give a multimodal model the whole video at a fraction of the cost.
- **Automations:** n8n, Make, Zapier or the Apify API — send a file URL, get Markdown back.
- **MCP tool:** let Claude, ChatGPT or Cursor call it through the Apify MCP server.

### What you get per document

| Field | Meaning |
|---|---|
| `markdown` | The whole document as Markdown, with invisible `<!-- page N -->` markers (optional) |
| `chunks` | Optional: the Markdown split on paragraph/table boundaries (size and overlap configurable), each with its page range |
| `pages` | Optional: raw text per page, the method used (`text-layer`, `ocr`, `empty`) and OCR confidence (0–100) |
| Metadata | File type, size, page count, title, author, creation date |
| Stats | Pages processed, text-layer pages, OCR pages, mean OCR confidence, characters |
| `status` | `ok`, `partial` (page limit or budget reached — you still get what was processed) or `error` (with the reason, not charged) |

For audio and video:
| Field | Meaning |
|---|---|
| `markdown` | Transcript as Markdown, one paragraph per ~minute with `**[mm:ss]**` timestamps |
| `segments` | Sentence-level segments with start/end seconds (on by default) |
| `srt`, `vtt` | Subtitles (turn on *Subtitles*) |
| `keyframes` | Video frames (scene changes or every N seconds) as image URLs in your key-value store, with their timestamps |
| Metadata | Media type, duration, detected language, minutes transcribed |

### Quick start

1. Paste one or more **direct links** to PDF, image (PNG, JPEG, TIFF, WebP, GIF, BMP), audio or video files.
2. Documents: keep **OCR = Auto** and pick the **OCR languages**: English, Spanish, Catalan, French, German, Italian, Portuguese, Dutch, Polish.
3. Audio/video: transcription is on by default and detects the language; set it only if detection struggles. Turn on **Subtitles** or **Keyframes** if you need them.
4. For RAG, turn on **RAG chunks** and choose a chunk size.

### Pricing (pay per event)

| Event | Free plan | Paid plans |
|---|---|---|
| `pdf-page` — page read from its text layer | $0.001 | down to $0.0006 |
| `ocr-page` — scanned page or image processed with OCR | $0.003 | down to $0.0018 |
| `audio-minute` — one started minute of audio transcribed | $0.008 | down to $0.005 |
| `audio-minute-byok` — same, with your own Groq API key | $0.003 | down to $0.002 |
| `keyframe` — one video frame extracted and stored | $0.001 | down to $0.0006 |

That is **$1 per 1,000 text pages**, **$3 per 1,000 OCR pages** and **$0.48 per hour of audio** on the free plan. **Never charged:** files that cannot be downloaded or are not supported. Set a max-charge limit and the run stops cleanly at it, still delivering what was already processed.

Without your own key, free-plan accounts can transcribe up to 30 minutes per run. Add a [Groq API key](https://console.groq.com/keys) to lift the cap and pay the lower `audio-minute-byok` price (Groq bills you for the transcription itself).

### FAQ

**Does it work with scanned PDFs?** Yes. In Auto mode each page is checked: pages with a text layer are read directly, scanned pages are OCR'd at 300 DPI.

**Are my files stored?** Files are downloaded into your run, processed and deleted from the run's temporary disk. Results stay in your own Apify storage. PDFs and images are processed entirely inside the run (no third-party service). For transcription, the audio track is sent to Groq's Whisper API; with your own key, under your Groq account.

**Which languages can be transcribed?** Whisper large-v3 turbo supports 99+ languages and detects the language automatically.

**Long recordings?** Audio is split into 10-minute parts and joined back with continuous timestamps. Default limit 120 minutes per file (`maxMediaMinutes`, up to 600).

**What about tables?** Simple column layouts become Markdown tables. Complex tables (merged cells, rotated text) are kept as text.

**Can I process only some pages?** Yes: set a page range such as `1-5,8,10-`.

**Password-protected PDFs?** They cannot be opened without the password.

**Limits?** Up to 1 GB per file and 2,000 pages per document (defaults: 200 MB, 300 pages).

### Good to know

- **Only direct file links.** Links to YouTube, social networks or other platform pages are rejected. Process only files you have the right to use.
- Transcript quality depends on audio quality; music, cross-talk and heavy accents lower accuracy.
- OCR quality depends on scan quality; use the per-page confidence to spot weak pages.

### Related

- [Sitemap & Indexability Auditor](https://apify.com/benexe/sitemap-indexability-auditor)
- [Core Web Vitals Monitor](https://apify.com/benexe/core-web-vitals-monitor)
- [Website Contact Extractor](https://apify.com/benexe/website-contact-extractor) — emails, phones, socials and company data from any website or Google Maps results; first 25 pages of every run free (launch offer).
- [Instagram Reels & TikTok Transcript](https://apify.com/benexe/reels-tiktok-transcript)
- [AI Image Upscaler](https://apify.com/benexe/ai-image-upscaler)

### Support

Open an issue on the Actor's *Issues* tab with the run ID. Feature requests welcome.

# Actor input Schema

## `sources` (type: `array`):

Direct links to PDF, image (PNG, JPEG, TIFF, WebP, GIF, BMP), audio (MP3, WAV, M4A, OGG, FLAC) or video (MP4, MOV, WebM, MKV) files. Pages of video or social platforms are not supported.

## `ocr` (type: `string`):

Auto runs OCR only where it is needed, which keeps cost low.

## `languages` (type: `array`):

Up to 4 languages present in the documents.

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

For example 1-5,8,10- . Empty = all pages.

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

Pages beyond this limit are skipped (the record is marked partial).

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

Also return the Markdown split into chunks on paragraph/table boundaries, with page numbers.

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

Maximum characters per chunk.

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

Characters repeated from the end of one chunk at the start of the next.

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

Also return the raw text of each page with the method used (text layer or OCR) and OCR confidence.

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

Insert invisible  markers, useful for citations.

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

Rendering resolution for OCR. 300 is a good balance of accuracy and speed.

## `maxFileMb` (type: `integer`):

Files larger than this are skipped (free).

## `transcribe` (type: `boolean`):

Transcribe audio and video files (MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM…) with Whisper large-v3 turbo.

## `transcriptionLanguage` (type: `string`):

Leave empty to detect it automatically. Setting it improves accuracy for short clips.

## `includeSegments` (type: `boolean`):

Return the transcript as segments with start and end times.

## `includeSubtitles` (type: `boolean`):

Also return ready-to-use SRT and WebVTT subtitles.

## `keyframes` (type: `string`):

Extract still frames for vision models. Frames are saved as JPEG in the run's key-value store with public links.

## `keyframeIntervalSec` (type: `integer`):

Used when keyframes = every N seconds.

## `maxKeyframes` (type: `integer`):

Hard cap per video.

## `maxMediaMinutes` (type: `integer`):

Longer recordings are transcribed up to this length (record marked partial).

## `groqApiKey` (type: `string`):

Bring your own key from console.groq.com to pay the lower per-minute price and use your own quota. Stored encrypted; never logged.

## `healthCheck` (type: `boolean`):

Internal. Never charged.

## `healthProfile` (type: `string`):

Internal. Used only together with health check mode.

## Actor input object example

```json
{
  "sources": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ],
  "ocr": "auto",
  "languages": [
    "eng"
  ],
  "maxPagesPerDocument": 300,
  "includeChunks": false,
  "chunkSize": 1500,
  "chunkOverlap": 150,
  "includePages": false,
  "pageMarkers": true,
  "ocrDpi": 300,
  "maxFileMb": 200,
  "transcribe": true,
  "includeSegments": true,
  "includeSubtitles": false,
  "keyframes": "off",
  "keyframeIntervalSec": 10,
  "maxKeyframes": 30,
  "maxMediaMinutes": 120,
  "healthCheck": false
}
```

# Actor output Schema

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

One record per input file: status, pages, OCR stats, metadata, Markdown, optional pages and chunks.

## `markdown` (type: `string`):

The Markdown of each document.

## `runSummary` (type: `string`):

Documents, pages by method, budget and stop reason.

# 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 = {
    "sources": [
        "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("benexe/pdf-to-markdown-ocr").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 = { "sources": ["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("benexe/pdf-to-markdown-ocr").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 '{
  "sources": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
  ]
}' |
apify call benexe/pdf-to-markdown-ocr --silent --output-dataset

```

## MCP server setup

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

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/1cOFVT8GkhLzJ6gA9/builds/zlMjI9PhVsj6b3uZC/openapi.json
