sfoln/pdf-ocr-markdown · AI, Developer tools, Automation On request
Convert PDFs, scans and images to Markdown with Mistral OCR, tables and layout preserved. Born-digital PDF pages are read from their text layer for $1 per 1,000 pages; only scanned pages are OCR'd ($7 per 1,000). Per-page output.
Turn PDFs, scanned documents, slides and images into clean, structured Markdown, headings, lists, tables and reading order preserved, ready for RAG pipelines, LLM prompts, search indexing or data extraction. Paste document URLs, get one record per document with the full Markdown plus per-page text, character counts and (optionally) the embedded images. Scans and images are read by Mistral OCR, a document-understanding model that handles multi-column layouts, tables, handwriting and 40+ languages; PDF pages that already contain text are read straight from the PDF's text layer, at a seventh of the price.
Price
Price per delivered record
Event
Price
Per 1,000
Charged for
OCR page ocr-page
$0.007
$7 / 1,000
Charged once per page processed by Mistral OCR: scanned PDF pages, images, DOCX/PPTX pages, or every page with forceOcr.
Text-layer page pdf-text-page
$0.001
$1 / 1,000
Charged once per PDF page read from the PDF's own text layer (born-digital or blank pages, hybrid mode): no OCR needed.
Apify free plan: up to 5 items per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.
Run
Call it from code, an agent or the Console
This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com
POST https://api.apify.com/v2/actors/sfoln~pdf-ocr-markdown/runs?maxTotalChargeUsd=1
GET https://api.apify.com/v2/actor-runs/{runId} # until status is SUCCEEDED
GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json
Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted.
Input
Input fields
List publicly reachable document or image URLs. Each document produces one dataset record with its Markdown and per-page details.
Field
Type
Default
Meaning
documentUrls *
array
required
Document URLs Public URLs of PDFs, images (PNG, JPG, WEBP, TIFF, …) or office documents (DOCX, PPTX), one per line, max 50 MB each. PDF pages that have a text layer are read directly ($0.001 per page); scanned pages, images and office files are OCR'd ($0.007 per page). Apify key-value store record URLs work if the store is publicly readable. Accounts on the Apify free plan can process up to 5 documents per run, with at most 5 pages per document.
maxPagesPerDocument
integer
50
Max pages per document Only the first N pages of each document are processed (and charged). Range 1–1000.
includeImages
boolean
false
Extract embedded images Save images detected on the pages (figures, photos, logos) to the run's key-value store and return their URLs per page. Images come from OCR, so every page is OCR'd when this is on.
forceOcr
boolean
false
OCR every page Send every PDF page to Mistral OCR, also pages that have a text layer (charged as ocr-page). Use it when you need OCR's layout and table reconstruction on born-digital pages too; images always need it.
maxDocuments
integer
100
Max documents Safety cap on the number of documents processed in this run. Range 1–10000.
concurrency
integer
2
Concurrency Documents processed in parallel. Range 1–5.
includeRaw
boolean
false
Include raw upstream response Attach the unmodified OCR response (without image data) to each record.
Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.
Field
Type
Meaning
input
string
Input URL as submitted.
url
string
URL Normalized document URL.
documentType
string
Document type document (PDF, DOCX, PPTX, …) or image.
mode
string | null
Mode hybrid: PDF pages with a text layer read directly, only scanned pages OCR'd; ocr: every page OCR'd (images, office files, forceOcr, includeImages, or a PDF whose text layer could not be read).
pageCount
integer
Pages returned Pages returned.
totalPages
integer | null
Pages in the PDF Hybrid mode: the PDF's page count.
pagesProcessed
integer
Pages processed Pages processed: OCR'd by Mistral, or read from the text layer (hybrid).
pagesCharged
integer
Pages charged Pages charged (ocr-page and pdf-text-page); exactly these pages are returned.
ocrPagesCharged
integer | null
OCR pages charged ocr-page events for this document.
textPagesCharged
integer | null
Text-layer pages charged pdf-text-page events for this document.
textLayerPages
array | null
Text-layer pages Hybrid mode: page numbers read from the PDF's text layer.
ocrPages
array | null
OCR pages Hybrid mode: page numbers sent to OCR.
pageLimit
integer
Page limit applied
possiblyTruncated
boolean
Possibly truncated The page limit was reached; the document may have more pages.
markdown
string
Markdown All pages joined, separated by <!-- page N --> comments.
markdownUrl
string | null
Full Markdown URL Set only when the record would exceed ~6 MB: the full Markdown is in the key-value store, `markdown` keeps the first 1 MB.
PDF pages that already contain text (exported from Word, LaTeX or a browser) are read straight from the PDF's text layer and cost $0.001 (pdf-text-page). Only pages without a usable text layer, such as scans and photos, are sent to Mistral OCR and cost $0.007 (ocr-page). Set forceOcr to OCR every page.
Does it handle tables and multi-column layouts?
OCR pages keep tables as Markdown tables and follow the reading order of multi-column layouts. Text-layer pages rebuild headings, lists and simple tables from the PDF's layout; use forceOcr when you need OCR's reconstruction on every page.