Tools,

Joplin OCR, tested on a real scanned PDF

0

of 1,955 scan words, with one typed page

Get the fix

Plain scans work

OCR is on by default in Joplin desktop 3.7.22. On a 10-page scan:

1,884 of 1,955 words, in order

39 s for 10 pages

The same pages as 300 DPI JPG attachments: 1,876 words in 57 s. To see what Joplin read, right-click the attachment, then View OCR text.

One typed page turns OCR off

Before OCR, Joplin checks the PDF for text. If any page has text, it keeps that text and runs no OCR.

I put a typed cover page in front of the scan. Joplin kept the 13 cover words and read none of the 10 scanned pages.

The fix: Accessible mode or OCRmyPDF

In the settings, set "OCR: PDF processing mode" to Accessible. Then Joplin OCRs every page. Or add a text layer before you attach the file. --skip-text leaves typed pages as they are:

ocrmypdf --skip-text --jobs 2 book.pdf book-ocr.pdf
11 pages, one typed
Setup Scan words Cover words
Normal (default) not read 13
Accessible mode 1,884 13
OCRmyPDF first 1,875 13

Accessible mode took 40 s. For a PDF Joplin already read, right-click it, then Create accessible document, then Run OCR.

German: change Joplin's language

There is no OCR language setting. Joplin uses its display language. I gave it 3 German pages. One is a magazine page with two columns.

3 German pages
Joplin language Umlauts, of 206 Two columns, of 972
English 0 420
German 146 497

One language at a time, for every attachment.

Joplin beat our Actor on English

Our Actor makes Markdown from a file URL, with no install:

curl -s -X POST "https://api.apify.com/v2/acts/brasspage~pdf-ocr-to-markdown/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"documentUrls": ["https://api.apify.com/v2/key-value-stores/sTnmNrGoSsi7tLQvs/records/anythingllm-mixed-11-pages.pdf"]}' \
  | jq -r '.[].markdown' > mixed.md
Same files, Joplin's best setting
Test Joplin Actor
Scan words in order 1,884 1,874
Umlauts 146 192
Two columns, in order 497 954
Time a page 3.6 s 12.1 s

Joplin's OCR is free and stays on your computer. The Actor works outside Joplin, read German and two columns better, and costs $0.006 a page.

How I tested it
  • Scan: the 10 pages of OCR in n8n, proofread Wikisource book scans, 1,955 true words. The 11-page file adds the 13-word typed cover page of AnythingLLM OCR.
  • German: the 3 pages of Paperless-ngx OCR, 1,887 words, 206 umlauts.
  • Joplin itself did not run. I ran the OCR code of Joplin 3.7.22 in Node, with the same tesseract.js 7.0.0 and pdf.js 3.11.174. Pages were drawn in Chromium at scale 2, JPEG quality 0.8, as Joplin does.
  • Score: true words found in order, with the scorer of the tessdata test. German: the scorer of Tesseract German.
  • OCRmyPDF 17.13.0, Node 22, Apple Silicon. One worker at the lowest priority. The code blocks above are the files that ran. The Actor: two real runs earlier the same day, build 0.1.65, on the same files.
What I did not test
  • The Joplin app and its menus. The settings here come from its code and help page.
  • Phones: they show OCR text that desktop made and synced.
  • Handwriting: that option sends files to Joplin Server or Cloud, and Joplin marks it experimental.
Sources

Two ways to skip the work

Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.

Try the Actor

Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.

Get one page free

Questions people ask

Does Joplin OCR scanned PDFs?

Yes, on desktop, and OCR is on by default. It read 1,884 of 1,955 words of a 10-page scan in 39 s. If any page already has text, it runs no OCR.

Why does Joplin not find text in my scanned PDF?

If one page has text, such as a typed cover page, Joplin keeps that text and skips OCR. With one typed page added, it read 0 of 10 scanned pages. Accessible PDF mode read all 11.

How do I OCR German in Joplin?

Set Joplin's display language to German. OCR uses it. With Joplin in English, 3 German pages kept 0 of 206 umlauts. In German, 146.