Image to Text OCR API - Extract Text from Images with AI avatar

Image to Text OCR API - Extract Text from Images with AI

Pricing

from $2.40 / 1,000 image transcribeds

Go to Apify Store
Image to Text OCR API - Extract Text from Images with AI

Image to Text OCR API - Extract Text from Images with AI

Extract text from images in bulk with AI OCR: receipts, screenshots, signs, document photos and tables as Markdown, in English, Chinese, Japanese and more. Use URLs, datasets or base64. No-text and failed results are free; no start fee.

Pricing

from $2.40 / 1,000 image transcribeds

Rating

0.0

(0)

Developer

Yukai Lin

Yukai Lin

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

2

Monthly active users

22 minutes ago

Last modified

Share

OCR image to text from receipts, screenshots, scans and photos: paste an image URL, choose plain text or Markdown, and get the extracted text in a dataset row.

Try the prefilled public road sign (one image, no account needed):

{"urls":["https://upload.wikimedia.org/wikipedia/commons/6/67/Japanese_Road_Sign_119_%28Street_name%29.jpg"]}

Example output from this image in plain text: {"success":true,"text":"関門大通り\nKanmon-odori","language":"ja","charged":true}. The text is kept in its original language.

Price: $0.003 per image with returned text on the Free and Bronze plans ($3 per 1,000); no start fee, and images without text or with failed results are not charged. Higher plans have discounts.

For batches, put one image URL per line in Image URLs, pick a dataset, or send base64 through the API. Choose Markdown (tables kept) for tables, then export JSON, CSV or Excel. Start with a clear image; crop or enlarge small text if needed. GIF reads its first frame only; PDF and SVG are unsupported.

Receipt / invoice fields

Choose Receipt / invoice fields ("mode":"receipt_fields") for an image of a receipt or invoice. The dataset row keeps the full OCR text and adds receipt: {vendor, date, total, currency, review}. For example, an image transcribed as Vendor: ACME SUPPLIES\nInvoice Date: 2026-10-18\nTotal: USD 105.00 yields {"vendor":"ACME SUPPLIES","date":"2026-10-18","total":105,"currency":"USD","review":false}. Only explicit labels are used; an unlabeled shop name is not guessed, and Subtotal, Tax and Invoice No are not extracted as the total or vendor. Missing or ambiguous values are null, with review:true when the date, total or currency needs checking. Even review:false is not an accuracy guarantee: check fields against the source image before accounting use.

This mode supports images only. For a PDF, use PDF, Word & Excel to Markdown Converter. A text-bearing result uses the same one image-ocr charge as the other modes; no-text and failed images remain free. The price and event are unchanged.

What does Image to Text OCR do?

Give it images and get their text back:

  • 🖥️ Screenshots to text: terminal output, app screens, web pages, chats
  • 🧾 Receipts, invoices and photos of documents: line items and totals, in reading order
  • 📦 Bulk OCR: a whole list of image links in one run, several at a time; every row says which image it belongs to, and one bad link never stops the rest
  • 🪧 Signs and labels in photos
  • 🌏 Many languages and scripts: English, German, Dutch..., Chinese, Japanese, Korean; the text stays in its original language (nothing is translated)
  • 📊 Tables: kept as Markdown tables in Markdown mode, or as one line per row in Plain text mode

Each result has the text, lineCount, charCount and a language guess. Images come from URLs (Google Drive, Dropbox and OneDrive share links work), from another Actor's dataset, or as base64. Images without text can be reported as no_text; no_text results are not charged.

The OCR is done by an AI vision model (Llama 4 Scout) with a strict "transcribe verbatim, do not translate or summarize" instruction. The Actor downloads each image itself (so sites that block cloud servers still work), straightens it using its EXIF rotation, puts transparent images on white and scales very large images down to 2,048 px. A link to a web page instead of an image (for example a Wikimedia Commons file page) reads that page's main image.

Use cases

  • Expense and receipt capture: turn receipt photos into text for bookkeeping or an AI extractor
  • Screenshot search: make screenshots and scanned notes searchable
  • E-commerce and marketplace data: read text printed on product images and labels
  • Social media and meme archives: text inside images for moderation or search
  • AI agents: "What does this image say?" as a tool call

How much does it cost?

EventPrice
Image transcribed$3.00 / 1,000 images ($0.003 per image)

Example: 1,000 receipt photos with text cost 1,000 × $0.003 = $3.00 on the Free plan; images with no text are free.

No start fee. Higher Apify plans get volume discounts (see the Pricing tab). Images with no text, images that cannot be downloaded and unsupported files are not charged; they carry an errorType (no_text, not_found, blocked, too_large, unsupported, network, invalid_input, model_refused, ocr_unavailable...). Every row has charged: true or false, and failed rows end with "(not charged)".

Control your cost

  • Before anything is read, the run logs its plan: the number of images × the price = the most the run can cost, compared with your maximum charge per run.
  • Charged: an image whose text was returned ($0.003). This includes a long text that was cut off (route: "image-truncated", used only when the long-text route fails): the part that was read is returned and charged.
  • Free: images without text, images that could not be downloaded or read, images that hit the time limit per image (180 seconds by default), lines that are not a URL, and the same URL given twice (processed once). A failed download says why when the server does, e.g. image returned HTTP 400: Use thumbnail sizes listed at ....
  • Maximum charge per run: set it in the run options (Console) or with maxTotalChargeUsd (API). When the next image could exceed it, no new image is started; the run ends with status LIMIT_REACHED, and the SUMMARY record lists the images not processed (notProcessed: the count and up to 100 inputs).
  • If Apify restarts the run (server migration or Resurrect), items already finished are skipped and not charged again (SUMMARY.resumedSkipped).

Price comparison (checked September 2026)

ActorPrice per image
Image to Text OCR (this Actor)$0.003, no start fee, images without text free
zen-studio/google-lens-ocr$0.00499
zenomastro/image-ocr-text-extractor$0.005
s-r/google-lens-ocr$0.006
lergassy/ocr-text-extractor$0.002 per file

How to use it

  1. First try one clear image with visible text. Paste its image URL (or more links, one per line, for a batch); you can also upload a text/CSV file of links in the URL list below, pick a dataset from another run (one image URL or an array of up to 100 per item), or send base64 images through the API.
  2. Choose the output format: Plain text (default) or Markdown (tables kept).
  3. Optional: a language hint such as "Japanese" for small or stylized script.
  4. Click Start and export the results as JSON, CSV or Excel.

A text-free image can return no_text; a no_text result is free. If visible text was missed, try cropping or enlarging the text area and retry; Language hint (optional) may help. Only the first GIF frame is read, and PDF/SVG files are unsupported.

Input example

This is the single-image prefill; it previously produced the Japanese sign text shown above:

{
"urls": [
"https://upload.wikimedia.org/wikipedia/commons/6/67/Japanese_Road_Sign_119_%28Street_name%29.jpg"
]
}

Output examples (real results, September 2026)

A supermarket receipt photographed on a table (Dutch), Markdown mode:

{
"imageUrl": "https://thumb.wikimedia.org/wikipedia/commons/thumb/b/b3/Sahan_Supermarket_receipt%2C_Hillegersberg%2C_Rotterdam_%282021%29_02.jpg/1920px-...jpg",
"success": true,
"mode": "markdown",
"text": "# SAHAN Supermarkt\nBergweg 170\n3036 BL Rotterdam\nTel: 010-265.33.99\n\n## KASSABON\n\nNummer 2-00005155\nDatum: 26/01/2021\nTime : 11.29\nCaissier Tuge\nKassa: 1\n\n| Omschrijving | Bedrag |\n|--------------|--------|\n| MIRAS OLijfoute (glas) 1L | 3,99 |\n| MERAY TRAKY A POMPOENPIT 200 | 1,99 |\n| PINAR POMPOENPITTEN 200G | 1,99 |\n| ULKER PETIBOR BISKUVI 1KG | 2,49 |\n| BROOD SIMIT * 5 x 0.75 | 3,75 |\n\nTOTAAL Incl: 14,21\nPIN Betaling 14,21\nTeruggave 0,00\nBTW Bedrag: 1,17\n\n6 Artikel / 9 Stuks\nD. uwel en tot ziens",
"lineCount": 23,
"charCount": 529,
"language": "nl",
"languageName": "Dutch",
"imageFormat": "jpeg",
"width": 1920,
"height": 3413,
"route": "image",
"imageBytes": 2315283
}

All prices, totals, the date and the address are right. Mistakes on this crumpled receipt: "OLijfoute (glas)" (printed OLIJFOLIE (GLAS); the Plain text run read it correctly), "TRAKY A" (TRAKYA), "Tuge" (Tugce), "11.29" (11:29).

A Japanese road sign, Plain text mode: "text": "関門大通り\nKanmon-odori", "language": "ja" (exact).

A Japanese terminal screenshot (24 lines, English and Japanese): every process line, the uname output, the Japanese date 2006年 10月 14日 土曜日 19:53:00 JST and こんにちはウィキペディア were read correctly.

A landscape photo without text: "success": false, "errorType": "no_text", not charged.

If the AI model declines to read an image (an answer like "I can't help with this request") the image is asked once more with another prompt; if it still declines, the row is "success": false, "errorType": "model_refused" and not charged. If the OCR service itself does not answer (busy or a server error), the row is "errorType": "ocr_unavailable" and not charged, and the image can simply be run again. A refusal is never returned as the transcription.

route says how the text was read: image (one vision call) or page (long or very dense text: when the first answer reaches its length limit of about 2,000 tokens, or the vision call cannot finish in time, the image is read again through our page-OCR route, which allows answers of up to about 4,096 tokens). A SUMMARY record in the key-value store has the run status (SUCCESS, PARTIAL_RESULTS, FAILED, NO_RESULTS, LIMIT_REACHED) and counts of transcribed, no-text and failed images. An image without text is a valid answer, not a failure: a run where every image was either transcribed or had no text ends as SUCCESS. Every row has index (the input order: URLs first, then base64 images) and input; rows from a dataset also have datasetItemIndex, and base64 images sent as {"id": ..., "data": ...} return their id.

Accuracy (our test, September 2026)

We checked the output against the images by eye:

ImageResult
Receipt photo (Dutch, crumpled)All numbers, totals, date and address right; 2-4 misread words per run
Japanese road signExact
Japanese + English terminal screenshotCorrect, including the Japanese lines
Wikipedia history table (screenshot, 7 rows × 13 columns)All dates, sizes, size changes and comments right; some cells shifted by one column and the user names (hidden in the image) left empty
English terminal ls -l screenshot (long text)All file names, sizes and times right, but written as a Markdown table, and single-digit days ("Jun 1") were dropped
Hong Kong restaurant sign photo (stylized Chinese, at an angle)About 60% of the dishes read correctly; the phone number right; the large calligraphic sign and some characters wrong
Poem photographed upside down, 90° turned, tilted 5°, blurred, as WebP, with transparency (test of October 2026)Exact in every case; the upside-down one is read again turned upright (turnedUpright)
Same poem shrunk to 300 px wide (JPEG) / 150 px wideExact / 4-6 misread words
Swiss restaurant receipt (German), TIFF page of English text, Hindi page, Chinese poem (5 lines)All right (the receipt: names, items, totals, VAT)
Landscape photo, blank image, 1×1 pixel imageCorrectly reported as no text, not charged

In short: printed text, screenshots and receipts work well; stylized, handwritten, angled or very small text is less reliable, and the AI can misread or occasionally drop characters. Check important values (amounts, IDs) before you rely on them.

Use with AI agents (MCP)

Connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/image-to-text-ocr) to Claude, Cursor or any MCP client, then ask e.g. "Read the text in these three receipt photos and give me the totals."

{ "urls": ["https://example.com/receipt.jpg"], "mode": "text" }

Failed images and images without text are not charged and carry an errorType.

Use it from code

curl -X POST "https://api.apify.com/v2/acts/tidytools~image-to-text-ocr/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls":["https://upload.wikimedia.org/wikipedia/commons/6/67/Japanese_Road_Sign_119_%28Street_name%29.jpg"],"mode":"text"}'

Base64 input: {"imagesBase64": ["data:image/png;base64,iVBORw0..."]}, or with your own ids: {"imagesBase64": [{"id": "receipt-17", "data": "iVBORw0..."}]}. The URL-list field imageUrls ([{"url": ...}]) is also accepted, but Apify rejects the whole run (HTTP 400) when it holds a blank line or a bare domain; urls (plain strings) never fails the run.

Schedules and integrations: run it daily or weekly with Apify Schedules, get a webhook when a run finishes, or send the results to Zapier, Make, n8n, Google Sheets, Slack and other apps with Apify integrations. Results can be exported as JSON, CSV, Excel or XML.

Advanced settings

  • Proxy: optional Apify Proxy for downloading images from sites that block data-center requests (billed to your Apify account). Without a proxy, a refused download (HTTP 401/403/429) is retried with an honest bot user agent, then with a referrer from the image's own site (hotlink protection).
  • Parallel images: how many images are processed at the same time (1-10).
  • Time limit per image: 180 seconds by default (30-300); a dense page of text can need 1-3 minutes. An image that takes longer (a stuck download or a very long text) fails with errorType: "timeout" and is not charged, so one slow image cannot hold the run.

Limitations

  • Formats: JPEG, PNG, WebP, GIF (first frame), AVIF, HEIC/HEIF (iPhone photos) and TIFF, up to 20 MB and 100 megapixels. SVG and PDF are not supported: a PDF fails with errorType: "unsupported" and a pointer to our PDF, Word & Excel to Markdown Converter, which has OCR for scanned PDFs.
  • Very large images are scaled down to 2,048 px on the long side, so tiny print in huge images can be lost; crop them first.
  • Very long text (more than about 2,000 tokens, e.g. a full restaurant menu) goes through the page route, which answers in Markdown and tends to turn column-aligned text into tables; in Plain text mode those tables become tab-separated lines. Dot leaders between a dish and its price ("Soup ........ 2,50") are written as " ... ".
  • Photos turned 90° without an EXIF rotation tag are read as they are. Photos that are upside down are detected by a quick orientation check (it runs alongside the first read, so it adds no waiting time) and read again turned upright; such rows carry turnedUpright: true. This costs you nothing extra. Very small or blurry text (about 150 px wide for a whole page) still gets misread words; use a larger version when you can.
  • The language value is a guess from the script and common words; for Latin-script text it tells apart English, German, Dutch, French, Spanish, Italian, Portuguese, Polish, Swedish and Vietnamese (und when unclear).
  • AI OCR can misread characters, and on rare occasions skip a line; it does not return per-word positions or confidence scores.

FAQ

Why did I get no_text? The model found no readable text. Crop to the printed area, use a larger image, or add a language hint for small or stylized text. A no_text row is free.

Why did an image time out? A slow download or dense page can exceed Time limit per image (180 seconds by default). Try a smaller crop or raise the limit (up to 300 seconds). A timeout row is free.

Why was my input invalid? Use a full public HTTPS image URL in Image URLs (urls), one per line; remove blank lines and private addresses. Invalid base64 also gives invalid_input. PDF and SVG are unsupported. The imageUrls file/list editor can reject a whole run if it contains a blank line or bare domain; urls reports bad lines as free rows.

Why could the image not be downloaded? not_found means the link is missing; blocked means the host refused the request. Try a public direct image link or an image you have permission to use, and follow the source site's robots.txt. The Actor does not log in or bypass a login wall. Optional Apify Proxy can help with permitted public sources and is billed by Apify.

When am I charged? Only a row with returned image text is charged: $0.003 on Free and Bronze plans, including a partial transcription marked image-truncated. no_text, invalid inputs, failed downloads, unsupported images, model failures and timeouts are not charged; duplicates run once. Check each row's charged field.

Support

Open an issue in the Issues tab with the image URL. Issues are checked regularly.

Found this useful? A short review on the Store helps other users find it.