On Runtime, OCR runs next to the documents, not on your servers. Scans arrive from customers, email and crawlers. Every sandbox is a Firecracker microVM with its own kernel. The image decoders that read the scans therefore work on a machine that holds only that batch. OCR keeps CPUs busy, and Runtime bills what it uses. A 2 vCPU, 4 GiB sandbox costs $0.08 an hour at full load and $0.03125 an hour idle (pricing). Ubuntu 24.04 shipped Tesseract 5.3.4 and OCRmyPDF 15.2.0 on 25 October 2026.
Versions and packages
| What | Ubuntu 24.04 | Upstream on 25 October 2026 |
|---|---|---|
| Tesseract engine | tesseract-ocr 5.3.4 |
5.5.3 on GitHub |
| Language data | tesseract-ocr-eng, -deu, -fra, ... (1:4.1.0-2) |
tessdata repositories on GitHub |
| Scanned PDF to searchable PDF | ocrmypdf 15.2.0 |
17.13.0 on PyPI |
| Python wrapper | none | pytesseract 0.3.13 on PyPI |
| In-browser or Node, no binary | none | tesseract.js 7.0.0 on npm |
Language packs are named tesseract-ocr- plus Tesseract's three-letter code:
tesseract-ocr-deu for German, tesseract-ocr-fra for French.
Read the text in an image
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ timeoutSeconds: 1800 });await sbx.exec( "sudo apt-get update -qq && sudo apt-get install -y -qq tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu", { check: true, timeoutMs: 600_000 },);await sbx.network.off(); // the scans stay on this machineawait sbx.files.upload("./invoice.png", "/workspace/invoice.png");const text = await sbx.exec(["tesseract", "invoice.png", "-", "-l", "eng+deu", "--psm", "3"], { check: true, timeoutMs: 300_000,});console.log(text.stdout);await sbx.exec(["tesseract", "invoice.png", "invoice", "-l", "eng", "tsv"], { check: true });const tsv = await sbx.files.readText("/workspace/invoice.tsv");const words = tsv .split("\n") .slice(1) .map((line) => line.split("\t")) .filter((cols) => cols.length === 12 && cols[11]!.trim() && Number(cols[10]) > 80);console.log(words.length, "words above 80% confidence");Pythonimport csvimport iofrom withruntime import Sandboxwith Sandbox.create(timeout_seconds=1800) as sbx: sbx.exec("sudo apt-get update -qq && sudo apt-get install -y -qq " "tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu", check=True, timeout_ms=600_000) sbx.network.off() # the scans stay on this machine sbx.files.upload("invoice.png", "/workspace/invoice.png") print(sbx.exec(["tesseract", "invoice.png", "-", "-l", "eng+deu", "--psm", "3"], check=True, timeout_ms=300_000).stdout) sbx.exec(["tesseract", "invoice.png", "invoice", "-l", "eng", "tsv"], check=True) rows = csv.DictReader(io.StringIO(sbx.files.read_text("/workspace/invoice.tsv")), delimiter="\t", quoting=csv.QUOTE_NONE) words = [r for r in rows if r["text"] and r["text"].strip() and float(r["conf"]) > 80] print(len(words), "words above 80% confidence")-as the output base sends the text to stdout. A result keeps up to 64 KiB of output. For long documents, write the text to a file and read it withfiles.readText.-l eng+deucombines languages for mixed documents.- The
tsvoutput gives every word with its box and confidence. An agent needs that to find a total or a date by its position. - The commands are arrays, so a file name cannot inject shell syntax.
Output formats
From Tesseract's command-line documentation, read 25 October 2026:
| Output config | File written | Use |
|---|---|---|
| (none) | out.txt |
Plain text |
pdf |
out.pdf |
The image with an invisible, searchable text layer |
hocr |
out.hocr |
HTML with word boxes |
tsv |
out.tsv |
One row per word: position, confidence, text |
--psm sets page segmentation: 3 is automatic, 6 assumes one
uniform block of text.
tesseract --list-langs shows the installed languages.
Make a scanned PDF searchable
Tesseract reads images, not PDFs. OCRmyPDF does the whole job. It renders the pages, runs Tesseract, and writes a PDF with a text layer. It also writes a plain-text sidecar if you ask for one.
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ image: "ocr", diskMiB: 6144, timeoutSeconds: 3600 });await sbx.files.upload("./scan.pdf", "/workspace/scan.pdf");await sbx.exec( "ocrmypdf -l eng --deskew --rotate-pages --skip-text --sidecar scan.txt scan.pdf searchable.pdf", { check: true, timeoutMs: 1_800_000 },);await sbx.files.download("/workspace/searchable.pdf", "./searchable.pdf");await sbx.files.download("/workspace/scan.txt", "./scan.txt");The flags are from OCRmyPDF's cookbook. --deskew straightens tilted pages,
--rotate-pages fixes pages scanned sideways, and --skip-text leaves alone
pages that already have text. --force-ocr does the opposite.
For OCRmyPDF 17 instead of Ubuntu's 15, its installation guide says to
install the Ubuntu package for the dependencies, then uv tool install ocrmypdf. uv is already in every sandbox, and it installs to
/workspace/.local/bin, which is first on PATH.
Start every sandbox with OCR installed
The ocr image the PDF sample uses, as a custom image. Add a
tesseract-ocr-<lang> package for each language you read:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "ocr", recipe: { apt: ["tesseract-ocr", "tesseract-ocr-eng", "tesseract-ocr-fra", "ocrmypdf"], pip: ["pytesseract==0.3.13"], },});Pythonfrom withruntime import RuntimeRuntime().images.build(name="ocr", recipe={ "apt": ["tesseract-ocr", "tesseract-ocr-eng", "tesseract-ocr-fra", "ocrmypdf"], "pip": ["pytesseract==0.3.13"],})Building is free, and without credit counts toward its hours; an account without credit stores three images free.
Throughput and limits
- CPU. OCR is CPU-bound. Split a large archive across sandboxes, one batch each: a paid account runs 100 at once, an account without credit four.
- Disk. Rendered PDF pages take room. The default 4 GiB disk had about
2.5 GiB free on 24 September 2026. For big PDFs, ask for
diskMiB: 6144or more, up to 10 GiB without credit. - Time. A command's default timeout is 60 seconds. Long PDFs need
timeoutMs. Set the sandbox'stimeoutSecondslonger than the job.
To feed the text to a model that answers questions about it, see a data analysis agent. To turn Office files into PDFs first, see LibreOffice in a sandbox. To clean up images before OCR, see ImageMagick in a sandbox.
Sources
- Tesseract command-line usage, https://tesseract-ocr.github.io/tessdoc/Command-Line-Usage.html, read 25 October 2026
- Tesseract releases, https://github.com/tesseract-ocr/tesseract/releases/latest, read 25 October 2026
- OCRmyPDF cookbook and installation, https://ocrmypdf.readthedocs.io/en/latest/cookbook.html and https://ocrmypdf.readthedocs.io/en/latest/installation.html, read 25 October 2026
- Ubuntu 24.04 tesseract-ocr, tesseract-ocr-eng and ocrmypdf packages, from the noble universe index at http://archive.ubuntu.com/ubuntu/dists/noble/universe/binary-amd64/, read 25 October 2026
- PyPI ocrmypdf and pytesseract, npm tesseract.js, read 25 October 2026
Facts on this page were checked on 25 October 2026.