Tools,

Qwen3-VL OCR, tested on a real scanned PDF

1,951

of 1,955 scan words, read in order

Get the setup

Use the instruct tag and temperature 0

139 s for 10 pages, Mac GPU

6.2 GB download, 8B instruct

  1. Install Ollama and Poppler. Run ollama pull qwen3-vl:8b-instruct.
  2. Save the Modelfile below, then run ollama create qwen3-vl-ocr -f Modelfile.
  3. Run sh qwen.sh qwen3-vl-ocr next to book.pdf. It writes book.md.
The Modelfile and qwen.sh
FROM qwen3-vl:8b-instruct
PARAMETER temperature 0
pdftoppm -r 200 -png book.pdf page
for p in page-*.png; do
  ollama run "$@" "Read all the text in the image. ./$p" > "${p%.png}.md" || exit 1
done
cat page-*.md > book.md

The prompt is the full-page OCR prompt of the Qwen3-VL cookbook.

The plain qwen3-vl tag thinks first

ollama pull qwen3-vl gets the 8B thinking model.

The tags :2b, :4b and :8b are thinking models too.

Page 1 only, the plain qwen3-vl tag
Flag File Time
None 2,672 bytes 28 s
--think=false 2,698 bytes 28 s
--hidethinking 1,170 bytes 32 s

With no flag, the file starts with "Thinking..." and the model's notes. --think=false did not stop it.

The instruct model wrote 1,156 clean bytes for page 1, and took about 14 s a page.

Temperature 0 gives the same text twice

The library sets temperature 1. I read the same 10 scan pages twice: once alone, and once in the 11-page file below.

3 of 10 pages the same, temperature 1

10 of 10 pages the same, temperature 0

That run also read 1 more word, and it took 26 s less.

glm-ocr still read 2 more words

The same 10 scanned pages, scorer and Mac GPU, all in Ollama:

Scan words in order, of 1,955
Model Words Time
glm-ocr 1,953 104 s
Qwen3-VL 8B, temperature 0 1,951 139 s
Qwen3-VL 8B, temperature 1 1,950 165 s
Qwen3-VL 4B, temperature 1 1,936 136 s

glm-ocr is an OCR model. Qwen3-VL is a general vision model, and it came close.

The 4B model is a 3.3 GB download. It often put a space between a quote mark and the next word.

The misses: 4 words, and every header

Qwen3-VL 8B wrote "yourn" as "you rn" and "old-fashioned" as "oldfashioned". Two double dashes became one dash.

It kept the running page header on all 10 pages. Delete those lines if you need clean book text.

At temperature 1, it also fixed a dialect word: "asho'" became "ashore".

Typed pages: 13 of 13 cover words

Qwen3-VL reads every page as a picture, typed pages too. It read the whole typed cover page, title line included.

In the 11-page file, the scan words stayed at 1,951, in 118 s.

German: two columns read in order

The script has no language option. I gave it 3 German pages. One is a magazine page with two columns.

Of 206 umlauts and 972 two-column words
Model Umlauts Two columns
Qwen3-VL, temperature 0 192 965
Qwen3-VL, temperature 1 195 961
glm-ocr, Ollama 193 955

At temperature 0, the 3 pages took 101 s.

dots.ocr is still the best here, with 204 umlauts.

Qwen3-VL and our Actor: 3 wins, 1 loss

Our Actor, 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, Qwen3-VL 8B at temperature 0
Test Qwen3-VL Actor
Scan words in order 1,951 1,874
Typed cover words 13 13
Umlauts 192 192
Two columns, in order 965 954
Time, 11 pages 118 s 133 s
Time, 3 German pages 101 s 59 s

Qwen3-VL read more scan words. The Actor was faster on German.

The Actor needs no GPU and no 6.2 GB download. It costs $0.006 a page.

The license allows business use

The Ollama download holds the plain Apache 2.0 license. It is the same text as the Qwen3-VL license on GitHub.

The model cards say apache-2.0, with no added use or region terms. I read all of it before the download.

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.
  • Score: true words found in order in book.md, with the scorer of the tessdata test. German: the scorer of Tesseract German.
  • Ollama 0.40.16 for macOS on an Apple Silicon Mac GPU, at the lowest priority. qwen3-vl:8b-instruct and qwen3-vl:4b-instruct, Q4_K_M, from the Ollama library.
  • Times count the script only, one model start included. The Ollama server ran before each script.
  • One run each. My first temperature 0 run stopped on page 1 with no answer from the server. The same command on its own worked, and a second run worked.
  • The glm-ocr rows: the same files and scorer, on the same Mac, on November 12. They have their own page.
  • The scripts 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 2B, 30B and larger Qwen3-VL models, and Q8_0 or BF16.
  • The cookbook's text spotting and key-value prompts.
  • Qwen3-VL in Transformers, vLLM or llama.cpp.
  • The Qwen-VL-OCR model of the Alibaba Cloud API.
  • Windows, Linux and NVIDIA GPUs.
  • Handwriting, tables, charts, math and forms.
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

Can Qwen3-VL do OCR?

Yes. In Ollama on a Mac GPU, the 8B instruct model read 10 scanned pages in 139 s.

Why does my Qwen3-VL OCR text start with Thinking...?

The plain qwen3-vl tags are the thinking models. Pull qwen3-vl:8b-instruct instead. The --think=false flag did not stop it.

Which Qwen3-VL size is best for OCR?

The 8B model read 14 more words on our scan, but its download is 2.9 GB bigger.