Image to Text OCR: Arabic, Scans and Screenshots avatar

Image to Text OCR: Arabic, Scans and Screenshots

Pricing

$5.00 / 1,000 image reads

Go to Apify Store
Image to Text OCR: Arabic, Scans and Screenshots

Image to Text OCR: Arabic, Scans and Screenshots

Read text from image links or base64: screenshots, scans and photos (receipt photos read at lower confidence and are flagged for review). English and Arabic built in, line boxes, a quality report per image. No browser. Empty and unreliable images are not charged.

Pricing

$5.00 / 1,000 image reads

Rating

0.0

(0)

Developer

Mohammed Samaan

Mohammed Samaan

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Give this Actor image links, or the images themselves as base64 text, and get back the text in reading order, a box for every line, and a quality report that tells you which results to look at. Screenshots, scanned pages and pictures with Arabic or mixed Arabic and English text are the target; phone photos of paper (receipts, for example) are read too, at a lower confidence, and are flagged for review. English and Arabic are built in, and Arabic comes back in the right reading order.

It was built for people who feed images to a document pipeline, a search index or an LLM, and who need two things most OCR services do not give: a signal for which results are shaky, and a guarantee in the pricing that images with nothing readable on them cost nothing. Everything runs over plain HTTP inside the Actor: no browser, no proxy, no login, and your images are not sent to any other service.

What you get

  • One dataset row per image with text, lines (each with a confidence and a box on your picture, even when the picture had to be turned or cropped before reading), optional blocks and word boxes, wordCount, format, width, height and warnings.
  • A quality report on every image: mean confidence, whether the picture was turned (orientationCorrected) or straightened (skewCorrected), whether the strong clean-up was used, the scale factor, the lines under 60 confidence, the result of a content check that does not use the engine's confidence, whether an unreliable image may be handwriting, how many lines mix right-to-left and left-to-right text, whether the language is experimental, and needsReview.
  • needsReview flags the conditions listed in the quality report. It does not guarantee that an image with needsReview: false was read correctly. It is true when the mean confidence is under 70, when the text fails the content check (many tokens that cannot be words, words stuck together, many single characters, many tiny lines), when a quarter or more of the lines are under 60 confidence, when the image was judged unreliable, or when a reading attempt failed. It cannot see an error that produces plausible text, so read the images that matter.
  • You pay only for images that were read. An image with no text, an image whose result is unreliable and an image that fails are never charged. The unreliable ones are still delivered, so you can look at them.
  • Turned and tilted pictures: text that runs sideways or upside down is turned back (90, 180 or 270 degrees), and a picture tilted by more than half a degree (up to 7) is straightened. JPEG files with an EXIF orientation are shown the way the camera meant them to be.
  • Photos on a dark table: a pale page on a dark background is cropped to the page before reading. The result says so and the boxes stay on the picture you sent.
  • Clean-up only when needed: the picture is read as it is first. If that result is poor, it is read again after clean-up (contrast, speckle removal, adaptive black and white for shadows and low light, light text on dark is inverted), enlarged when the text is small, and turned when the result looks like garbage. At most 5 readings per image; the best one is delivered.
  • Right-to-left text: Arabic (and other right-to-left scripts) comes back in logical order, first word first. A line that mixes Arabic and Latin words or numbers keeps each run in its own order. Tables whose columns are read one at a time are put back into rows.
  • Formats: JPEG, PNG, WebP, GIF (first frame), BMP and TIFF (first page; only uncompressed TIFF was tested). Transparent backgrounds are put on white.
  • Share links: Google Drive file links and Dropbox links are turned into direct download links. Any other link must point straight at the image.

Sample input

{
"urls": ["https://upload.wikimedia.org/wikipedia/commons/b/bc/Grocery_Store_Receipt_in_Vienna.jpg"],
"ocrLanguages": ["eng"],
"outputFormat": "lines",
"preprocess": "auto"
}

This is the prefilled input (a public-domain photo of a crumpled receipt). For Arabic or mixed Arabic and English use "ocrLanguages": ["ara", "eng"]. To send images without hosting them, put them in imageBase64 as plain strings or data URLs:

{ "imageBase64": ["data:image/png;base64,iVBORw0KGgo..."], "ocrLanguages": ["eng"] }

Sample output

Real output of this Actor (a local run with a stand-in for the platform's billing call) on a generated test image of printed text. Only the first two lines are shown.

{
"schemaVersion": 1,
"index": 0,
"url": "https://example.org/q3-printed.png",
"status": "ok",
"format": "png",
"width": 1242,
"height": 278,
"text": "Optical character recognition turns photographs of documents into text.\nInvoice 2026-1043 was issued on 21 October 2026 for 123.50 dollars.\nPayment is due within thirty days of the date shown above.\n\nQuestions about this invoice can be sent to the billing office.",
"lines": [
{ "text": "Optical character recognition turns photographs of documents into text.", "confidence": 95.9, "bbox": { "x0": 32, "y0": 32, "x1": 1032, "y1": 62 }, "rtl": false },
{ "text": "Invoice 2026-1043 was issued on 21 October 2026 for 123.50 dollars.", "confidence": 95.9, "bbox": { "x0": 33, "y0": 86, "x1": 1014, "y1": 109 }, "rtl": false }
],
"wordCount": 42,
"quality": {
"meanConfidence": 95.9,
"orientationCorrected": 0,
"skewCorrected": 0,
"preprocessApplied": "none",
"scaleFactor": 1,
"lowConfidenceLines": [],
"sanity": { "judged": true, "ok": true, "score": 1, "reasons": [] },
"possibleHandwriting": false,
"mixedDirectionLines": 0,
"experimental": false,
"needsReview": false,
"warnings": []
},
"warnings": [],
"error": null,
"errorKind": null,
"charged": true
}

An image with nothing on it keeps its place in the dataset, says so and is not charged (real output, shortened):

{ "status": "no_text_found", "format": "png", "width": 900, "height": 600, "text": "", "lines": [], "wordCount": 0, "warnings": ["No text was found in the image."], "error": null, "errorKind": null, "charged": false }

An image that cannot be read says why and is not charged:

{ "status": "error", "url": "https://example.org/login-page", "text": null, "error": "The link returned an HTML page, not an image (often a login, error or consent page).", "errorKind": "not_an_image", "charged": false }

Input

FieldTypeDefaultWhat it does
urlslist of linksnonePublic links to images. Up to 100 per run in total with imageBase64; 25 MB and 50 megapixels (20,000 pixels on a side) each. Duplicates are read once. A data: URL in this list is treated as base64 data.
imageBase64list of stringsnoneImages as plain base64 text or data URLs. Each item is a string, never an object. At least one of urls and imageBase64 is required. A bad item becomes an error row for that item; the rest of the run is not affected.
ocrLanguageslist of codes, at most 3["eng"]Language of the text, for example ["ara", "eng"], ["deu"], ["chi_sim"]. Put the main language first. eng and ara are built in; any other official Tesseract tessdata_fast code is downloaded when needed and its output is marked experimental. An unknown code stops the run with a message naming it.
outputFormatlines, text, blocks, alllinestext: only text. lines: adds lines with confidence and box. blocks: adds blocks (paragraphs with boxes) and no lines. all: lines with a box and confidence for every word, and blocks. Fields you do not ask for are null.
preprocessauto, none, strongautoauto: read as it is, clean up only when the result is poor. none: never clean up. strong: always clean up first.

Output fields

FieldMeaning
schemaVersionAlways 1 for this layout.
indexPosition of the image in your input after duplicates were removed. Rows are written as images finish, so sort by index to get input order.
url, finalUrl, sourceThe link you gave (null for base64 items), the address after redirects, and what the image came from: the direct link that was fetched (differs from url when a share link was rewritten) or imageBase64[n].
statusok, no_text_found, unreliable, error, skipped_charge_limit or skipped_repeated_failures.
format, width, height, framesWhat the file is, its size in pixels (as shown, after any EXIF turn) and the number of frames or pages it holds.
textAll the text in reading order, one line per row, blocks separated by a blank line. A wide gap between neighbouring words (a table column) is written as two spaces. null on an error row, empty when nothing was found.
linestext, confidence (0 to 100), bbox (x0, y0, x1, y1 in pixels of the picture you sent), rtl; with outputFormat: "all" also words (each with its own box and confidence).
blocksindex, text, bbox, lineIndexes, confidence.
wordCount, languagesWords read, and the OCR languages used.
qualitymeanConfidence, orientationCorrected, skewCorrected, preprocessApplied (none or strong), scaleFactor (above 1 enlarged, below 1 reduced), lowConfidenceLines (indexes of lines under 60), sanity (judged, ok, score, reasons), possibleHandwriting, mixedDirectionLines, experimental, experimentalLanguages, needsReview, warnings.
warningsAnything uncertain or done to the picture: turned, straightened, cropped, low confidence, possible handwriting (unreliable images only), table or multi-column layout, animated GIF read from its first frame, a server that mislabelled the file, billing_error.
error, errorKindSpecific reason when status is error, else null. Kinds: http_error, refused_address, download_failed, file_too_large, empty_file, not_an_image, unsupported_format, image_too_large_pixels, corrupt_image, invalid_base64, language_unavailable, ocr_unavailable, ocr_failed, conversion_timeout, conversion_memory, conversion_crashed, conversion_failed, charge_limit, circuit_open, unexpected_failure.
chargedWhether the image-read event was billed for this image.

A run summary (SUMMARY in the key-value store) counts images read, without text, unreliable, failed and skipped, and how many were billed.

Pricing

Pay per event, one event:

EventPriceWhen
image-read$0.005each image that was read, produced text and passed the content check (status ok)

Worked examples: 1,000 clean screenshots or scans cost $5.00. 100 images of which 12 are blank or unreadable cost 88 x $0.005 = $0.44. 20 images cost $0.10.

Not charged: links that fail (HTTP errors, refused addresses, files over 25 MB or 50 megapixels, damaged or non-image files), images with no text (no_text_found), and images whose text is unreliable (unreliable: delivered, flagged, not billed).

How billing works: an image is charged once, after it was read. If the charge fails (an error from the platform) the text is still delivered in full with a billing_error warning and charged: false, and the run carries on. If you set a maximum cost per run, the Actor stops when it is reached: the remaining images get a row with status: "skipped_charge_limit", and an image that was read but could not be billed because the limit was reached is not delivered for free. If pay-per-event pricing is not active for a run, images are still delivered, charged stays false, and the run status says so once.

Use with AI agents / MCP

Send this input:

{ "urls": ["https://example.org/receipt.jpg"], "ocrLanguages": ["eng"], "outputFormat": "text" }

Read these fields from each dataset item:

  1. status must be ok. If it is error, read error and errorKind. no_text_found means there was nothing to read; unreliable means text came back but should not be trusted.
  2. quality.needsReview: when true, tell the user which quality.lowConfidenceLines or warnings to check before relying on the text. When false, the checks listed above found nothing; that is not proof the text is right.
  3. text for the content; with outputFormat: "lines" use lines[].bbox to point at where a line is on the picture.

Images can also be sent as base64 strings in imageBase64 (an array of strings).

Benchmark

Settings: the Actor's default input (preprocess: auto, outputFormat: lines) with ocrLanguages: ["ara", "eng"] for the two Arabic files and ["eng"] for the others, one image per run, 21 Oct 2026, the same code on Windows and in the Linux image (identical results). 17 files, so treat the numbers as a measurement of these files only. Character error rate (CER) compares the text with the exact text drawn into the image after lower-casing, removing punctuation and spaces, and folding Arabic diacritics and alef variants. The synthetic files are drawn by us with known text (Liberation Sans and Noto Naskh Arabic); the three photos are real, with key words read by eye.

FileWhat it testsResult
printed English, small text, low contrast, screenshot, low light, warped invoice on a tableclean-up, upscaling, croppingCER 0 on all six
turned 90 and 180 degreesorientationCER 0 on both, turned back automatically
tilted 3.5 degrees with 3,000 specks of noiseskew and noiseCER 0.098, needsReview: true
three Arabic linesArabic accuracy and orderCER 0, word F1 1.0
four mixed Arabic and English linesline and word orderall 4 lines in order, words in order on 3 of 4 lines, CER 0.164 (one line came back as "VAT 6" plus a stray token), needsReview: true
a table of 5 rowsrows keptrows in order, CER 0.123: the middle column was skipped by the engine on this file
crumpled phone photo of a receipt (13 megapixels, dark table)real photo recalllocal run: 29 of 32 key tokens, mean confidence 57.8, needsReview: true; on the Apify platform the same photo came back unreliable (confidence 60.9) and was not charged
receipt photo hanging on a tree (blurry, 640 x 480)very poor photonothing read, not charged (0 of 4 words)
handwritten notehandwritingnothing read, not charged (0 of 12 words). Handwriting is not supported.
blank white image, random noise imageempty inputno text, not charged

Honest notes: the table result shows that a sparse column can be dropped while the confidence of what was read stays high, which is why a table or multi-column layout is flagged needsReview with a warning. The receipt reads at a low confidence, which is why it is flagged. Photos that Tesseract cannot read at all come back empty and free; they are not read badly and billed. Speed is in the Limits section.

Limits

  • OCR quality depends on the picture. The built-in models are Tesseract's fast LSTM models. Clean printed text reads very well; photographed receipts read at a lower confidence and the checks flag them; handwriting, strong blur, glare, curved or crumpled paper and very small print read badly or not at all. A result can pass every check and still contain errors, and a line can be missing without any warning, and a column can be dropped (tables and multi-column layouts are flagged for review, but the flag is a layout check, not proof).
  • Handwriting is not supported. Only an image that fails the checks (status unreliable, not charged) carries the possibleHandwriting flag and the handwriting warning, and the flag is a guess. A charged read at low confidence says "check it by eye" and is flagged for review.
  • Orientation, skew, crop: turning is tried only when the result looks like garbage or the text runs sideways; skew is measured up to 7 degrees; photos taken at an angle (perspective), mixed orientations on one picture and strongly curved pages are not corrected. The crop to a pale page assumes one page on a darker background; it reads such a page as a single column of lines, so a photographed page with two text columns is read less well.
  • Mixed-direction lines: a line that holds both Arabic and Latin words looks the same whichever way it was written, so its word order is decided from the layout of the whole picture. The quality report counts these lines (mixedDirectionLines) and warns; check them.
  • Languages: eng and ara ship with the Actor and were benchmarked. Every other language file (1 to 12 MB, official Tesseract tessdata_fast) is downloaded at the start of the run and its output is experimental: it was not benchmarked, quality.experimental is true and the row carries a warning. Up to 3 languages at once; more languages make OCR slower. Set the language you expect: Arabic text read with ["eng"] can come back as unreliable.
  • Formats: JPEG, PNG, WebP, GIF, BMP, TIFF. Not supported: HEIC, AVIF, SVG, ICO, PDF (use a PDF tool). An animated GIF (tested), WebP or PNG is flagged in the warnings and read as the decoder shows it (a GIF from its first frame), a multi-page TIFF from its first page, and the row says so. Files with an invalid header or a failed checksum are refused as corrupt_image before decoding, because the image decoder can crash on them; if it still stops on a damaged file, the row says the file is probably damaged.
  • Size: 25 MB and 50 megapixels per image (20,000 pixels on a side). Larger pictures are refused with a message. Pictures are reduced to at most about 3,800 pixels on the long side for reading.
  • Speed and memory. One image is read at a time per CPU core (the platform gives one core per 4 GB; the default memory is 2 GB, half a core), while the next images download. Measured in a Linux container with Node 20 at 0.5 core and 2 GB: 0.1 to 3 seconds for clean images, about 9 seconds for a 13 megapixel receipt photo, peak memory under 500 MB; at 1 core and 4 GB about half of those times. A reader is stopped if it reports no progress for 30 seconds before reading has started, or for 120 seconds (or 12 times its median step time, when longer) while reading, and in any case after 300 seconds; the image gets an error row and the run goes on. If 10 images in a row have to be stopped, the run ends early and the rest get status: "skipped_repeated_failures".
  • Public links only. The Actor does not log in, use cookies or fetch addresses on private networks. Only ports 80 and 443 are used.
  • Not supported: layout analysis beyond lines, paragraphs and table rows, form fields, barcodes and QR codes, translating, describing pictures.

FAQ

Do I pay for images with no text? No. Only status ok is charged: images with no text, unreliable results and failures are free.

How do I know if a result can be trusted? Read quality.meanConfidence, quality.lowConfidenceLines, quality.sanity and quality.needsReview. They flag the conditions described above. A false is not a guarantee.

Can I send base64? Yes: imageBase64 takes plain base64 strings and data URLs. Every item is a string.

Which languages? English and Arabic are built in and benchmarked. Set ocrLanguages to another official Tesseract code (for example fra, deu, spa, rus, chi_sim, hin) and its language file is downloaded for the run; the result is marked experimental.

Is the Arabic in the right order? Arabic lines in the benchmark come back in logical order, so a search for the first word of a sentence finds the start of the sentence. Lines that mix Arabic with English words or numbers are ordered by a layout heuristic and counted in the quality report.

Why did my photo come back as unreliable or empty? The text could not be read reliably: blur, glare, handwriting or a language that was not set. Try a sharper picture, set ocrLanguages, or set preprocess to strong.

Why do the boxes not match a turned photo? They do: boxes are on the picture exactly as you sent it (with its EXIF orientation applied), even when the Actor turned, straightened or cropped it to read it.

Open-source credits

Licences were read from each package's and font's LICENSE file in the installed version, and the production tree of the Linux image was scanned with tools/licence-scan.mjs.

Package or fileVersionLicenceUsed for
tesseract.js7.0.0Apache-2.0OCR engine for Node
tesseract.js-core7.0.0Apache-2.0Tesseract compiled to WebAssembly
tessdata_fast (eng, ara, others on demand)main, 21 Oct 2026Apache-2.0 (LICENSE of the repository)OCR language models
@napi-rs/canvas and its Linux binary0.1.65MIT. The prebuilt binary is built on Google Skia (BSD-3-Clause upstream); the Linux binary package ships no licence or notice file, so the Skia notice is not included hereDecoding JPEG, PNG, WebP, GIF and BMP; turning, scaling and writing the pictures that are read
utif3.1.0MITDecoding TIFF
pako1.0.11MIT AND Zlib (the package's declared licence; its LICENSE file holds the MIT text)Dependency of utif
apify3.7.2Apache-2.0Actor runtime
bmp-js, is-url, node-fetch, regenerator-runtime, zlibjs0.1.0, 1.2.4, 2.7.0, 0.13.11, 0.3.1MITDependencies of tesseract.js
idb-keyval, wasm-feature-detect6.3.0, 1.9.0Apache-2.0Dependencies of tesseract.js
Liberation Sans and Noto Naskh Arabic fonts (test fixtures only, used to draw the benchmark and test images)as shipped in pdfjs-dist 4.10.38 and an earlier fixtureSIL Open Font License 1.1Not used by the running Actor

Scan of the shipped Linux image (npm install --omit=dev): 200 packages. Of those 142 are MIT, 22 Apache-2.0, 15 BSD-2-Clause, 8 ISC, 5 BSD-3-Clause, 2 (MIT OR CC0-1.0), 0BSD, BlueOak-1.0.0 (sax), (MIT AND Zlib) (pako), CC-BY-4.0 (caniuse-lite browser data inside the Apify SDK; attribution given here) and 2 with no licence field in their metadata (map-stream, pause-stream, inside the Apify SDK), which ship licence files. Ten packages declare a permissive licence but ship no licence file (the Skia binary above and nine others, mostly inside the Apify SDK tree). No GPL, AGPL, LGPL or OpenRAIL component is installed. The sharp image library (Apache-2.0) was not used because its prebuilt binaries bundle libvips under the LGPL.