PDF to Markdown + OCR — Structured Document Extraction
Pricing
from $1.00 / 1,000 native text pages
PDF to Markdown + OCR — Structured Document Extraction
Convert public PDF URLs into clean structured Markdown. Born-digital pages extract natively; scanned or image-only pages are recovered by a built-in OCR engine — no key or setup required. Per-page mode, confidence and partialFailures for PDF to Markdown and scanned PDF extraction pipelines.
Pricing
from $1.00 / 1,000 native text pages
Rating
0.0
(0)
Developer
Heim AI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Public PDF URL in → structured Markdown out. Born-digital pages extract natively; scanned / image-only pages go through a managed OCR engine. Built for PDF to Markdown, PDF OCR API, scanned PDF extraction, and structured document data pipelines (MCP / API / schedule).
| Actor id | kaz_kakyo/pdf-structured-ocr |
| Minimal input | { "pdfUrls": ["https://…/file.pdf"] } |
| Cost | $0.001/native page · $0.012/OCR page · $0.005/document manifest · $0.00005 start |
| Output | type: "page" rows + one type: "manifest" per document (or type: "error") |
Call it (MCP / API)
{"actor": "kaz_kakyo/pdf-structured-ocr","input": {"pdfUrls": ["https://example.com/report.pdf"],"ocr": "auto"}}
OCR is included — no setup, no key required. Native-text pages always succeed; if a page needs OCR and OCR capacity is unavailable, it is marked mode: "unavailable" and listed in partialFailures. Very large or image-heavy pages may return unavailable rather than being silently truncated. Billed only for pages actually delivered.
Because OCR capacity is shared across all users, each run caps OCR-billable pages (maxOcrPages, default 100, hard ceiling 200). Native (born-digital) extraction is unaffected by the cap and consumes no OCR capacity.
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('kaz_kakyo/pdf-structured-ocr').call({pdfUrls: ['https://example.com/report.pdf'],ocr: 'auto',ocrMaxWaitSecs: 300,maxPages: 50,},{ maxTotalChargeUsd: 1.0 },);const { items } = await client.dataset(run.defaultDatasetId).listItems();const manifest = items.find((i) => i.type === 'manifest');
Output contract
Page row (charged only when mode is native or ocr):
{"type": "page","url": "https://example.com/report.pdf","pageNumber": 1,"mode": "native","confidence": null,"markdown": "## Introduction\n\n…","textCharCount": 1842}
mode | Meaning |
|---|---|
native | Born-digital text extracted locally |
ocr | Page recovered by the managed OCR engine |
unavailable | Needed OCR but capacity unavailable / OCR failed / budget exhausted — never charged |
Manifest (charged only when ≥1 page was delivered):
{"type": "manifest","url": "https://example.com/report.pdf","pageCount": 12,"pagesDelivered": 12,"markdown": "<!-- page 1 (native) -->\n\n…","pages": [{ "pageNumber": 1, "mode": "native", "confidence": null }],"partialFailures": []}
Pricing
| Event | Price | When |
|---|---|---|
native-page-delivered | $0.001 | Each saved native-text page |
ocr-page-delivered | $0.012 | Each saved OCR page |
document-manifest-delivered | $0.005 | Final manifest, only if ≥1 page delivered |
apify-actor-start | $0.00005 | Per run |
| Default dataset item | $0 | Never billed separately |
Charge order: budget-check → save dataset row → Actor.charge(). Unavailable / error rows are never billed. Cap spend with maxTotalChargeUsd.
Input
| Field | Notes |
|---|---|
pdfUrls / pdfUrl | Public http(s) PDF links only |
maxPages | Default 50 (hard cap 500) |
ocr | auto (default) · never · always |
maxOcrPages | Default 100 (hard ceiling 200); per-run OCR page cap |
ocrMaxWaitSecs | Default 300 (max 900); OCR timeout → ocr_timeout, uncharged |
Private / localhost / link-local / RFC1918 targets are rejected (SSRF guard, enforced at connect time and on every redirect hop). File size cap: 50 MB, enforced while streaming. PDFs are fetched over direct egress only — no proxy, because a proxy cannot enforce the connect-time address ACL. OCR processes the already-fetched PDF bytes; the source is never re-fetched.
Why this one
- Structured Markdown, not a blob of OCR text — headings and crude tables from layout when native text exists.
- Page-level honesty: every page reports
mode+confidence; gaps go inpartialFailures. - OCR only when needed (
auto) so born-digital PDFs stay cheap. - Billed only for pages actually delivered — timeouts, failures, and capacity limits never charge OCR pages.