Versions follow MAJOR.MINOR.PATCH (src/version.py); Apify shows MAJOR.MINOR from .actor/actor.json.
Every run logs its version and records it in the RUN_STATS key-value record.
- A run that returns nothing (every input bad, private, blocked or unreachable, or an empty input) now ends
SUCCEEDED with an empty dataset and the reason as its status message and in the log, instead of FAILED. Only an
unexpected error still fails the run.
RUN_STATS keeps the reason as before.
- No change to output fields or price.
- Waits out longer
Retry-After answers: when a site or API asks it to wait before retrying, it now waits up
to 90 seconds (was 30), once per site, with at most 3 minutes of such long waits per run; a longer wait, or a
site that asks again after it was waited out, is reported with the reason instead of stalling the run.
- Narrower AI opt-out rule: a page is skipped as opting out of AI use only when the site's robots.txt
disallows it for a general AI token (Google-Extended, Applebot-Extended, CCBot, or OpenAI's, Anthropic's or
Perplexity's crawlers and user fetchers). Blocking only one company's crawler (Bytespider, Meta-ExternalAgent,
Amazonbot, Diffbot, Omgilibot, cohere-ai) no longer counts: GitHub and Notion pages, for two, are read now.
- No change to input, output or price.
urls is no longer marked required, so AI agents (Apify's MCP server) see that a dataset alone (datasetId) is enough. Nothing else changes: a run with neither still stops with a clear message.
- New: image links from another actor's dataset (
datasetId, with datasetUrlField), so it can run right
after any actor that outputs image links, from that actor's Integrations tab
("datasetId": "{{resource.defaultDatasetId}}"). Each item's link is read like a urls line, in the dataset's
order, duplicates read once; urls is ignored then, so its default (which Apify fills into runs started by an
integration or the API) is never fetched or charged. The field is a name or a dotted path; left empty, it's found
among imageUrl (Bulk Image Downloader), image, displayUrl (Instagram scrapers), images, src and url, then one level
down. A list of links gives its first. Read with the shared dataset reader (as in PDF to Text Converter): the
user's run token, read-only, at most 20,000 items and 10,000 distinct links. A dataset that can't be read, is the
run's own output, or has no links fails the run clearly, before anything is downloaded. RUN_STATS.dataset has
the counts.
- New output fields
sourceTitle and sourceIndex: the dataset item an image came from (its title or name, and
its position), so results join back to it; null for URLs typed in.
- Price and pricing events unchanged. A run without
datasetId behaves exactly as before.
- 1 ready-to-run example published on Apify Store and linked from the README.
- Cheaper on paid Apify plans: $3.80 per 1,000 images on Starter, $3.60 on Scale and $3.50 on Business ($4.00 on the Free plan).
- Input field descriptions rewritten for AI agents (Apify's MCP server shows agents only the description, not the
form): each now states its default, its allowed range, the value of each option and how it combines with other
fields. No change to field names, types, defaults or behaviour.
- Internal: the OCR code (image preparation, the tesseract wrapper, the per-image worker process and the language
list) moved into the shared
mms_ocr package, so document-to-text reads scanned PDF pages the same way. No change
in behaviour or output.
First release.
- Reads the text in images the user supplies by URL: PNG, JPEG, WebP, TIFF, GIF and BMP, plus one-page PDFs
rendered at 300 DPI. Animated GIF/WebP: first frame (
frameCount, truncated). Multi-page TIFFs and PDFs are
refused with the reason, uncharged.
- OCR with the tesseract command line (Tesseract 5, LSTM engine, Debian's tessdata models) in 32 languages, up to 4
per run; five layout modes (automatic, automatic with orientation detection, one block, one line, scattered text).
- One TSV recognition pass per image gives the text (lines, paragraphs and blocks), the mean word confidence, and
optionally every line and word with its box in pixels and its confidence.
- Images are prepared in a separate process with a deadline (3 minutes) and a memory cap, tesseract included: format
read from the bytes and limited to the formats above, 50-megapixel cap checked from the header before decoding
(Pillow's decompression-bomb check set to the same cap and made an error), EXIF orientation applied, transparency
flattened onto white, 16-bit and CMYK converted to 8-bit.
- Downloads through the shared client (robots.txt incl. AI-crawler opt-outs, private-network guard, ports 80/443),
40 MB per image, 2 GB per run. Temporary files are deleted as soon as each image is read.
- Charged per image with text, through Apify's standard
apify-default-dataset-item event ($5.00 per 1,000 images
plus the $0.00005 run start). Images with no text (noTextFound) and failed images are never charged, and don't
use up the "Max images per run" or the maximum cost per run: a result is reserved before each download and given
back if the image yields nothing.
- Failure isolation: a failing image only affects itself; the run fails only when every image failed (images with
no text don't count as failures).
RUN_STATS lists every image's outcome and counts per reason.
Before building (ACTOR-CHECKLIST.md, section 0), 2026-09-24:
- Source and terms: no fixed source. The actor fetches only the image URLs the user supplies (the "tools that
only process URLs or files the user supplies" class allowed under PLAN.md's legal hold), as a logged-out visitor,
honouring robots.txt and AI-crawler opt-outs. The default input is two public-domain files on Wikimedia Commons
(upload.wikimedia.org robots.txt:
User-agent: * / Disallow: /wikipedia/commons/archive/ only).
- Demand (store_merged.json, 30-day users): direct image-to-text OCR actors ~54 (zenomastro/image-ocr-text-
extractor 27 at $5.00/1k images, gochujang 8 at $2.00/1k, welcoming_fireplace 7 at $10.00/1k, amanatools 2 at
$1.50/1k); Google Lens "image to text" OCR actors, the same job on a surface we don't build on, ~197 more
(s-r/google-lens-ocr 85 at $6.00/1k, zen-studio 84, getascraper 20).
- Licences of every component (read from the Debian 13 packages' copyright files in the base image and the
wheels' metadata): Tesseract 5.5.0 and the tesseract-ocr-* language models Apache-2.0; Leptonica BSD-2-clause
style; libarchive, libgif, libwebp, libtiff, libjpeg-turbo, libpng, libopenjp2, libcurl BSD/MIT/ISC/libtiff/libpng
licences (their GPL mentions are autoconf/libtool build files with the usual exceptions); Pillow MIT-CMU;
pypdfium2 BSD-3-Clause/Apache-2.0 with PDFium BSD-3 (bundled ICU's GPL text is an Autoconf-exception build
script). Not used: PyMuPDF (AGPL), pdf2image/poppler (GPL).