Tools,

olmOCR on a Mac, tested on a real scanned PDF

1,954

of 1,955 scan words, read in order

Get the setup

Ten scanned pages in 77 seconds

77 s for 10 pages, Mac GPU

9.5 GB model download

  1. Run pip install olmocr and brew install poppler.
  2. Unpack the llama.cpp macOS arm64 build into llama-b12316/. Put the Q8_0 model and the F16 mmproj in gguf/.
  3. Save olmocr.sh below next to book.pdf. Run sh olmocr.sh. It writes ws/markdown/book.md.
olmocr.sh
./llama-b12316/llama-server -m gguf/olmOCR-2-7B-1025-Q8_0.gguf --mmproj gguf/mmproj-olmOCR-2-7B-1025-F16.gguf \
  -c 16384 -np 1 --host 127.0.0.1 --port 8095 --threads 2 --no-warmup > server.log 2>&1 &
S=$!
until curl -sf http://127.0.0.1:8095/health > /dev/null; do kill -0 $S || exit 1; sleep 1; done
BEAKER_ASSIGNED_CPU_COUNT=2 python -m olmocr.pipeline ws --server http://127.0.0.1:8095/v1 --model olmocr --markdown \
  --pdfs book.pdf --workers 1 --max_concurrent_requests 1 > pipeline.log 2>&1
R=$?
kill $S; wait $S
exit $R

The GGUF files are the LM Studio community copy. The BEAKER_ASSIGNED_CPU_COUNT line caps page renders at 2.

The plain command wants an NVIDIA GPU

The README asks for a recent NVIDIA GPU with 12 GB or more for local runs.

Without --server, the toolkit tries to start its own vLLM. The base install has no torch, so on the Mac it stopped after 1.5 seconds:

No module named 'torch'

With --server, it skips that check. It sends each page to llama-server, like it does to a paid API.

What the toolkit adds

Watch one default: if more than 1 page in 250 falls back, the code drops the whole document. That did not happen here.

One quote mark and one running head

The only missed word was a closing quote mark after "course--". The only extra line was the running head on top of page 9:

THE UNCOMMON PRAYER-BOOK

The 11-page file with a typed cover page took 106 s. It read all 13 cover words, and the scan pages came out byte for byte the same.

German: good umlauts, weaker columns

The model card lists English only. It still wrote 194 of 206 umlauts, in 98 s.

3 German pages: umlauts, and words in order on the two-column page
Model Umlauts Columns
LightOnOCR-3 202 961
LightOnOCR-2 199 959
olmOCR-2 194 935

The two-column page has 972 words.

Tied with LightOnOCR-2 for the most words

The same 10 scanned pages, scorer and Mac GPU:

Scan words in order, of 1,955
Model Words Time
LightOnOCR-2 1,954 72 s
olmOCR-2 1,954 77 s
glm-ocr, Ollama 1,953 104 s
GOT-OCR 2.0 1,936 134 s
Florence-2 1,887 158 s

olmOCR and our Actor: 3 wins, 2 losses

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, olmOCR on the Mac GPU
Test olmOCR Actor
Scan words in order 1,954 1,874
Typed cover words 13 13
Umlauts 194 192
Two columns, in order 935 954
Time, 11 pages 106 s 133 s
Time, 3 German pages 98 s 59 s

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

Apache 2.0, from Ai2

The toolkit and the model are Apache 2.0. I read the license, the model card and Ai2's use guidelines in full before the download.

The card says the model is for research and education. The guidelines it points to list harmful uses, with no ban on business use.

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. One page has two columns, 972 words.
  • Score: true words found in order in book.md, with the scorer of the tessdata test. German: the scorer of Tesseract German.
  • olmocr 0.4.27 and llama.cpp b12316 on an Apple Silicon Mac GPU, at the lowest priority, 2 CPU threads, one page at a time.
  • GGUF: lmstudio-community/olmOCR-2-7B-1025-GGUF, revision 9191740, Q8_0 model (8.1 GB) and F16 mmproj (1.35 GB). Their SHA-256 sums match the Hub.
  • Times count the whole script, with the model load. The files were already downloaded. One run of each file.
  • The other model rows: the same files and scorer, on the same Mac, on November 12. They have their own pages.
  • The Actor: two real runs earlier the same day, build 0.1.65, on the same files.
What I did not test
  • The full BF16 or FP8 model, and smaller GGUF sizes.
  • vLLM on an NVIDIA GPU, the toolkit's own path.
  • Paid olmOCR APIs.
  • Tables, math, handwriting and rotated pages.
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 olmOCR run on a Mac?

Yes, with the toolkit's --server flag. Serve a GGUF copy of the model with llama.cpp on the Mac GPU. The plain command wants vLLM and an NVIDIA GPU.

Can olmOCR read German?

Yes. It wrote 194 of 206 umlauts on German pages and tagged each page as German. Both LightOnOCR models read more words in order on a two-column page.

Is olmOCR free for business use?

The toolkit and the model are Apache 2.0, from Ai2. Ai2's use guidelines list harmful uses. They do not forbid business use.