AnythingLLM OCR, tested on a scanned PDF
2 of 1,955
words AnythingLLM found with one typed page
A plain scan works
1,874 of 1,955 true words found
12.7 seconds for 10 pages
Start it like this:
docker run -d --name anythingllm -p 127.0.0.1:3001:3001 \
-v anythingllm:/app/server/storage \
-e STORAGE_DIR=/app/server/storage \
mintplexlabs/anythingllm
AnythingLLM 1.19.0 runs OCR on a PDF when no page has text. The OCR is tesseract.js, in the image. Our paid Actor found the same 1,874, so a plain scan needs nothing else.
One typed page turns OCR off
AnythingLLM checks the whole PDF. If any page has text, it skips OCR on every page. I put one typed cover page in front of the same scan. The upload said success in 0.1 seconds. The document held only the 13 cover words.
Fix it for free with OCRmyPDF. It adds text to the scanned pages and leaves the typed page alone:
ocrmypdf --skip-text --jobs 2 mixed.pdf mixed-ocr.pdf
It took 37.9 seconds. Then AnythingLLM read 1,875 of 1,955 words.
No internet? The first scan crashes it
The OCR model is not in the image. The first scan downloads eng.traineddata (5.2 MB) from the jsdelivr CDN. With no internet, the container stopped with exit code 1, and curl got an empty reply. The log said:
Error: TypeError: fetch failed
Put the model in the volume once, while you have internet:
docker run --rm -v anythingllm:/app/server/storage --entrypoint sh mintplexlabs/anythingllm -c \
'mkdir -p /app/server/storage/models/tesseract && curl -sL https://cdn.jsdelivr.net/npm/@tesseract.js-data/eng/4.0.0_best_int/eng.traineddata.gz | gunzip > /app/server/storage/models/tesseract/eng.traineddata'
Then the same scan worked with no internet: 1,874 words in 12.0 seconds.
Long scans stop at 300 seconds
OCR has a 5-minute limit. My 300-page scan, the same 10 pages 30 times, stopped after page 280. The upload still said success, with no error. Pages 281 to 300 were not in the document.
On 2 CPUs that was 280 pages. Split a long scan into smaller files.
Six setups, one scan
| Setup | Words found | Seconds |
|---|---|---|
| Plain scan | 1,874 | 12.7 |
| No internet | 0 | 0.3 |
| No internet, model saved first | 1,874 | 12.0 |
| One typed page first | 2 | 0.1 |
| OCRmyPDF, then upload | 1,875 | 38.0 |
| Our OCR Actor, then upload | 1,874 | 153.5 |
AnythingLLM ran in Docker on a Mac, limited to 2 CPUs. OCRmyPDF ran with 2 jobs. The Actor's time includes its start in the cloud.
No OCRmyPDF? Upload Markdown
Our OCR Actor reads each page on its own: typed pages as text, scanned pages with OCR. It takes a PDF URL and returns Markdown:
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' > scan.md
Then upload scan.md with your AnythingLLM API key:
curl -s -H "Authorization: Bearer $ALLM_KEY" -F file=@scan.md http://localhost:3001/api/v1/document/upload
AnythingLLM kept all 1,874 words, and all 13 cover words. On this file the free OCRmyPDF fix found one more. The Actor costs $0.006 a page.
How I tested it
- Scan: the 10-page PDF of OCR in n8n, the first 10 of 55 proofread Wikisource book scans, with no text layer. 1,955 true words.
- Typed page: a 13-word cover sheet from cupsfilter, put in front with pdfunite. Long scan: the same 10 pages 30 times.
- Score: true words found in order, with the scorer of the tessdata test.
- mintplexlabs/anythingllm:latest, server 1.19.0 (5.22 GB on disk), tesseract.js 6.0.1, a fresh volume for each setup. No internet: a Docker network made with --internal. Uploads went to the document upload API.
- OCRmyPDF 17.13.0 with Tesseract 5.5.4. The code blocks above are the files that ran. The Actor: one real run on the 11-page PDF.
What I did not test
- Other OCR languages, image uploads, and the desktop app.
- Chat answers, embedders, and vector databases.
- Tables, photos, handwriting, and faster or slower CPUs.
Sources
Two ways to skip the work
Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.
Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.
Questions people ask
Does AnythingLLM do OCR on scanned PDFs?
Yes. Version 1.19.0 runs tesseract.js when no page of the PDF has text. My 10-page scan gave 1,874 of 1,955 words in 12.7 seconds.
Why does AnythingLLM skip OCR on my PDF?
If any page has text, it skips OCR on all pages. One typed cover page left 2 of 1,955 words. Run ocrmypdf --skip-text on the file first.
Why does AnythingLLM crash on a scan with no internet?
The OCR model is not in the image, and the first scan downloads it. Put eng.traineddata in storage/models/tesseract while you have internet.