pytesseract config: the mistakes it hides
6 of 12
mistakes gave no Python error
Try it on your PDF, $0.006 a page
pytesseract hides Tesseract's warnings
These ran on 6 test pages with no Python error. The first 4 gave the same text as no config:
| config= | What Tesseract printed |
|---|---|
-c tessedit_char_whitelst=0123456789 |
Warning: The parameter 'tessedit_char_whitelst' was not
found.
|
-c TESSEDIT_CHAR_WHITELIST=0123456789 |
The same warning. Names are case sensitive. |
digts |
read_params_file: Can't open digts |
psm 6 |
Can't open psm, then Can't open 6: two
file names
|
digits --psm 6 |
Can't open --psm. Options after a file name are
file names too. Same text as digits alone.
|
-c tessedit_char_whitelist=0-9 |
Nothing. That is a list of 3 characters, not a range. 2 of 726 words came out right. |
The loud mistakes, 2 with an empty message
These raised TesseractError on all 6 pages:
| config= | The error |
|---|---|
-psm 6 |
(1, "Error, unknown command line argument '-psm'")
|
--psm=6 |
The same, for '--psm=6' |
-c tessedit_char_whitelist = 0123456789 |
(1, "exception: Missing '=' in configvar assignment")
|
--oem 0 |
Error: Tesseract (legacy) engine requested, but components
are not present
|
--psm 14 |
(1, '') |
--psm 6, --oem 1 |
(1, '') |
The empty ones are a bad psm value. Tesseract prints
Invalid PSM value to standard output, not to the error
stream, so pytesseract has no message to show.
--oem 0 asks for the legacy engine, which the
tessdata_fast model leaves out. See
tessdata_best vs tessdata_fast.
Check a config once: 11 of 12 caught
It reruns the config on the command line and fails on hidden warnings:
import shlex
import subprocess
import pytesseract
def check_config(config, image):
"""Fail on the warnings pytesseract hides."""
cmd = pytesseract.pytesseract.tesseract_cmd
args = [cmd, image, "stdout", *shlex.split(config)]
r = subprocess.run(args, capture_output=True, text=True)
lines = r.stderr.splitlines()
bad = [x for x in lines if "not found" in x or "Can't open" in x]
if r.returncode or bad:
raise ValueError(bad or r.stderr.strip() or r.stdout.strip())
return config
config = "-c tessedit_char_whitelst=0123456789"
check_config(config, "invoice.png")
It stopped with:
ValueError: ["Warning: The parameter 'tessedit_char_whitelst' was not found."]
On all 6 pages, it stopped 11 of the 12 mistakes and passed every good config. It misses the range, which is a valid list to Tesseract.
What worked, and what each did
| config= | On my 6 pages |
|---|---|
--psm 6 |
724 of 726 words right, against 693 with no config |
--psm 6 --oem 1 |
The same text as --psm 6 |
-c tessedit_char_whitelist=0123456789 |
"Invoice 2026-0417" came out as 20260417 |
digits |
2026-0417: the file also allows the dash and the
point
|
-c preserve_interword_spaces=1 |
Kept the gaps between columns, as below |
import pytesseract
config = "--psm 6 -c preserve_interword_spaces=1"
text = pytesseract.image_to_string(
"invoice.png", lang="eng", config=config
)
print(text.splitlines()[4])
Date: October 30, 2026 Due: November 29, 2026
Pass the language as lang. pytesseract puts
-l and the language before your config.
631 parameters: search for the name
tesseract --print-parameters lists every name Tesseract
5.5.3 knows. Search it before you type one:
$ tesseract --print-parameters | grep whitelist
tessedit_char_whitelist Whitelist of chars to recognize
A bare word in config is a file name. The Homebrew tessdata/configs
folder holds 26, such as digits, hocr and
tsv. The digits file is one line:
tessedit_char_whitelist 0123456789-.
If you want the text, not the tuning
PDF OCR to Markdown
is our Apify Actor. On scanned pages it runs Tesseract with fixed
settings, so you pass no config. You get Markdown, with tables as
Markdown tables. I ran
check_config on 4 of its config strings, and all 4
passed.
- $0.006 a page, plus $0.00005 a run at the default 1 GB of memory. Pages that fail are free.
- The Apify free plan lets you try 20 pages a run and 50 a month.
- Pages are read inside the run. They are not sent to any AI service.
Questions people ask
What config options does pytesseract accept?
The options of the tesseract command: --psm, --oem, --dpi, --tessdata-dir, --user-words, --user-patterns, --loglevel and -c name=value, then config file names. pytesseract splits the string like a shell and puts it after -l and the language, if you pass lang.
Why is my tessedit_char_whitelist not working?
Check the spelling and the capitals first: a wrong name only prints a warning, and pytesseract hides it. Then check the value. 0-9 is not a range. A space before the equals sign stops the run, and a space after it drops the whitelist with no error.
How do I pass psm and oem in pytesseract?
Use two dashes and a space, as in config="--psm 6 --oem 1". -psm 6 and --psm=6 raised TesseractError. psm 6 with no dashes ran, but Tesseract took psm and 6 as two file names it could not open.
How do I see Tesseract warnings from pytesseract?
pytesseract shows the error stream only when Tesseract fails. Otherwise it drops it. Run the same arguments with subprocess and read stderr yourself, as check_config on this page does.
What is a Tesseract config file?
A text file with one name and value per line, in tessdata/configs. The digits file holds tessedit_char_whitelist 0123456789-. Put its name at the end of config, after every option.
How many Tesseract parameters are there?
tesseract --print-parameters listed 631 in Tesseract 5.5.3. The names are case sensitive.
Method, limits and sources
How I tested it
Tesseract 5.5.3 from Homebrew, pytesseract 0.3.13 and Python
3.14.7 on a Mac, one thread, with the eng model from
tessdata_fast 4.1.0. The 6 pages are the ones from
Tesseract bounding boxes: a
notice, an invoice and minutes, clean and rough, 726 words.
Each of 18 configs went through image_to_string on
every page, and through the command line to read the error stream.
The scripts and output are in
research/bench/tesseract-config-2026-11-01/.
What I did not test
-
Windows. pytesseract splits config with
posix=Falsethere, so quote marks act differently. - Tesseract 4, tesserocr, tesseract.js and other languages.
- Real scans. The pages are ones we wrote and made to look like scans.
Sources
- pytesseract 0.3.13 source: how it builds the command
- Tesseract command line usage
- The digits config file
-
tesseract --help-extraand--print-parametersfrom 5.5.3, read November 1, 2026 - We make the Apify Actor. Tesseract and pytesseract are free tools we do not make.