Arabic Image OCR & Saudi Invoice QR Reader
Pricing
Pay per event
Arabic Image OCR & Saudi Invoice QR Reader
Fast Arabic + English OCR for screenshots, documents and images (normalised and raw text, lines with confidence, RTL order), plus exact fields from Saudi ZATCA e-invoice QR codes (signature not checked). For receipts and Arabic-Indic digits use Arabic Receipt Reader.
Pricing
Pay per event
Rating
0.0
(0)
Developer
saif alnuaimi
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Fast Arabic + English OCR for screenshots, web pages, chat messages and typed or scanned documents, plus the exact fields from Saudi ZATCA e-invoice QR codes.
- Plain-text mode (
text): low-cost OCR that handles dense, small print well. Lines come with a confidence score and in right-to-left reading order. - Exact QR fields (
qr): the seller name, VAT number, timestamp, invoice total and VAT total, decoded from the e-invoice QR. These are the values encoded in the QR, never guesses from OCR text.
Each image gives you the text exactly as read (textRaw) and a normalised copy (text). In the normalised copy, digits become 0-9, ٫ becomes ., ٬ becomes , and tatweel is removed.
Receipts, invoices, prices or Arabic-Indic digits? Use Arabic Receipt Reader (
arabic-receipt-reader) instead. It reads Arabic-Indic digits much better, gives every number a confidence score, finds the total, subtotal, VAT and line items, checks they add up, and tells you which receipts need a human check.
This tool reads and reports the fields on an invoice. It doesn't issue, send or receive e-invoices, isn't an accredited service provider, and doesn't confirm compliance with ZATCA or UAE rules.
Which mode should I use?
| You have | Use |
|---|---|
| Screenshots, chat messages, web pages, scanned or typed documents | text (this actor) |
| Only the Saudi e-invoice QR values | qr (this actor). Images without a ZATCA QR cost nothing. |
| Receipts, invoices, price lists, anything where the numbers matter | Arabic Receipt Reader |
| Photos of signs, shop fronts or menus | Arabic Receipt Reader (copes better with real-world photos) |
Plain-text mode (text)
This mode runs Tesseract (Arabic + English, tessdata_best models) with automatic upscaling, deskewing and QR masking. A second pass re-reads Arabic-Indic and Persian digits with a dedicated digit classifier.
Warning: plain-text mode reads Arabic-Indic digits (٠-٩) poorly. The digit pass improves them a lot on clean, printed images. On photos, low-resolution images or unusual fonts, digits are still often wrong or dropped. For receipts, invoices, prices or any number you rely on, use Arabic Receipt Reader. Plain-text mode also handles photos of signs badly. Treat it as a tool for screenshots and documents.
Image size: every image is downscaled to at most 4 megapixels before OCR (and upscaling for small text never goes past 4 MP). imageSize in each row shows the original and processed sizes. Line boxes are always in original-image pixels.
Exact QR fields (qr, optional in text with includeQrFields)
When an image contains a Saudi e-invoice QR (ZATCA TLV, base64), you get exactQrFields:
| Tag | Field |
|---|---|
| 1 | sellerName |
| 2 | vatNumber (plus vatNumberFormatValid: 15 digits, starts and ends with 3; this is a flag, never a rejection) |
| 3 | timestamp (plus timestampIso) |
| 4 | invoiceTotal (with VAT) |
| 5 | vatTotal |
| 6–9 | reported as present, with their lengths (hash, signature, public key, certificate signature) |
tagsFound lists the tags in the QR. qrFormat is an informational label: phase1 (tags 1–5, before 2023), phase2-standard (tags 1–7 or 1–8), phase2-simplified (tags 1–9) or other.
We decode the QR TLV but do NOT verify its cryptographic signature/stamp (signatureChecked is always false). A QR that decodes cleanly can still be forged or belong to another invoice. These are the exact fields stored in the QR, not proof that the invoice is genuine or registered.
qr.status is zatca_tlv (decoded), not_zatca_tlv (a QR that isn't a ZATCA invoice QR, e.g. a menu link; its text is in qr.codes[].rawText) or no_qr_found. The QR fields are never filled in from the OCR text.
Input
| Field | Default | Notes |
|---|---|---|
mode | text | text or qr |
imageUrls | Public image links (JPEG, PNG, WebP, GIF, BMP, TIFF) | |
keyValueStoreRecords | Uploaded images: record-key for this run's store, or store-name-or-id/record-key | |
includeQrFields | false | Text mode: also read ZATCA QR fields |
languages | ara+eng | ara, eng or ara+eng |
pageLayout, upscale, deskew, threshold | sensible defaults | Image preprocessing |
digitSecondPass | true | Arabic-Indic digit classifier |
maskQrCodes | true | Blanks QR codes before OCR so they don't become junk text |
outputLines, outputWords, stripTatweel | true, false, true | Output detail |
maxImageSizeMb, maxConcurrency | 20, 2 | Limits |
No images in the input? The actor reads a small bundled sample image (an Arabic/English text sample in text mode, a sample ZATCA QR in qr mode) so you can see the output. The same happens if the example link in the input form can't be downloaded. Sample rows have sample: true and are free. The run's status message and OUTPUT.note say so too (for example "Input image failed to download; returned built-in sample instead").
Example: QR fields only, from files uploaded to a key-value store:
{ "mode": "qr", "keyValueStoreRecords": ["my-invoices/inv-0001.png", "my-invoices/inv-0002.jpg"] }
Output
One row per image. The views are Overview and Exact QR fields. A shortened text row:
{"source": "https://example.com/screenshot.png","sample": false,"status": "ok","mode": "text","text": "فاتورة ضريبية Tax Invoice\nCustomer service: support@example.com\nالعنوان: شارع الملك فهد، الرياض","textRaw": "فاتورة ضريبية Tax Invoice\n...","meanConfidence": 88.4,"primaryScript": "arabic","digitSystems": [],"lines": [{"text": "فاتورة ضريبية Tax Invoice", "textRaw": "فاتورة ضريبية Tax Invoice", "confidence": 91.2, "direction": "rtl", "bbox": [212, 38, 476, 46]}],"width": 900, "height": 320,"imageSize": {"original": [900, 320], "processed": [1800, 640], "downscaledBy": 1.0, "maxProcessedMegapixels": 4.0},"qr": {"status": "no_qr_found", "count": 0, "codes": []},"exactQrFields": null,"chargedEvents": ["plain-text-ocr"]}
A decoded QR adds "exactQrFields": {"sellerName": "...", "vatNumber": "310122393500003", "vatNumberFormatValid": true, "timestamp": "...", "invoiceTotal": "172.50", "vatTotal": "22.50", "qrFormat": "phase1", "tagsFound": [1, 2, 3, 4, 5], "signatureChecked": false}.
Images that can't be read (a broken link, a file that isn't an image, a file that is too large) get a row with status: "error" and an error message. Error rows are free. The OUTPUT record summarises the run: images processed, failed and skipped, sample rows, the events charged and how long it took.
Pricing (pay per event)
| Event | When | Price |
|---|---|---|
plain-text-ocr | Each image read in text mode | $0.003 |
exact-qr-fields | Each invoice whose ZATCA QR was decoded, in qr mode or in text mode with includeQrFields | $0.01 |
chargedEventsin each row lists only the events actually charged for that row.- One
exact-qr-fieldscharge per invoice, never a separate "QR read" charge. Inqrmode, images without a ZATCA QR are free. Error rows and sample rows are always free. - Spending limit: if you set a maximum cost per run, the actor checks before each image that the image's maximum possible price still fits. If it doesn't, the actor stops cleanly and keeps every row saved so far (
OUTPUT.stoppedByChargeLimit,skippedSources). You are never charged for a row that wasn't saved. Intextmode withincludeQrFields, each image needs $0.013 of headroom, because we only know whether it has a QR after reading it.
Limitations
- OCR is not perfect. On our synthetic test set, plain-text mode with the digit pass read about 84% of Arabic-Indic digits correctly (plain Tesseract: about 23%). Real photos score lower. For numbers, use the Receipt Reader.
- Handwriting, decorative calligraphy, heavy diacritics (tashkeel) and stretched display lettering are read poorly.
- Lines that mix Arabic and Latin are put into reading order with heuristics. Word order around the script change can be off.
- Only Saudi ZATCA QR codes are decoded into fields. Other QR codes are reported as
not_zatca_tlvwith their raw text. - Only the first frame of multi-page TIFF and GIF files is read.
Privacy
Images are downloaded into the run's own container, processed in memory and not sent to any third-party service. All OCR runs inside the actor. Results are stored only in your run's dataset and key-value store, under your Apify account and its retention settings. Invoices can contain personal data (names, VAT numbers), so make sure you have the right to process the images you submit, and delete runs you no longer need.