Dev48
Language
  • About
  • Services
  • Industries
  • Technologies
  • Articles
  • Contacts
Book a call
    Home/Articles/Best ocr model for scanned documents measured
Dev48
info@dev48.org+375 29 320-40-96WhatsApp@isky_by

© 2026 · All rights reserved.

Best OCR Model for Scanned Documents, Measured

Source: OpenRouter Blog•November 10, 2026 at 06:16 PM

Best OCR Model for Scanned Documents, Measured

We made eight scanned pages from text we wrote, ran them through 15 vision models, Mistral OCR and Tesseract, and checked every value. Claude Opus 5.5 was the most accurate and Mistral OCR the best value.

Turning scanned documents into reliable text is hard. Classic OCR engines such as Tesseract fail on faded print, handwriting and faxes. Vision models read those pages well, but sometimes write values that aren’t on the page. We made eight test pages from text we wrote, so every character could be checked, and ran them through 15 vision models and Mistral OCR on OpenRouter, plus Tesseract.

The best OCR model in our test was Claude Opus 5.5, with 262 of 264 key values right at $16.42 per 1,000 pages. Mistral OCR was the best value: 258 of 264 for $2.02. This post shows the results, the errors to watch for, and code to catch them.

These results are a starting point. Our eight pages aren’t your documents, so the only real way to know which model is best for your workflow is to test the candidates on your own scans.

Tl;dr

  • Most accurate: anthropic/claude-opus-5.5. Best value: mistral-ocr. Cheapest good result: inclusionai/ling-3.0-flash-vl with reasoning off, 254 of 264 for $0.04 per 1,000 pages.
  • On a faded receipt, GPT-6 Luna and GPT-6.1 Sol made up card digits, wifi passwords and a server name. Error rates don’t show this, so check the values you’ll actually use.
  • Turning reasoning off made four of five models we tested faster and cheaper, with no key values lost.
  • Flagging the words where two cheap models from different labs disagreed caught 34 of 35 wrong words, for $0.62 per 1,000 pages.

How we tested

We rendered each page from known text, then degraded it like a scan: a small rotation, blur, noise and JPEG compression. Five pages are ordinary: a receipt, a letter with two deliberate misspellings, a form with a ticked box, a two-column newsletter and a neat handwritten note. Three are built to be hard: a faded thermal receipt, fast cramped handwriting, and a low-resolution fax of 12 serial numbers made from look-alike characters (0/O, 1/I/L, 5/S, 8/B), so a model can’t guess them from context.

We scored each transcript two ways. The character error rate (CER) is the edit distance to the true text divided by its length, ignoring line breaks and Markdown. The key values are 88 strings a pipeline would use, 10 to 15 per page, such as totals, dates, card digits, serials and the misspelled words. Each has to appear exactly in each of three runs, which gives 264 checks per model. Costs are the billed usage.cost of each request. Models are from the OpenRouter catalog as of October 8, 2026.

Which OCR model is most accurate on scanned documents?

The table is sorted by key values correct.

On the five ordinary pages every vision model scored under 0.3% CER, and all 15 transcribed the neat handwriting perfectly. Most of the spread comes from the faded receipt. Opus 5.5 and Mistral OCR got all 33 checks on it, while GPT-6 Luna got 16. Models count image tokens differently (a median page was 1,070 prompt tokens for DeepSeek and 3,314 for Grok), so measure cost on your own pages.

Which OCR model fits your work

What goes wrong when a vision model reads a hard scan?

The most serious error was a value that looks plausible but isn’t on the page. Here’s the bottom of the faded receipt as printed, followed by one GPT-6 Luna run:

There’s no NET line on the receipt. The card ends in 9026, and the name and password are invented. GPT-6 Luna changed the server’s name and the year in all three runs. GPT-6.1 Sol wrote a different made-up password in each run (flatwhite24, flat9am!, flatleaf). We also asked models to write [?] instead of guessing. It didn’t help: four of seven models never used the marker.

The other errors that repeated:

  • O and 0: Two fax serials were wrong in at least one run from 13 of the 15 models. Only Claude Sonnet 5.5 and GPT-6.1 Sol read them correctly every time.
  • Spelling fixes: The letter is signed “Senior Assosiate”, and the prompt says to copy spelling exactly. 16 of 45 transcripts “corrected” it anyway.
  • Ticked boxes: Claude Sonnet 5.5 and Haiku 5.5 copied the form’s checkbox labels but dropped which box was ticked.

Step 1: Send the scan to a vision model

A vision model generates its transcript the same way a language model generates any text, so it tends to write what text usually says rather than exactly what’s printed. The prompt asks it to copy exactly. That reduces the problem but doesn’t remove it: 16 of 45 transcripts still corrected the letter’s deliberate misspelling. You need an OpenRouter API key in OPENROUTER_API_KEY. The image goes in as a base64 image_url part (see image inputs), so every vision model on OpenRouter takes this same request. Save it as transcribe.py, since steps 3 and 4 import from it:

Every character came back right, for about two hundredths of a cent. The data URL takes its type from the file extension, so PNG and WebP scans work too. To compare models, change only the model string, and pass reasoning=None for the models in step 2 that can’t turn reasoning off.

The finish_reason check is there because reasoning tokens count against max_tokens. With a limit of 4,000, Gemini 3.8 Flash spent 3,841 tokens reasoning about the fax on every run and stopped partway through serial number 4. The request still returned 200 OK with finish_reason: "length", so without the check a pipeline stores short transcripts without noticing.

Step 2: Turn reasoning off for transcription

Reasoning helps when a model has to plan an answer. Copying text from a page doesn’t need a plan, so the extra tokens mostly add cost and time. That’s why transcribe sends "reasoning": {"effort": "none"} by default (see reasoning tokens). We reran the full test with reasoning off for every model that allows it:

With reasoning on, one Mistral Large 4 request reasoned for 626 seconds and returned no text (finish_reason: "error"). Qwen3.8 27B did better with reasoning on, so test your own pages. Gemini 3.8 Flash, Grok 4.7 and GLM 5.3 FlashX don’t allow reasoning to be turned off, so pass reasoning=None to leave the field out. Otherwise the request fails with:

Step 3: Cross-check two models from different labs

Look-alike characters such as O and 0 are hard to tell apart in a blurry image. Each model decides based on its own training, so two models from different labs rarely make the same wrong choice. Where their transcripts differ is usually where the image is unclear. We tested every pair among six models. The best was Claude Haiku 5.5 checked by DeepSeek V4.1 Flash. Haiku made 35 word errors in 2,964 words, and DeepSeek, with reasoning off as in step 2, disagreed on 34 of them, with 10 false alarms. The pair costs $0.62 per 1,000 pages, a third of Mistral OCR. Both use the same API, so the check is one extra call. Haiku is called with reasoning=None because that’s how it ran in our table:

Those are the two serials most models got wrong. If both models misread a character the same way, nothing is flagged. That happened once in our runs, with an O both read as a zero, so validate IDs against a list or a checksum where you can. The comparison also assumes both models read the page in the same order. In one of three runs the models listed the fax’s two columns in different orders, and every serial showed up as a disagreement.

Step 4: Use Mistral OCR as a dedicated engine

Mistral OCR is a model trained only for document OCR. On OpenRouter it runs as an engine in the file-parser plugin, which accepts PDFs, at $2 per 1,000 pages. The plugin OCRs the file before your model sees it. It returns the text as a file annotation on the response, so the model you name only has to reply. Wrap the scan in a one-page PDF and send it with any cheap model:

Every value on the faded receipt came back right, including the card digits and password. Mistral OCR is built to keep layout, so its output is Markdown: receipt lines become tables, headings get ##, and & comes back as &. That’s why the function unescapes the HTML entities. Strip the Markdown if you need plain text, or keep it if an LLM reads the result next.

Is an LLM better than Tesseract for OCR?

Yes, except on clean typed pages. Tesseract 5.5 reads character shapes line by line, so it holds up on crisp print and breaks down on noise and handwriting. It transcribed the letter and the newsletter perfectly. It returned nothing for the faded receipt, 1 of 11 values on the messy handwriting and 4 of 15 on the fax.

Frequently asked questions

Which LLM is best for OCR?

Claude Opus 5.5 in our test. Gemini 3.8 Flash and Grok 4.7 had error rates almost as low but missed more serials. DeepSeek V4.1 Flash and Ling 3.0 Flash VL came close for under $0.20 per 1,000 pages.

How do I OCR a scanned PDF?

Send it with the mistral-ocr engine as in step 4. Alternatively, render each page to an image for a vision model, or send the PDF directly to a model that reads PDFs. A free text parser won’t work on a scan, because a scan has no text layer.

What is the most accurate OCR model?

Claude Opus 5.5 got 262 of 264 key values right and had a 0.02% character error rate across our eight scans. Mistral OCR was second with 258 of 264, at an eighth of the cost.

How much does OCR with an LLM cost?

In our test it ran from $0.04 per 1,000 pages (Ling 3.0 Flash VL with reasoning off) to $16.42 (Claude Opus 5.5). Mistral OCR costs $2 per 1,000 pages. Models count image tokens differently, so measure cost on your own pages.

Is Mistral OCR better than a vision model?

It was the best value in our test: 258 of 264 key values for $2.02 per 1,000 pages, behind only Claude Opus 5.5. It returns Markdown that keeps the layout, while a vision model returns whatever format you ask for.

Can an LLM read handwriting?

Yes. All 15 vision models transcribed our neat note perfectly. On messy handwriting most stayed above 99% character accuracy, and the misses were mostly names (“Ackterberg” for “Achterberg”).

Next steps

  • Image inputs covers sending images by URL or base64, and our vision API guide covers detail levels.
  • PDF inputs lists the PDF engines and explains how to reuse parsed results.
  • The vision models collection lists every model that takes images.
  • To turn a transcript into typed fields, see structured outputs.
← All articles

What this article says

More in AI & Machine Learning

All →
Donating KubeRay to the CNCF
Anyscale

Donating KubeRay to the CNCF

Cogent and OpenAI build cyber defense factories for enterprises
OpenAI

Cogent and OpenAI build cyber defense factories for enterprises

ChatGPT Plus for veterans and servicemembers
OpenAI

ChatGPT Plus for veterans and servicemembers

BotPsy: On-Device Personal Assistant with a Sub-Billion-Parameter Agentic Language Model
Hugging Face

BotPsy: On-Device Personal Assistant with a Sub-Billion-Parameter Agentic Language Model

OpenAI, Anthropic face new oversight as New York’s AI safety law takes effectПресса
OpenAI

OpenAI, Anthropic face new oversight as New York’s AI safety law takes effect

How AI Helps Recyclers Turn Mixed Waste Into Reusable Material
NVIDIA

How AI Helps Recyclers Turn Mixed Waste Into Reusable Material

More from OpenRouter

MCP vs CLI vs Skills: What Each Costs in Context
OpenRouter

MCP vs CLI vs Skills: What Each Costs in Context

LLM Quantization: What fp8 and fp4 Do to Quality and Price
OpenRouter

LLM Quantization: What fp8 and fp4 Do to Quality and Price

LLM API Rate Limits: How to Fix OpenAI and Claude 429 Errors
OpenRouter

LLM API Rate Limits: How to Fix OpenAI and Claude 429 Errors

How to Get Structured Output from Any LLM: JSON Schema, Tool Calls, or a Decision Model
OpenRouter

How to Get Structured Output from Any LLM: JSON Schema, Tool Calls, or a Decision Model

How to Build a Voice AI Agent
OpenRouter

How to Build a Voice AI Agent

How Sentry Capped Runaway AI Bills Without Restricting Access
OpenRouter

How Sentry Capped Runaway AI Bills Without Restricting Access