Google Lens OCR API - Image to Text Under 500ms REST API avatar

Google Lens OCR API - Image to Text Under 500ms REST API

Pricing

from $3.49 / 1,000 image ocrs

Go to Apify Store
Google Lens OCR API - Image to Text Under 500ms REST API

Google Lens OCR API - Image to Text Under 500ms REST API

Extract text from any image via Google Lens OCR API. Under 500ms per image, no browser needed. Returns word-level bounding boxes with pixel coordinates, detected language, and structured paragraphs/lines/words. Batch and HTTP API modes.

Pricing

from $3.49 / 1,000 image ocrs

Rating

0.0

(0)

Developer

Zen Studio

Zen Studio

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

a day ago

Last modified

Share

Google Lens OCR - Extract Text from Images with Bounding Boxes

Extract text from any image with word-level bounding boxes and pixel coordinates. Returns detected language, full text, and structured paragraph/line/word data in a single request.

  • Sub-second processing per image, no browser required
  • Word-level bounding boxes with both normalized and pixel coordinates
  • Supports JPEG, PNG, WebP, BMP, TIFF, and HEIC formats
  • Standby mode for low-latency HTTP API access

Output Example

Output Example

Pricing -- Pay Per Event

EventFreeStarterScaleBusiness
Image OCR (/1,000)$4.99$4.49$3.99$3.49
Result (/1,000)$0.01$0.01$0.01$0.01
Actor start (one-time)$0.002$0.002$0.002$0.002

Apify plan subscribers get automatic volume discounts.

Free trial: 5 runs, no credit card required.


How Do You Want to Use It?

Two modes, same deployment. Pick what fits your workflow.

Option 1: REST API (Standby Mode)

Best for: developers, automation scripts, no-code tools (n8n, Make, Zapier)

Never heard of Standby mode? It keeps the Actor running as a persistent HTTP server. No cold starts, no waiting for builds. You send a request, you get a response in under 500ms. Think of it as a regular API endpoint that happens to run on Apify.

Authentication

All API requests require authentication. Get your token from the Apify Console under Settings > Integrations.

Two ways to authenticate:

  • Bearer header (recommended): -H "Authorization: Bearer YOUR_APIFY_TOKEN"
  • Query parameter (convenient for testing and no-code tools): ?token=YOUR_APIFY_TOKEN

Endpoints

MethodEndpointDescription
GET/ocrOCR via query parameters
POST/ocrOCR via JSON body (supports imageUrl and imageBase64)
GET/healthReturns {"status": "ok"}

The base URL for your requests:

https://google-lens-ocr.apify.actor

Examples

curl -- OCR an image by URL

curl "https://google-lens-ocr.apify.actor/ocr?imageUrl=https://example.com/document.png&outputDetail=lines" \
-H "Authorization: Bearer YOUR_APIFY_TOKEN"

curl -- OCR a local file via base64

base64 -i photo.jpg | curl -X POST "https://google-lens-ocr.apify.actor/ocr" \
-H "Authorization: Bearer YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(cat -)" '{imageBase64: $img, outputDetail: "full"}')"

curl -- POST with image URL

curl -X POST "https://google-lens-ocr.apify.actor/ocr" \
-H "Authorization: Bearer YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://example.com/document.png",
"outputDetail": "lines",
"translateTo": "en"
}'

Python -- URL and base64

import requests
import base64
TOKEN = "your_apify_token"
BASE = "https://google-lens-ocr.apify.actor"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
# From URL
resp = requests.get(f"{BASE}/ocr", headers=HEADERS, params={
"imageUrl": "https://example.com/document.png",
"outputDetail": "lines"
})
print(resp.json()["fullText"])
# From local file (base64)
with open("photo.jpg", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
resp = requests.post(f"{BASE}/ocr", headers=HEADERS, json={
"imageBase64": image_b64,
"outputDetail": "full"
})
for line in resp.json()["lines"]:
print(line["text"])

n8n / Make / Zapier

Use an HTTP Request node pointed at https://google-lens-ocr.apify.actor/ocr with your Bearer token in the Authorization header. Pass imageUrl as a query parameter (GET) or in a JSON body (POST).


Option 2: Batch Processing

Best for: one-off image processing, scheduled jobs, results saved to a dataset

The simplest way: paste an image URL in the Apify Console, click Start, and download results from the dataset.

Quick Start Input

Minimal

{
"imageUrl": "https://example.com/document.png"
}

With options

{
"imageUrl": "https://example.com/page1.png",
"outputDetail": "lines",
"language": "de",
"region": "DE"
}

Text only (smallest output)

{
"imageUrl": "https://example.com/receipt.jpg",
"outputDetail": "text_only"
}

Using the Apify API Client

Python

from apify_client import ApifyClient
client = ApifyClient("your_token")
run = client.actor("zen-studio/google-lens-ocr").call(run_input={
"imageUrl": "https://example.com/receipt.jpg",
"outputDetail": "lines"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"Language: {item['language']}")
print(f"Text: {item['fullText']}")
for line in item.get("lines", []):
box = line["boundingBox"]["pixelCoords"]
print(f" Line: {line['text']} at ({box['x']}, {box['y']})")

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'your_token' });
const run = await client.actor('zen-studio/google-lens-ocr').call({
imageUrl: 'https://example.com/receipt.jpg',
outputDetail: 'full'
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
console.log(`Language: ${item.language}`);
console.log(`Text: ${item.fullText}`);
}

Scheduled jobs: Create a Schedule in the Apify Console to run the Actor on a recurring basis.


Getting Your Apify API Token

  1. Go to the Apify Console
  2. Navigate to Settings > Integrations
  3. Copy your Personal API token

Use it as a Bearer token for Standby mode, or pass it to the ApifyClient constructor for batch mode.

Input Parameters

ParameterTypeDescriptionDefault
imageUrlstringImage URL to extract text fromrequired
outputDetailstringLevel of detail: full, paragraphs, lines, words, text_onlyfull
languagestringLanguage hint (ISO 639-1 code)en
regionstringRegion hint (ISO 3166-1 alpha-2)US
translateTostringTranslate text to this language (ISO 639-1 code)--

Output Detail Levels

  • full -- paragraphs with nested lines and words, all with bounding boxes
  • paragraphs -- paragraph text and bounding boxes
  • lines -- line text and bounding boxes
  • words -- lines with individual word-level bounding boxes
  • text_only -- just the extracted text, no coordinate data

Output

Each run produces one result with these fields:

FieldTypeDescription
imageUrlstringSource image URL
languagestringDetected language code
fullTextstringAll extracted text joined
linesarrayLines with text and bounding boxes (when detail >= lines)
paragraphsarrayParagraphs with nested lines/words (when detail >= paragraphs)
errorstringError message if processing failed

Bounding Box Format

Every text element includes a bounding box with normalized coordinates (0-1) and pixel coordinates:

{
"centerX": 0.4457,
"centerY": 0.1070,
"width": 0.8512,
"height": 0.1152,
"rotation": 0.0032,
"pixelCoords": {
"x": 30,
"y": 33,
"width": 1265,
"height": 77
}
}
  • centerX, centerY -- center point (0-1 normalized)
  • width, height -- dimensions (0-1 normalized)
  • rotation -- rotation angle in radians (only present when non-zero)
  • pixelCoords -- absolute pixel coordinates computed from image dimensions

Full Output Example

Real output from processing this test image with outputDetail: "full":

{
"imageUrl": "https://tesseract.projectnaptha.com/img/eng_bw.png",
"language": "en",
"fullText": "Mild Splendour of the various-vested Night!\n\nMother of wildly-working visions! hail!\n\nI watch thy gliding, while with watery light\nThy weak eye glimmers through a fleecy veil;\nAnd when thou lovest thy pale orb to shroud\nBehind the gather'd blackness lost on high;\nAnd when thou dartest from the wind-rent cloud\nThy placid lightning o'er the awaken'd sky.",
"lines": [
{
"text": "Mild Splendour of the various-vested Night!",
"boundingBox": {
"centerX": 0.445742,
"centerY": 0.107093,
"width": 0.851279,
"height": 0.115269,
"rotation": 0.003223,
"pixelCoords": { "x": 30, "y": 33, "width": 1265, "height": 77 }
},
"words": [
{
"text": "Mild",
"boundingBox": {
"centerX": 0.066876,
"centerY": 0.105125,
"width": 0.09354,
"height": 0.113772,
"rotation": 0.003223,
"pixelCoords": { "x": 30, "y": 32, "width": 139, "height": 76 }
}
},
{
"text": "Splendour",
"boundingBox": {
"centerX": 0.226699,
"centerY": 0.106229,
"width": 0.192463,
"height": 0.115269,
"rotation": 0.003223,
"pixelCoords": { "x": 194, "y": 32, "width": 286, "height": 77 }
}
}
// ... "of", "the", "various", "-", "vested", "Night", "!"
]
},
{
"text": "Mother of wildly-working visions! hail!",
"boundingBox": {
"centerX": 0.436285,
"centerY": 0.21934,
"width": 0.739569,
"height": 0.113772,
"rotation": 0.004585,
"pixelCoords": { "x": 99, "y": 109, "width": 1099, "height": 76 }
},
"words": [
{ "text": "Mother", "boundingBox": { "centerX": 0.135817, "centerY": 0.216275, "width": 0.138627, "height": 0.113772, "rotation": 0.004585, "pixelCoords": { "x": 99, "y": 106, "width": 206, "height": 76 } } }
// ... "of", "wildly", "-", "working", "visions", "!", "hail", "!"
]
}
// ... 6 more lines
],
"paragraphs": [
{
"text": "Mild Splendour of the various-vested Night!",
"boundingBox": {
"centerX": 0.445742,
"centerY": 0.107093,
"width": 0.851279,
"height": 0.115269,
"rotation": 0.003223,
"pixelCoords": { "x": 30, "y": 33, "width": 1265, "height": 77 }
},
"contentLanguage": null,
"lines": [
{
"text": "Mild Splendour of the various-vested Night!",
"boundingBox": {
"centerX": 0.445742,
"centerY": 0.107093,
"width": 0.851279,
"height": 0.115269,
"rotation": 0.003223,
"pixelCoords": { "x": 30, "y": 33, "width": 1265, "height": 77 }
},
"words": [
{ "text": "Mild", "boundingBox": { "centerX": 0.066876, "centerY": 0.105125, "width": 0.09354, "height": 0.113772, "rotation": 0.003223, "pixelCoords": { "x": 30, "y": 32, "width": 139, "height": 76 } } },
{ "text": "Splendour", "boundingBox": { "centerX": 0.226699, "centerY": 0.106229, "width": 0.192463, "height": 0.115269, "rotation": 0.003223, "pixelCoords": { "x": 194, "y": 32, "width": 286, "height": 77 } } }
// ... 7 more words
]
}
]
}
// ... 2 more paragraphs
]
}

FAQ

Do I need to start the Actor before using the API? No. Standby mode auto-starts the Actor when it receives a request. There's no manual step required.

Can I use both modes at the same time? Yes. Batch runs and Standby API requests are independent. You can run a batch while also making API calls.

What's the difference between Standby and a normal run? A normal run processes an image and saves the result to a dataset. Standby mode keeps the Actor alive as an HTTP server, returning results directly in the response. Use Standby for real-time requests. Use batch for one-off processing with dataset output.

What image formats are supported? JPEG, PNG, WebP, BMP, TIFF, HEIC, and GIF.

How accurate is the text detection? Uses the same OCR engine as Google Lens in Chrome. Accuracy is high for printed text in good lighting. Handwriting and very low-resolution images may produce partial results.

What languages are detected? Language detection is automatic. The language hint improves accuracy for specific languages but doesn't limit detection. The detected language is returned in the output.

How does the bounding box data work? Each text element (paragraph, line, word) includes normalized coordinates (0-1 range) and pixel coordinates. Normalized coordinates are relative to the image dimensions. Pixel coordinates give absolute positions for direct use in image annotation or cropping.

What is the rotation field? The rotation angle in radians for text that isn't perfectly horizontal. Only included when the rotation is significant (> 0.001 radians).

Can I send base64 images instead of URLs? Yes, via the Standby mode POST endpoint. Include imageBase64 in the JSON body instead of imageUrl. Supports raw base64 or data URI format (data:image/png;base64,...).

What happens if the image fails to process? The Actor returns an error result with the imageUrl and error field set. Failed images are not charged.

Is there a rate limit? No hard rate limit. In Standby mode, concurrent requests are handled by thread-safe sessions.

This Actor processes publicly accessible images provided by the user. Users are responsible for ensuring they have the rights to process the images they submit and must comply with applicable data protection regulations (GDPR, CCPA).