Skip to content
Tidewell Software
Document to Markdown

Scanned PDF to Markdown with OCR

OCR scanned PDFs and page images to Markdown in 25 languages. Pages with text skip OCR.

Steps

  1. Get an API token. Apify Console → Settings → API & Integrations. Export it as APIFY_TOKEN.
  2. Install the client. pip install apify-client
  3. Add the scans. PDF, PNG, JPEG, TIFF or WebP URLs in fileUrls.
  4. Set the languages. ocrLanguages, e.g. ["eng", "deu"].
  5. Check the result. ocr_confidence per document; read markdown.

Input

input.json
{
  "fileUrls": ["https://archive.org/download/literarylapses00leacuoft/page/n13_w1000.jpg"],
  "ocrLanguages": ["eng"]
}

Run it

run.py
import os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("tidewell/doc-to-markdown").call(run_input={
    "fileUrls": [
        "https://archive.org/download/literarylapses00leacuoft/page/n13_w1000.jpg"
    ],
    "ocrLanguages": ["eng"]
})

for doc in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(doc["ocr_pages"], doc["ocr_confidence"])
    print(doc["markdown"])

Output

Input: page 12 of Literary Lapses (1910), from the Internet Archive. Run on 9 November 2026: 1 OCR page, $0.005 at list price.

Dataset row (trimmed)
{
  "doc_id": "doc-0001",
  "status": "succeeded",
  "source_url": "https://archive.org/download/literarylapses00leacuoft/page/n13_w1000.jpg",
  "file_type": "jpeg",
  "pages": 1,
  "ocr_pages": 1,
  "ocr_confidence": 93.9,
  "word_count": 195,
  "token_count": 243,
  "markdown": "Interary Lapses\n\npoked the ball of money at him with a quick convulsive movement as if I were doing a conjuring trick.\n\nMy face was ghastly pale.\n\n“Here,” I said, “ deposit it.” The tone of the words seemed to mean, “Let us do this painful thing while the fit is on us.”\n\nHe took the money and gave it to another clerk.\n\nHe made me write the sum on a slip and sign my name in a book. I no longer knew what I was doing. The bank swam before my eyes.\n\n“Is it deposited?” I asked in a hollow, vibrating voice.\n\n“ Tt is,” said the accountant.\n\n“Then I want to draw a cheque.”\n\nMy idea was to draw out six dollars of it for present use. Someone gave me a chequebook through a wicket and someone else began telling me how to write it out. The people in the bank had the impression that I was an invalid millionaire. I wrote something on the cheque and thrust it in at the clerk. He looked at it.\n\n“‘ What! are you drawing it all out again ? ” he asked in surprise. Then I realized that I\n\n32\n"
}

Options

ocrLanguages
eng, deu, fra, spa, ita, por, nld, pol, jpn, chi_sim and 15 more; combine them
forceOcr
OCR every page, for PDFs with a broken text layer
ocrDpi
Render resolution, 300 by default
Mixed PDFs
Pages with a text layer are read directly and billed as text pages

Use it from Claude or ChatGPT

Apify MCP server, this actor only
https://mcp.apify.com/?tools=tidewell/doc-to-markdown
Claude
Settings → Connectors → Add custom connector. Paste the URL, sign in to Apify
Claude Code
claude mcp add apify "https://mcp.apify.com/?tools=tidewell/doc-to-markdown" -t http
ChatGPT
Add a custom MCP server with the URL and OAuth
Then ask
Use tidewell/doc-to-markdown to OCR this scanned German letter (ocrLanguages: deu) and translate it to English.

Pricing

Pay per event, from the actor's live pricing on 9 November 2026.

Price
$0.002 per document + $0.0003 per page. OCR pages +$0.0027.
Free
Failed, encrypted, empty and unsupported files