Arabic Receipt Reader (OCR + Saudi ZATCA QR) avatar

Arabic Receipt Reader (OCR + Saudi ZATCA QR)

Pricing

Pay per event

Go to Apify Store
Arabic Receipt Reader (OCR + Saudi ZATCA QR)

Arabic Receipt Reader (OCR + Saudi ZATCA QR)

Reads Arabic and English receipts and invoices, including Arabic-Indic digits: full OCR, total/VAT/subtotal/line-item candidates checked against each other, a needsReview flag, and exact fields from Saudi ZATCA e-invoice QR codes (signature not checked). For dense documents use Arabic Image OCR.

Pricing

Pay per event

Rating

0.0

(0)

Developer

saif alnuaimi

saif alnuaimi

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Read Arabic and English receipts and invoices, including Arabic-Indic digits (٠١٢٣٤٥٦٧٨٩) and Persian digits (۰-۹). For every image you get:

  • the full text and lines, each with a confidence score, in right-to-left reading order;
  • candidates for the total, subtotal, VAT, VAT number, date and line items, each with its confidence;
  • a reconciliation check: do the line items + VAT add up to the total, does subtotal + VAT equal the total, does the total match the e-invoice QR?
  • a needsReview flag that tells you which receipts a person should check, with reviewReasons;
  • the exact fields from a Saudi ZATCA e-invoice QR (seller, VAT number, timestamp, total, VAT), decoded from the QR, never guessed from the OCR text.

Dense documents, article screenshots or chat screenshots? Use Arabic Image OCR (arabic-image-ocr) instead. Its plain-text mode is faster, cheaper and reads dense small print better. It also has a QR-only mode.

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.

How it reads

A neural OCR engine (EasyOCR, Arabic + English) reads the image, and every number is cross-checked by a dedicated Arabic-Indic digit classifier. When the two read a number differently, you get the more confident reading plus alternativeReading. Every image is downscaled to at most 4 megapixels before OCR; imageSize shows the original and processed sizes, and boxes are in original-image pixels.

The receipt object

  • totalCandidate, subtotalCandidate, vatCandidate: the value, the text as printed (textRaw), the line it came from, a confidence from 0 to 100 and lowConfidence (below confidenceThreshold, default 80).
  • vatNumberCandidate and dateCandidate.
  • lineItems: the description and amount of each line, with their confidence.
  • sumCheck: whether the line items add up to the subtotal, the total minus VAT, or the total, within sumToleranceCents (default 0.05).
  • vatCheck: whether subtotal + VAT equals the total.
  • qrCrossCheck: whether the printed total and VAT agree with the invoice QR (tags 4 and 5), and the printed VAT number with tag 2: agree, mismatch, not_in_qr or not_found_in_text.
  • reconciliation: {"reconciled": true/false, "by": [...]}, with by naming what matched (lineItemsPlusVatEqualTotal, lineItemsEqualTotal, lineItemsEqualSubtotalAndSubtotalPlusVatEqualsTotal, subtotalPlusVatEqualsTotal, totalMatchesQr).
  • needsReview, reviewReasons and notes.

When is needsReview true?

reviewReasons entryMeaning
line_items_do_not_add_upThe line items don't add up to the subtotal / total (within the tolerance)
subtotal_plus_vat_differs_from_totalSubtotal + VAT is not the total
printed_value_differs_from_qr: total / vatThe printed value disagrees with the e-invoice QR
no_total_foundNo total line was recognised
total_low_confidence_and_nothing_to_reconcileThere are no line items, VAT or QR total to check the total against, and its confidence is below confidenceThreshold

Low OCR confidence alone does not flag a receipt whose numbers reconcile. When the items + VAT add up to the total (or the total matches the QR), a low confidence score is only mentioned in notes. On our test set this cut the flag rate on correctly read receipts from 83% to 21%, while still flagging every misread or inconsistent receipt (see test-results/REPORT.md).

Totals are candidates, not facts. OCR can misread a digit, a decimal separator or which line is the total. Numbers that reconcile are much more likely to be right, but not guaranteed. Don't book, pay or file anything on OCR values alone. When an invoice has a ZATCA QR, exactQrFields.invoiceTotal is the value encoded by the seller's system and is the better source.

Exact QR fields

When an image contains a Saudi e-invoice QR (ZATCA TLV, base64), you get exactQrFields:

TagField
1sellerName
2vatNumber (plus vatNumberFormatValid: 15 digits, starts and ends with 3; a flag, never a rejection)
3timestamp (plus timestampIso)
4invoiceTotal (with VAT)
5vatTotal
6–9reported as present, with their lengths (hash, signature, public key, certificate signature)

tagsFound lists the tags in the QR. qrFormat is informational: phase1, phase2-standard, phase2-simplified 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, not_zatca_tlv (another kind of QR; its text is in qr.codes[].rawText) or no_qr_found.

Input

FieldDefaultNotes
imageUrlsPublic image links (JPEG, PNG, WebP, GIF, BMP, TIFF)
keyValueStoreRecordsUploaded images: record-key for this run's store, or store-name-or-id/record-key
includeQrFieldstrueDecode a ZATCA QR and cross-check against it (included in the price, no extra charge)
confidenceThreshold80The lowConfidence threshold
sumToleranceCents5Reconciliation tolerance, in 1/100 of the currency
deskew, digitSecondPass, maskQrCodestrueImage options
outputLines, outputWords, stripTatweeltrue, false, trueOutput detail
maxImageSizeMb20Limit per image

No images in the input? The actor reads a small bundled sample receipt so you can see the output (sample: true, free). This is also what the input form's default run does. If the input links to an example image that can't be downloaded, the sample is read instead. Either way the run's status message and OUTPUT.note say so (for example "Input image failed to download; returned built-in sample instead").

{
"imageUrls": [{"url": "https://example.com/receipt-1.jpg"}, {"url": "https://example.com/receipt-2.png"}],
"confidenceThreshold": 85
}

Memory: the OCR models need about 1.5–1.8 GB of RAM, so the actor runs at 4 GB (minimum and default 4096 MB) and reads one image at a time. If it is started with less than about 3 GB, it stops straight away with the message "increase memory to 4 GB" and charges nothing. A receipt screenshot takes a few seconds; a phone photo can take up to about a minute.

Output

A shortened row for a phase-2 receipt:

{
"source": "https://example.com/receipt.png",
"sample": false,
"status": "ok",
"mode": "full",
"text": "Al Waha Trading Co.\nSimplified Tax Invoice\nLaptop stand 1000.00\nVAT 15% 150.00\nTotal 1150.00",
"imageSize": {"original": [760, 747], "processed": [760, 747], "downscaledBy": 1.0, "maxProcessedMegapixels": 4.0},
"qr": {"status": "zatca_tlv", "count": 1},
"exactQrFields": {"sellerName": "Al Waha Trading Co. شركة الواحة", "vatNumber": "300000000000003", "vatNumberFormatValid": true,
"timestamp": "2026-09-30T08:05:44", "invoiceTotal": "1150.00", "vatTotal": "150.00",
"qrFormat": "phase2-simplified", "tagsFound": [1, 2, 3, 4, 5, 6, 7, 8, 9], "signatureChecked": false},
"receipt": {
"totalCandidate": {"value": 1150.0, "textRaw": "1150.00", "confidence": 61.2, "lowConfidence": true},
"vatCandidate": {"value": 150.0, "confidence": 90.3, "lowConfidence": false},
"lineItems": [{"description": "Laptop stand", "value": 1000.0, "confidence": 72.5, "lowConfidence": true}],
"sumCheck": {"itemsSum": 1000.0, "comparedTo": "totalCandidate minus vatCandidate", "difference": 0.0, "tolerance": 0.05, "addsUp": true},
"qrCrossCheck": {"total": "agree", "vat": "agree", "vatNumber": "agree"},
"reconciliation": {"reconciled": true, "by": ["lineItemsPlusVatEqualTotal", "totalMatchesQr"]},
"needsReview": false,
"reviewReasons": [],
"notes": ["low OCR confidence on totalCandidate, lineItems, but the numbers reconcile, so not flagged"]
},
"chargedEvents": ["full-ocr-screenshot"]
}

Images that can't be read 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, rows needing review, sample rows, the events charged and how long it took.

Pricing (pay per event)

EventWhenPrice
full-ocr-screenshotEach image whose original is up to 4 megapixels (screenshots, scans, most receipts)$0.025
full-ocr-photoEach image whose original is over 4 megapixels (phone photos)$0.05
  • Photo or screenshot is decided by the original image's pixel count, before the 4 MP downscale. A 12 MP phone photo is billed as full-ocr-photo even though it is read at 4 MP.
  • The Saudi e-invoice QR fields and the QR cross-check are included in the price. A receipt with a ZATCA QR costs the same as one without: $0.025 or $0.05.
  • Error rows and sample rows (sample: true) are free.
  • chargedEvents in each row lists only the events actually charged for that row.
  • Spending limit: before each image the actor checks that its price still fits under your run's maximum cost. 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.

Limitations

  • OCR is not perfect. On our synthetic receipts this actor read about 90% of Arabic-Indic digits correctly. Real photos (blur, glare, crumpled or faded thermal paper) score lower. Use needsReview.
  • Very dense pages (a full article screenshot) are slow and read worse than with Arabic Image OCR.
  • Handwriting, decorative calligraphy and heavy diacritics are read poorly.
  • Decimal separators: ٫, . and , are all used on Gulf receipts. Something like ٢٢,٥٠ is read as 22.50 and marked separatorAmbiguous.
  • Field detection relies on keywords in Arabic and English (الإجمالي، المجموع، ضريبة القيمة المضافة, Total, VAT, Subtotal…). Unusual layouts may give no totalCandidate (no_total_found).
  • Only Saudi ZATCA QR codes are decoded into fields.
  • 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. Receipts and invoices can contain personal data (names, VAT numbers, sometimes card digits), so make sure you have the right to process the images you submit, and delete runs you no longer need.