OCR scanned PDFs in n8n with Tesseract, tested
0 of 1,955
words Extract from File found
Extract from File: success, 0 words
On a 10-page scanned book, the node said success. Its text was 18 line breaks:
{
"numpages": 10,
"text": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
}
It reads the PDF's text layer, and a scan has none. The words are in the page images, so they need OCR.
The n8n image has no apk
Old guides add Tesseract with apk. On 2.47.4 the build stops:
/bin/sh: apk: not found
Bring in a static apk from Alpine 3.24, the image's own Alpine, and delete it after the install:
FROM alpine:3.24 AS apk
RUN apk add --no-cache apk-tools-static
FROM n8nio/n8n:2.47.4
USER root
COPY --from=apk /sbin/apk.static /tmp/apk
RUN /tmp/apk add --no-cache tesseract-ocr tesseract-ocr-data-eng poppler-utils \
&& rm /tmp/apk
USER node
RUN mkdir /home/node/.n8n-files
docker build -t n8n-ocr .
docker run -d --name n8n -p 5678:5678 -e NODES_EXCLUDE="[]" -v n8n_data:/home/node/.n8n n8n-ocr
5.5.2 Tesseract inside, no apk left
107 MB added to the image
Two lines you need
NODES_EXCLUDE. n8n 2.0 and later leave Execute Command out. Without the variable, my workflow failed with:
Unrecognized node type: n8n-nodes-base.executeCommand
The mkdir. n8n 2.x reads and writes files only in
~/.n8n-files, and the image has no such folder. Without
it, saving the PDF failed with "The file or directory does not exist".
The workflow: save, OCR, delete
Five nodes: workflow.json. Read PDFs takes them from a folder. HTTP Request in its place gave the same text.
Save PDF writes each file under a number:
/home/node/.n8n-files/ocr-{{ $execution.id }}-{{ $itemIndex }}.pdf
The OCR node reads that file, with Execute Once off:
f=/home/node/.n8n-files/ocr-{{ $execution.id }}-{{ $itemIndex }}.pdf
d=$(mktemp -d)
pdftoppm -r 300 -gray "$f" "$d/p" && ls "$d"/p-*.pgm | tesseract stdin stdout --dpi 300
s=$?; rm -rf "$d" "$f"; exit $s
1,872 of 1,955 true words found
1.2 s a page, one thread
Keep file names out of the command
The command runs in a shell. I put
{{ $json.fileName }} in it instead and gave it four
copies of the scan:
| Name | Name in command | Numbered copy |
|---|---|---|
plain.pdf |
Text | Same text |
receipt $25.pdf |
Not found: receipt 5.pdf | Same text |
say "hi".pdf |
Not found: say hi.pdf | Same text |
scan$(touch pwned).pdf |
Not found, and ran touch pwned |
Same text |
With the node's default error setting, the first bad name stopped the whole run.
Turn off Execute Once
Execute Command runs once by default, for the first item only. With it on, n8n read 1 of 4 PDFs and left 3 saved copies on disk.
n8n Cloud: call an OCR API
n8n's docs say Execute Command is not available on n8n Cloud. An HTTP Request node can call our OCR Actor instead:
POST https://api.apify.com/v2/acts/brasspage~pdf-ocr-to-markdown/run-sync-get-dataset-items
Authorization: Bearer YOUR_APIFY_TOKEN
{"documentUrls": ["https://api.apify.com/v2/key-value-stores/sTnmNrGoSsi7tLQvs/records/n8n-scan-2-pages.pdf"]}
353 of 381 words, 2 scanned pages
Tesseract in the container found the same 353. The Actor reads a URL, so the PDF has to be online.
How I tested it
- Scan: the first 10 of the 55 proofread Wikisource book scans of Tesseract in Node.js, in one PDF with no text layer. 1,955 true words.
- Score: true words found in order, with the scorer of the tessdata test.
- n8n 2.47.4 in Docker on an Apple Silicon Mac. Each workflow ran in a fresh container with n8n import:workflow and n8n execute, no editor.
- Alpine's tesseract-ocr 5.5.2 and its English data, poppler-utils 25.12.0. One OCR thread (OMP_THREAD_LIMIT=1).
- The run line above started n8n and answered on /healthz with Tesseract inside.
- The Actor: one real run from the HTTP Request node, with a Header Auth credential.
What I did not test
- The n8n editor, n8n Cloud, and queue mode workers.
- Gmail and Google Drive as the PDF source.
- The Apify node, and the OCR nodes of paid AI services.
- Other languages, photos, and npm or desktop installs of n8n.
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
Why does Extract from File return empty text?
The PDF is a scan. Extract from File reads only the text layer, and a scan has none. On my 10-page scan it gave 18 line breaks and 0 words.
Why is Execute Command missing in n8n?
n8n 2.0 and later leave it out by default. Start n8n with NODES_EXCLUDE="[]" to bring it back. It is not available on n8n Cloud.
Can I apk add Tesseract in the n8n image?
Not as is: the 2.47.4 image has no apk, and the build stops with apk: not found. Copy apk.static from alpine:3.24 in a first stage, then delete it after the install.