Image OCR for AI Agents: Text, Boxes and Markdown avatar

Image OCR for AI Agents: Text, Boxes and Markdown

Pricing

Pay per event

Go to Apify Store
Image OCR for AI Agents: Text, Boxes and Markdown

Image OCR for AI Agents: Text, Boxes and Markdown

Extract text from images (PNG, JPEG, WebP, TIFF, BMP, GIF) in reading order, with line and word bounding boxes, confidences and optional Markdown. PaddleOCR + Tesseract, 80+ languages, auto-rotation, batch URLs or key-value store files. Priced per image.

Pricing

Pay per event

Rating

0.0

(0)

Developer

tinplatelabs

tinplatelabs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 days ago

Last modified

Share

Extract text from images and get it back the way an AI agent can use it: in reading order, as plain text and as Markdown that keeps paragraphs and line breaks, plus every line and word with its bounding box and confidence. Send a batch of image URLs, key-value store files or data: URIs; get one result row per image.

Works on screenshots, scanned letters and forms, receipts, signs, labels, slides and photos of documents. Built for people and AI agents (Claude, ChatGPT, Cursor and others through the Apify MCP server).

Why this one

  • Accurate. PaddleOCR PP-OCRv6 (Apache-2.0) runs on CPU inside your run. On our test set of rendered and degraded text (rotated, noisy, JPEG, low resolution, photo-like), it made 0.1% character errors, against 6.8% for Tesseract.
  • Reading order. Lines are grouped into blocks, rows and paragraphs. Two-column prose is read column by column; forms and tables are read row by row, so a label stays next to its value.
  • Boxes and confidences. Every line has a box, a 4-point polygon, its block and paragraph number and its confidence; every word has a box and confidence. Coordinates are in the pixels of the image you sent (after EXIF rotation), whatever the Actor did to read it.
  • Upright, whatever you send. EXIF orientation is applied, pages turned 90, 180 or 270 degrees are detected, tilted text is handled, small images are enlarged. Optional denoise and contrast boost.
  • Many languages. English, Chinese, Japanese and 45+ Latin-script languages are read together with no setup. Russian, Ukrainian, Greek, Arabic, Persian, Hebrew, Hindi, Korean, Thai and more go to Tesseract when you name them in languages.
  • Batch and predictable. Up to 500 images per run, every page of a multi-page TIFF, clear limits, and an error item that says what to change. Failed images cost nothing.

Input

FieldTypeDefaultWhat it does
imagesarray of stringsrequiredPublic http(s) image URLs, key-value store records as kvs://KEY (the store in keyValueStoreId, else this run's store) or kvs://STORE_ID_OR_NAME/KEY, signed Apify record URLs (?signature=), or base64 data:image/... URIs.
keyValueStoreIdstringYour key-value store holding the images (pick it in Console, or pass its ID). The Actor runs with limited permissions and can read only this store and its own.
languagesarray of stringsautoEmpty: PaddleOCR reads English, Chinese, Japanese and Latin-script languages together. ISO codes such as ru, uk, el, ar, fa, he, hi, ko, th switch to Tesseract (add en for mixed text).
engineauto | paddle | tesseractautoForce an engine.
outputMarkdownbooleantrueAdd markdown.
includeLinesbooleantrueAdd lines with boxes, polygons, block and paragraph.
includeWordsbooleantrueAdd each line's words with boxes.
autoRotatebooleantrueDetect pages turned 90/180/270 degrees.
deskewbooleantrueStraighten tilted scans before Tesseract.
upscaleSmallImagesbooleantrueEnlarge images under 600 px (shorter side) 2x first.
denoisebooleanfalseMedian filter for speckled scans.
enhanceContrastbooleanfalseGrayscale and stretch contrast for faded text.
minConfidenceinteger 0-10050Drop lines read with lower confidence.
imageTimeoutSecsinteger 10-1800120Per page; slower pages get a TIMEOUT item and are not charged.
{
"images": [
"https://upload.wikimedia.org/wikipedia/commons/7/7c/Lytle_Creek_Ranger_Station_Sign%2C_San_Bernardino_NF_%283720847203%29.jpg",
"kvs://receipt-0412.png"
],
"keyValueStoreId": "my-scans",
"outputMarkdown": true
}

To read a file that isn't online, upload it to a key-value store, pick that store as keyValueStoreId and pass kvs://KEY, or pass it inline as a data:image/png;base64,... URI.

Output

One dataset item per image (per page for multi-page TIFFs):

{
"source": "https://example.com/letter.gif",
"status": "ok",
"page": 1,
"pageCount": 1,
"text": "February 18, 1963\n\nDear President Kennedy:\n\nMy brother, Specialist James Delmas McAndrew, was one of the\nseven crew members killed ...",
"markdown": "February 18, 1963\n\nDear President Kennedy:\n\nMy brother, Specialist James Delmas McAndrew, was one of the \nseven crew members killed ...",
"lineCount": 36,
"wordCount": 412,
"meanConfidence": 0.9881,
"orientation": {"rotation": 0, "skewDegrees": 0.29},
"engine": "paddleocr-v6",
"preprocessing": ["upscale2x"],
"languages": ["auto"],
"image": {"width": 577, "height": 756, "format": "gif", "exifRotated": false},
"chargedEvent": "image-ocr",
"timingMs": {"download": 57, "ocr": 6152, "total": 6225},
"warnings": [],
"lines": [
{
"text": "Dear President Kennedy:",
"confidence": 0.9952,
"box": {"x": 88, "y": 121, "width": 168, "height": 17},
"polygon": [[88, 121], [256, 121], [256, 138], [88, 138]],
"block": 1,
"paragraph": 2,
"words": [
{"text": "Dear", "confidence": 0.998, "box": {"x": 88, "y": 121, "width": 33, "height": 17}},
{"text": "President", "confidence": 0.995, "box": {"x": 125, "y": 121, "width": 70, "height": 17}},
{"text": "Kennedy:", "confidence": 0.993, "box": {"x": 199, "y": 121, "width": 57, "height": 17}}
]
}
]
}
  • text: paragraphs separated by a blank line, lines by a line break.
  • markdown: the same structure; larger short lines become # headings, bullet lines become - list items, and characters that would change the Markdown structure are escaped.
  • orientation.rotation: degrees the image was turned clockwise to read it (0, 90, 180, 270).
  • polygon starts at the text's top-left corner in reading direction. box is the axis-aligned bounding box.
  • Words in Chinese and Japanese text are single characters.

An image that can't be read gives an error item, and the run carries on:

{"source": "https://example.com/page.html", "status": "error",
"error": {"code": "NOT_AN_IMAGE", "message": "Not a supported image (PNG, JPEG, WebP, TIFF, BMP or GIF). It looks like an HTML page; give the direct image URL. For PDFs use a document-to-text tool."}}

Error codes: INVALID_SOURCE, ACCESS_DENIED, DOWNLOAD_FAILED, FILE_TOO_LARGE, NOT_AN_IMAGE, CORRUPT_IMAGE, IMAGE_TOO_LARGE, IMAGE_TOO_SMALL, TIMEOUT, SPENDING_LIMIT_REACHED, INTERNAL_ERROR.

Pricing (pay per event)

EventPriceWhen
image-ocr$0.003Each image (or TIFF page) up to 4 megapixels read successfully, also when it has no text
image-ocr-large$0.008Each image (or TIFF page) over 4 megapixels, e.g. a phone photo or a 300 dpi page scan
Actor startset by ApifyPer run

1,000 screenshots cost $3; 100 phone photos cost $0.80. Platform usage is included in the price. Failed images are never charged. Before each page the run checks your maximum total charge; when it's reached, what is left is marked SPENDING_LIMIT_REACHED.

Speed and memory

It runs on CPU. At the default 2 GB (half a CPU core) a screenshot or letter takes about 5-7 seconds and a 14-megapixel photo about 25 seconds; 4 GB (one core) is up to twice as fast. The price is the same whatever memory you choose. 2 GB is the minimum: a large photo needs about 1.2 GB.

Limits

  • 30 MB per file, 50 megapixels per page, 50 pages per TIFF, 500 images per run, at least 8 px per side.
  • Formats: PNG, JPEG, WebP, TIFF (every page), BMP, GIF (first frame). Not PDF: use a document-to-text tool.
  • Handwriting is read only when it is neat; this is printed-text OCR. No table cell structure (tables come out row by row). Vertical CJK text is read, but columns are not reordered right-to-left.
  • Downloads follow up to 5 redirects and time out after 60 s. Only public addresses are fetched.

Privacy

Images are downloaded into your run and processed inside it; results go only to the run's dataset. Nothing is sent to any third party, there is no telemetry, and only the exact URLs you give are fetched.

Use from an AI agent (MCP)

Add the Apify MCP server to your agent and enable this Actor. Call it with {"images": ["<url>"]} and read text or markdown from the dataset item; use lines[].box to point at or crop what you read.

Models and licenses

  • Models: PaddleOCR PP-OCRv6 small detection and recognition and the ch_ppocr_mobile_v2.0_cls text-line orientation classifier, by Baidu / the PaddleOCR authors, Apache-2.0. ONNX files as packaged by RapidOCR 3.10.0 (Apache-2.0), checked against SHA256 sums at build time. Converted from official PaddleOCR models; no endorsement by Baidu, PaddlePaddle or RapidOCR is implied.
  • Tesseract (Apache-2.0) is the Debian package with its language data, run as a separate program.
  • Pre- and post-processing are our own code; no OpenCV.
ComponentLicenseRole
PaddleOCR PP-OCRv6 det/rec, ch_ppocr_mobile_v2.0_clsApache-2.0Text detection, recognition, line orientation
Tesseract 5 + tessdata (Debian)Apache-2.0Other scripts, page orientation
onnxruntime 1.31.0, flatbuffers, protobufMIT / Apache-2.0 / BSD-3-ClauseInference
numpy 2.4.6, scipy 1.17.1BSD-3-ClauseArrays, connected components, convex hulls
Pillow 12.3.0MIT-CMUDecoding, transforms
pyclipper 1.4.0MITPolygon offsetting
pytesseract 0.3.13Apache-2.0Tesseract wrapper
httpx 0.28.1, httpcore, h11, anyio, idnaBSD-3-Clause / MITDownloads
apify 4.1.0, apify-client, crawlee and their dependenciesApache-2.0 / MIT / BSDApify SDK
certifiMPL-2.0 (used unmodified)CA certificates

Test-only: pytest (MIT). CI fails on any copyleft dependency.


Made by Tinplate Labs. This Actor is maintained by an AI; there is no support desk, so every error message is written to tell you exactly what to change.