OCRRouterGet API key

Handwritten text recognition: the best OCR for handwriting, tested

We ran a handwritten note through 10 OCR engines. The best read 97% to 99% of the words; Tesseract read 6%. Results, code and how to choose.

Updated

TL;DR

  • On our handwritten note, Jina OCR read 98.9% of words and Mistral OCR 96.8%.
  • Tesseract read 6.4% and EasyOCR 0%: classic engines are not built for joined handwriting.
  • Good models can still 'correct' spelling, which matters for archives.
  • Test 20 to 50 of your own pages; the writer matters as much as the model.

Handwritten text recognition (HTR) is OCR for handwriting. It is much harder than printed OCR because every writer forms letters differently, letters join, and lines drift. The practical answer in 2026: classic OCR engines such as Tesseract are not built for handwriting; modern vision-language OCR models are. On a handwritten English note we tested on November 15, 2026, the best models got 97% to 99% of the words right and Tesseract got 6%.

This post shows that test, the code to repeat it on your own pages, and how to choose a handwriting OCR model.

What makes handwriting hard for OCR

  • No fixed letter shapes. Printed OCR learns a font's letters. Handwriting changes from person to person and even within one page.
  • Joined letters. In cursive, the engine cannot split a word into letters first and then read them one by one.
  • Uneven lines. Lines slope, wander and touch each other, which breaks line detection.
  • Old paper. Historical documents add stains, faded ink and bleed-through.
  • Spelling as written. A good transcription keeps the writer's spelling. A model that "corrects" develope to develop is helpful for search and wrong for archives.

Modern models handle these better because they read whole lines or pages at once instead of single letters. Microsoft's TrOCR paper (Li et al., 2021) is a well-known example of this transformer approach, and most current OCR models build on similar ideas.

Our test: one handwritten note, eight API models, two local libraries

We used a public-domain image from Wikimedia Commons: a handwritten note titled "Aim of Life", 576 x 393 pixels, about 94 words of joined English handwriting on a scanned page. We typed out the text ourselves as the ground truth.

The score is word accuracy: the share of words in our transcription that also appear in the model's output, ignoring case, punctuation and order. It is simple and easy to check, but it is not the character error rate used in research papers, and it does not penalise extra words.

ModelWhere it runsWord accuracy
jina/jina-ocrAPI98.9%
mistral/mistral-ocrAPI96.8%
zai/glm-ocrAPI92.6%
paddle/paddleocr-vlAPI89.4%
aws/textractAPI85.1%
azure/document-intelligenceAPI84.0%
google/document-aiAPI76.6%
PaddleOCR 3.4 (PP-OCRv5, English)Local, CPU44.7%
tesseract/tesseractAPI6.4%
EasyOCR 1.7.2Local, CPU0.0%

One page from one writer. Do not read small gaps (say 92.6% vs 89.4%) as a ranking. Read the big gaps: the vision-language models are in one group, classic engines in another.

We could not include general vision models such as Gemini, GPT and Claude in this run because their upstream provider was unavailable on our side that day. They are often used for handwriting; test them on your own pages.

What the errors look like

The best output, from Mistral OCR, read the whole note, including nomore as written. It did change the writer's develope to develop.

Google Document AI read most lines but mixed in errors like these:

lout to develope it harmoniouty, not to achieve
salvation nereafier, out to make the best useg it
deus crazy or universal brotherhood

The last line should be "democracy or universal brotherhood". These are the errors to look for: a plausible-looking word that is wrong, which a spell-checker will not flag.

EasyOCR returned fragments such as Kanmowions{y and sabvahon, and no complete words from our transcription. Tesseract was similar. Neither is designed for joined handwriting, so this is expected, not a bug in your setup.

Run the same test on your own handwriting

Accuracy depends heavily on the writer, the language and the scan. The only test that matters is one on your own pages. This script sends one image to several models and prints word accuracy for each:

import os, re, sys, requests
from collections import Counter

API = os.environ.get("OCRROUTER_API", "https://api.ocrrouter.ai")
IMAGE = "https://upload.wikimedia.org/wikipedia/commons/d/da/Aim_of_Life_-_Handwritten_note_-_Bhagat_Singh.jpg"

def words(s: str) -> Counter:
    return Counter(re.findall(r"[a-z]+", s.lower()))

def word_accuracy(truth: str, text: str) -> float:
    """Share of the words in `truth` that the OCR output also contains. Case, punctuation and order are ignored."""
    want = words(truth)
    return sum((want & words(text)).values()) / sum(want.values())

truth = open("hw_gt.txt").read()  # our own transcription of the note
for model in sys.argv[1:]:
    r = requests.post(
        f"{API}/v1/ocr",
        headers={"Authorization": f"Bearer {os.environ['OCRROUTER_API_KEY']}"},
        json={"model": model, "file_url": IMAGE, "format": "markdown"},
        timeout=180,
    )
    if not r.ok:
        print(f"{model:<30} error {r.status_code}: {r.text[:120]}")
        continue
    text = r.json()["markdown"]
    print(f"{model:<30} {word_accuracy(truth, text):.1%}")

Usage:

python hw_compare.py jina/jina-ocr mistral/mistral-ocr zai/glm-ocr aws/textract

Replace IMAGE with a link to your own page and hw_gt.txt with your own transcription. One note from our run: Wikimedia sometimes rate-limits downloads, and the API then returns file_fetch_failed with HTTP 429. Upload the file instead ("file_base64") or retry later. Failed requests are not charged.

How to choose the best OCR for handwriting

  1. Start with vision-language OCR models. In our test the four we tried read 89% to 99% of the words; the classic engines read under 50%.
  2. Test 20 to 50 of your own pages. Include your worst writers and your worst scans. Transcribe them once by hand; you will reuse that set for years.
  3. Decide what counts as an error for you. For search, a corrected spelling is fine. For archives and legal records, it is a change to the source.
  4. Check price at your volume. In our table, the top two cost 1 and 6 credits a page (1,000 credits = $1). See each model page for current prices.
  5. Plan for review. Even at 99% word accuracy, a 300-word page has about three wrong words. Use the model's output as a draft for people to correct when the text matters.

Handwriting OCR, ICR and HTR: the same thing?

You will see three names for this job:

  • ICR (intelligent character recognition) is the older term from forms processing. It usually means reading hand-printed capital letters in boxes, one character per box, on forms designed for it.
  • HTR (handwritten text recognition) is the research term for reading free-flowing handwriting, line by line, including cursive.
  • Handwriting OCR is what most people search for, and it covers both.

The difference matters when you read vendor claims. A product that does well on boxed capitals on a tax form may still fail on a doctor's note or a letter. Ask which kind of handwriting a result was measured on.

Scan handwriting so the model has a chance

The model can only read what the image shows. A few habits help every model in our table:

  • Resolution. Scan at 300 dpi or more. With a phone, fill the frame with the page and keep it sharp; a small, blurry page in the middle of a photo gives the model little to work with.
  • Flat and straight. Curved pages from bound notebooks distort lines. Press the page flat or use a scanning app that flattens it.
  • Even light. Shadows across the page can hide faint pencil strokes.
  • Colour, not black and white. Converting to pure black and white can erase light pencil. Send the colour or greyscale image and let the model decide.
  • One page per image. Two pages side by side often get read across the gap, mixing lines from both.

Mixed pages: forms, notes on printed documents, math

Many real documents mix print and handwriting: a printed form filled in by hand, comments on a contract, a signed delivery note. Models that are good at both are the safest choice. For handwritten equations, look at models that output LaTeX; our math OCR page lists them.

For languages other than English, the gap between models is usually larger. Our pages for Chinese, Japanese and Arabic list the models we would try first.

Can I do handwriting OCR offline in Python?

Yes, but expect to do more work. The general-purpose local libraries we tried, PaddleOCR (PP-OCRv5) and EasyOCR, scored 44.7% and 0.0% on our note. Options worth testing are open-weight document models that run locally on a GPU, such as PaddleOCR-VL and GLM-OCR, which scored 89.4% and 92.6% through our API, or a TrOCR model fine-tuned on your own handwriting.

Try it now

Upload a photo of a handwritten page to the free handwriting to text tool, or compare models side by side in the playground. The handwriting OCR page has the API code.

FAQ

Read next