Which local model reads handwriting best, and which Mac it needs

The last row of my test of cloud models was the model Tagged Sync can download for you: free and private, and the weakest reader of paper in the table. The first question after it went live was whether Gemini 3.1 Flash-Lite, the cloud model it recommends, can be downloaded too. It cannot. Google’s open models are a family of their own, Gemma 4, and that turns the question into a better one: of the models you can run on your own Mac, which reads handwriting best?
This article answers it the way the cloud one did. Nine models that run on a Mac with 32 GB of memory or less, from Google, Alibaba and OpenBMB, read the same 264 handwritten pages from the same three public sets. Two of them are the ones the plugin downloads, called built in from here on. The request is exactly the one version 1.8.5 of the plugin sends. Everything ran on my own Mac, so no page left it. Gemini 3.1 Flash-Lite stays in the table as the yardstick, with its numbers taken from the cloud test.
The short version, one model per Mac:
- 32 GB or more: Gemma 4 31B, in LM Studio, with thinking switched off. It makes a little more than a third of the built-in 8B’s errors on scanned paper and comes closest to the cloud of any local model. On reMarkable ink it reads no better than the built-in 8B.
- 16 GB: keep the built-in Qwen3-VL-8B. Nothing that fits reads tablet ink better. Qwen3.5-9B reads paper slightly better, but it needs LM Studio with thinking switched off, and it reads ink worse.
- 8 GB: the built-in Qwen3-VL-2B, which the plugin offers on such a Mac. It is the only model that fits and still reads usefully.
Why measure again
The cloud test measured the local model because it is the one the plugin downloads. That does not make it the best model a Mac can run. There are bigger ones and newer ones: Google’s Gemma 4, Alibaba’s Qwen3.5 and Qwen3.8, and a MiniCPM-V from OpenBMB that came out in October. The published comparisons do not settle it. The few that test handwriting at all put the built-in 8B at or near the top of the open models, and none of the bigger candidates has a published number for Latin-script handwriting. The only way to know was to read the same pages with each of them.
Only models that fit a Mac with 32 GB of memory count here. My own Mac has far more than that, so I measured on it what each model needs; “How it was measured” explains how.
The nine models, and the three sets
All nine are general vision models from three open families, published under the Apache 2.0 licence. Four are sized for a Mac with 32 GB and three for 16 GB; two are small enough for 8 GB.
- Gemma 4 31B and Gemma 4 12B, Google’s open family, in the 4-bit files Google trained for that precision (QAT).
- Qwen3.8-27B and Qwen3-VL-30B-A3B for 32 GB, and Qwen3.5-9B for 16 GB, from Alibaba.
- MiniCPM-V 4.7 35B-A3B and its 1B sibling, from OpenBMB.
- Qwen3-VL-8B and Qwen3-VL-2B, the two the plugin downloads: the 8B on a Mac with 16 GB or more, the 2B on a Mac with 8 GB.
“A3B” in a name means that only about three billion of the model’s parameters work on each word, which is why those two are fast for their size. I left out the document-OCR models, which read print well and, in published tests and one of my own, fall apart on handwriting.
The pages are the cloud test’s, and that article describes them in detail. GNHK is 172 phone photos of English everyday notes from well over a hundred writers, published by Goodnotes. The ScaDS.AI German Full-Page Handwriting Dataset is 77 scanned half pages, each a German Wikipedia paragraph copied out by a different volunteer. Both are CC BY 4.0. The third set is the plugin’s own fifteen reference pages, written by me on a reMarkable Paper Pro and rendered the way the plugin renders them: the only tablet ink of the three, and one writer.

GNHK page eng_AS_018. Goodnotes, GNHK dataset, CC BY 4.0.

ScaDS.AI page 010. ScaDS.AI German Full-Page Handwriting Dataset, CC BY 4.0.

What is measured
The numbers are the cloud test’s, with one swap. The character error rate on the German scans and on my fifteen pages is the share of characters that would have to be inserted, deleted or changed to turn the transcript into the truth, as the median over a set’s pages: 1 % is roughly one wrong character per line. On the phone photos it is word recall, the share of the labelled words that arrived in the transcript, because GNHK labels only the handwriting and every model also reads the printed headings.
Cents per page are zero for every local model, so time takes their place in the picture: seconds per page, one page at a time. And there is a number the cloud never needed, memory. The most memory a model took while reading decides which Mac can run it at all.
As before, I also counted the pages a model did not read, and whether each list and table on my pages came back as a list or a table.
How it was measured
The request is the one Tagged Sync 1.8.5 sends. Nothing in the request was tuned for the test.
- The prompt is word for word the cloud test’s. The tablet pages went as the plugin renders them, the public pages as their JPEG files, the photos brought to 2000 pixels on the long edge.
- The two built-in models ran through the plugin’s own code path: the pinned llama.cpp build (b10295), Qwen’s own 4-bit files, temperature 0, a fixed seed, 1 024 answer tokens, one process per page, with an 8 192-token context for the 8B and 6 144 for the 2B, as the plugin ships them.
- The other seven ran in LM Studio 0.4.26 on its llama.cpp engine (build b11698), which is how a reader would run them, through the plugin’s LM Studio backend: the model name, the prompt, the image, temperature 0, and an answer limit of 16 384 tokens. All are 4-bit GGUF files, Google’s QAT files for Gemma and Q4_K_M for the others, with an 8 192-token context. One page at a time.
- Six of the nine models think before they answer unless told not to, and the plugin does not tell them. For the table I switched thinking off in each model’s LM Studio settings and checked every answer: no model spent a thinking token on any of the 264 pages.
- The computer is an Apple M5 Max with 128 GB, and every time in this article is an M5 Max time. A Mac with 32 GB has a smaller chip and will most likely be slower; how much slower I did not measure.
- “Fits a 32 GB Mac” is a measurement. For each model I took the peak memory while it read the heaviest pages of each set, added 4 GB for macOS and Obsidian, and rounded up to a size Macs are sold in. So a model that peaks at 27 GB or less fits 32 GB, 19 GB or less fits 24 GB, 11 GB or less fits 16 GB, and 3 GB or less fits 8 GB. I did not run any model on a 32 GB Mac.
- Each model ran once, on 17 October 2026. At temperature 0 the built-in 8B read all 264 pages byte for byte the same as in the cloud test the day before. The Gemini row is copied from that test, which ran on 16 October with four pages in flight.
Handwriting OCR results: error rate and time per model
| model | German scans, CER | English photos, words found | reMarkable pages, CER | lists and tables kept | ¢ per page | thinking tokens per page | seconds per page | pages not read |
|---|---|---|---|---|---|---|---|---|
| Gemma 4 31B | 0.82 % | 94.1 % | 2.32 % | 3/3 | 0 | 0 | 8.5 | 1 |
| Qwen3-VL-30B-A3B | 1.50 % | 92.6 % | 4.65 % | 3/3 | 0 | 0 | 4.4 | 6 |
| Qwen3.8-27B | 1.54 % | 92.7 % | 2.32 % | 3/3 | 0 | 0 | 7.0 | 0 |
| Qwen3.5-9B | 1.63 % | 92.9 % | 2.52 % | 3/3 | 0 | 0 | 3.8 | 0 |
| Qwen3-VL-8B, built in | 2.22 % | 92.6 % | 1.79 % | 3/3 | 0 | 0 | 4.5 | 0 |
| MiniCPM-V 4.7 35B-A3B | 3.42 % | 92.1 % | 4.55 % | 3/3 | 0 | 0 | 1.6 | 0 |
| Gemma 4 12B | 4.42 % | 92.2 % | 3.19 % | 3/3 | 0 | 0 | 7.7 | 10 |
| Qwen3-VL-2B, built in | 5.26 % | 91.0 % | 6.55 % | 3/3 | 0 | 0 | 2.8 | 0 |
| MiniCPM-V 4.7 1B | 16.67 % | 82.7 % | 17.60 % | 3/3 | 0 | 0 | 0.9 | 1 |
| Gemini 3.1 Flash-Lite, cloud | 0.54 % | 95.0 % | 1.00 % | 3/3 | 0.046 | 0 | 1.8 | 8 |
Medians over the pages each model read. A local model’s “pages not read” are pages it never finished (see below); Gemini’s are refusals. Seconds per page are wall time over all 264 pages, one page at a time on the M5 Max for the local models, four pages in flight for the cloud model.
The table is sorted by the error rate on the German scans, where every page is a different writer, and the cloud model sits apart at the bottom. The chart at the top plots that same error rate against the seconds per page; an orange dot is a local model that no other local model beats on both at once, and the ring is Gemini 3.1 Flash-Lite, for scale. Every model kept the lists and the table on my pages as lists and a table.
Gemma 4 31B reads paper best, and the built-in 8B reads ink best
Gemma 4 31B is the best local reader of both paper sets: 0.82 % on the German scans, little more than a third of the built-in 8B’s 2.22 %, and 94.1 % of the words on the phone photos, against 92.6 %. It is the slowest model in the table, at 8.5 seconds a page, and it lost one photo. Behind it on paper the three Qwen models are close together, between 1.50 % and 1.63 % on the scans and within a third of a point of one another on the photos: Qwen3-VL-30B-A3B, Qwen3.8-27B and, at a third of their size, Qwen3.5-9B.
On my tablet pages the order turns over. The built-in 8B reads them at 1.79 %, better than every other local model. Gemma 4 31B and Qwen3.8-27B tie behind it at 2.32 %, and Qwen3.8-27B, unlike Gemma, read all 264 pages. The two fast 32 GB models, Qwen3-VL-30B-A3B and MiniCPM-V 4.7 35B-A3B, read ink worst of the big ones, at 4.65 % and 4.55 %. MiniCPM is the fastest model here that reads usefully, 1.6 seconds a page. It is not in LM Studio’s catalogue, so you have to load its files yourself.
One number needs a caution. The built-in 8B reads my tablet pages at 1.79 % in the plugin’s own runtime. I ran the same model file once more in LM Studio as a control, and there it read them at 3.19 %, with the scans and photos almost unchanged (2.29 % and 92.6 %). Every challenger ran in LM Studio, so its ink score is the one you get there, and it might read ink better in another engine. I have corrected no score for this, and I do not know the cause.
At the small end, Gemma 4 12B fits 16 GB and reads worse than the built-in 8B on every set. The built-in 2B, the plugin’s model for 8 GB, reads the scans at 5.26 % and my pages at 6.55 %. MiniCPM-V 4.7 1B fits 8 GB as well and gets one character in six wrong.
A page that never ends
Every page a local model did not read failed the same way. The model wrote one line again and again until its 8 192-token context was full, which took between 50 seconds and almost five minutes. One German scan did that to three different models. Gemma 4 12B lost ten pages like this and Qwen3-VL-30B-A3B six; Qwen3.8-27B, Qwen3.5-9B, MiniCPM-V 35B-A3B and both built-in models lost none. The plugin marks such a page as failed and tries it again at the next sync, and at temperature 0 the second try runs the same way. A bigger context would only make the wait longer.
Thinking helps only Gemma 4, and slowly
LM Studio switches thinking on for every model that can think, unless you switch it off. To see what that buys, I ran the six that can over my fifteen tablet pages once more with thinking on, as LM Studio ships them, with three times the context to think in.
| model | reMarkable pages, CER, thinking off → on | seconds per page, off → on | thinking tokens per page |
|---|---|---|---|
| Gemma 4 31B | 2.32 % → 2.24 % | 5.6 → 37.0 | 786 |
| Qwen3.8-27B | 2.32 % → 2.52 % | 4.0 → 11.1 | 357 |
| Gemma 4 12B | 3.19 % → 2.61 % | 2.3 → 52.0 | 2 779 |
| Qwen3.5-9B | 2.52 % → 4.35 % | 2.2 → 46.5 | 3 494 |
| MiniCPM-V 4.7 35B-A3B | 4.55 % → 6.67 % | 1.3 → 5.7 | 487 |
| MiniCPM-V 4.7 1B | 17.60 % → 19.23 % | 0.7 → 2.6 | 479 |
Thinking helped Gemma 4 alone: the 12B clearly, at twenty-three times the time, and the 31B by so little that a single page could account for it, at seven times the time. Every other model read worse while thinking, Qwen3.5-9B worst. Two pages of Gemma 4 12B and one of Qwen3.5-9B never got past the thinking: the plugin’s answer limit of 16 384 tokens ran out first.
MLX or GGUF?
LM Studio offers most of these models in two formats and does not tell you which to take: GGUF, which runs on llama.cpp, and MLX, which runs on Apple’s own framework. I measured four of them both ways, on all three sets, the same way as above.
| model | format | German scans, CER | English photos, words found | reMarkable pages, CER | seconds per page | pages not read | memory, model alone | memory, as LM Studio ran it |
|---|---|---|---|---|---|---|---|---|
| Qwen3-VL-8B | GGUF, built in | 2.22 % | 92.6 % | 1.79 % | 4.5 | 0 | 7.9 GB | 7.9 GB |
| Qwen3-VL-8B | GGUF, LM Studio | 2.29 % | 92.6 % | 3.19 % | 4.0 | 1 | 8.9 GB | 20.8 GB |
| Qwen3-VL-8B | MLX | 1.96 % | 92.6 % | 1.80 % | 5.3 | 4 | 12.3 GB | 15.7 GB |
| Qwen3-VL-30B-A3B | GGUF | 1.50 % | 92.6 % | 4.65 % | 4.4 | 6 | 20.3 GB | 31.1 GB |
| Qwen3-VL-30B-A3B | MLX | 1.85 % | 92.6 % | 3.68 % | 3.9 | 3 | 22.7 GB | 25.5 GB |
| Qwen3.5-9B | GGUF | 1.63 % | 92.9 % | 2.52 % | 3.8 | 0 | 7.4 GB | 18.3 GB |
| Qwen3.5-9B | MLX | 1.64 % | 93.2 % | 3.77 % | 3.7 | 2 | 11.9 GB | 12.3 GB |
| Gemma 4 31B | GGUF (QAT) | 0.82 % | 94.1 % | 2.32 % | 8.5 | 1 | 21.7 GB | 36.3 GB |
| Gemma 4 31B | MLX (not QAT) | 0.89 % | 92.9 % | 3.07 % | 5.2 | 0 | 27.8 GB | 27.8 GB |
The same weights in both formats, except Gemma: the MLX builds of Google’s QAT file are all larger mixed-precision files, so its MLX row is the ordinary 4-bit model. “Model alone” is the peak without LM Studio’s cache of earlier pages (next section); MLX holds its memory in a way the usual process counter misses, so its peaks were read from the process’s physical footprint.
The format changes the text of almost every page: only 17 to 32 of each model’s 264 transcripts came out identical in both formats. Neither format reads better across the board. On the scans and photos the numbers move by tenths, in both directions, except Gemma’s photos, where the MLX file is a different one. On the tablet pages the moves are bigger, about a point: MLX reads them better for the 8B and the 30B, and worse for the 9B and Gemma. The 8B as MLX reads my pages like the plugin’s own runtime does, which makes its LM Studio GGUF row the odd one.
Two other differences matter. MLX is faster on the big models as long as nothing goes wrong: Gemma 4 31B took 5.2 seconds a page against 8.5. But a page that never ends runs on past the context to the plugin’s answer limit, about three minutes a page. The 8B lost four photos that way, which made its MLX row the slower one. And MLX needs 2 to 6 GB more memory for the model itself, but less than GGUF as LM Studio runs it, for a reason the next section explains. For Gemma 4 31B the answer is GGUF either way: as MLX it reads slightly worse and needs 27.8 GB, over the 27 GB that fits a 32 GB Mac.
What it costs: memory and time
A local model costs nothing per page. The price is memory and time.
| model | download | memory while reading | as run over 264 pages | smallest Mac |
|---|---|---|---|---|
| Gemma 4 31B | 18.9 GB | 21.7 GB | 36.3 GB | 32 GB |
| MiniCPM-V 4.7 35B-A3B | 22.3 GB | 21.7 GB | 31.3 GB | 32 GB |
| Qwen3-VL-30B-A3B | 19.6 GB | 20.3 GB | 31.1 GB | 32 GB |
| Qwen3.8-27B | 17.7 GB | 19.1 GB | 32.0 GB | 32 GB |
| Gemma 4 12B | 7.2 GB | 8.8 GB | 22.2 GB | 16 GB |
| Qwen3-VL-8B, built in | 6.2 GB | 7.9 GB | 7.9 GB | 16 GB |
| Qwen3.5-9B | 6.5 GB | 7.4 GB | 18.3 GB | 16 GB |
| Qwen3-VL-2B, built in | 1.6 GB | 2.9 GB | 2.9 GB | 8 GB |
| MiniCPM-V 4.7 1B | 1.8 GB | 2.4 GB | 11.3 GB | 8 GB |
The “smallest Mac” column rests on the model’s own peak, the third column. LM Studio adds something on top. Its llama.cpp engine keeps up to 8 GB of earlier pages in memory in case the next request starts the same way, and LM Studio 0.4.26 has no setting to switch it off. Over a long sync that cache fills up: Gemma 4 31B’s process grew to 36.3 GB on my Mac by the end of the 264 pages. On a 32 GB Mac that means swapping, and a slower sync than the times here suggest. The two built-in models do not have this, because the plugin starts a fresh process for every page.
Time is the other cost. On the M5 Max, Gemma 4 31B took 5.6 seconds per tablet page, the built-in 8B 2.9, so a notebook of fifty pages takes under five minutes with Gemma and under three with the 8B, and longer on a smaller Mac. The whole test, nine models and the extra runs for thinking and for MLX, took about six hours of my Mac’s time and cost electricity.
Where the cloud stands
Gemini 3.1 Flash-Lite, the model the cloud test recommends, still reads better than every local model on every set: 0.54 % on the German scans against Gemma 4 31B’s 0.82 %, 95.0 % of the words on the photos against 94.1 %, and 1.00 % on my tablet pages against the built-in 8B’s 1.79 %. It takes 1.8 seconds a page and costs 0.046 cents. In exchange the page goes to Google, and Gemini refuses a page it recognises as published text, as it did with eight of the 264. If your pages may leave your machine, the cloud test has the models and the prices.
What a Tagged Sync user should set
32 GB or more: Gemma 4 31B, in LM Studio, thinking off. It is the best local reader of scanned paper and photos by a clear margin. On tablet ink alone it does not beat the built-in 8B, so it earns its setup on the pages you photograph or scan.
To set it up, install LM Studio, search for google/gemma-4-31b-qat and
download it (18.9 GB). Under My Models, open the model’s settings and, on the Inference tab, switch
off Enable Thinking; LM Studio applies that to every request, including the plugin’s. Load the
model and start the server on the Developer tab. Then in Obsidian open Settings, Transcription,
Backend, choose LM Studio (your own server), and type google/gemma-4-31b-qat into the Model
field. The LM Studio backend is part of the free plugin.
16 GB: keep the built-in Qwen3-VL-8B. It needs no other program and is already the plugin’s opt-in on a Mac with Apple silicon: Settings, Transcription, Backend, Downloaded model (managed by this plugin). Qwen3.5-9B is worth the trouble only if you mostly scan paper: it reads scans at 1.63 % against the 8B’s 2.22 %, and ink at 2.52 % against 1.79 %.
8 GB: the built-in Qwen3-VL-2B. The plugin offers it in place of the 8B on such a Mac. It makes a third of the errors of MiniCPM-V 4.7 1B, the only other model here that fits.
On Windows with an Intel or AMD chip and on Linux the plugin downloads no model. The LM Studio route works there too, but I measured on a Mac only.
What this does not settle
- One run per model, on one machine, an M5 Max. A 32 GB Mac is most likely slower, and with LM Studio’s cache it may swap.
- Every challenger ran in LM Studio only. Ollama was not tested. It has no setting to switch thinking off; only the request can, and the plugin’s request does not.
- The tablet condition is one writer, me. The ranking on paper rests on hundreds of hands, the ranking on ink on fifteen pages.
- LM Studio gives Gemma 4 its default image budget, about half the image tokens per scan that the Qwen models get. It read the scans best anyway; with more it might read better still, or not.
- Marks a Bullet Journal writer relies on, a dot, a cross, an arrow at the start of a line, are not scored here, as in the cloud test.
Sources and licences
The GNHK and ScaDS.AI pages shown here are reproduced under their CC BY 4.0 licences with attribution as above; the full sets are available from their publishers. My fifteen pages are in the plugin’s repository under its own licence. The nine models are published by Google, Alibaba’s Qwen team and OpenBMB under the Apache 2.0 licence and were downloaded through LM Studio and Hugging Face.