# Google Lens OCR API - Image to Text Under 500ms REST API (`zen-studio/google-lens-ocr`) Actor

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.

- **URL**: https://apify.com/zen-studio/google-lens-ocr.md
- **Developed by:** [Zen Studio](https://apify.com/zen-studio) (community)
- **Categories:** SEO tools, Automation, Developer tools
- **Stats:** 386 total users, 93 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.49 / 1,000 image ocrs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 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

#### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
zen-studio/google-lens-ocr on Apify. Call: ApifyClient("TOKEN").actor("zen-studio/google-lens-ocr").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items for results. Also supports Standby mode (REST API): GET https://google-lens-ocr.apify.actor/ocr?imageUrl=...&token=TOKEN. Key inputs: imageUrl: string (required), outputDetail: string (full|paragraphs|lines|words|text_only), language: string. Full actor spec (input schema with all params/enums/defaults, output dataset fields, README): GET https://api.apify.com/v2/acts/zen-studio~google-lens-ocr/builds/default (Bearer TOKEN) → inputSchema, actorDefinition.storages.dataset, readme. Pricing: $0.00499/image OCR, $0.002/actor start, $0.00001/dataset item. Get token: https://console.apify.com/account/integrations
```

### Output Example

![Output Example](https://iili.io/q5DiXmN.png)

### Pricing -- Pay Per Event

| Event | Free | Starter | Scale | Business |
|-------|------|---------|-------|----------|
| 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](https://console.apify.com/settings/integrations) 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

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/ocr` | OCR via query parameters |
| `POST` | `/ocr` | OCR via JSON body (supports `imageUrl` and `imageBase64`) |
| `GET` | `/health` | Returns `{"status": "ok"}` |

The base URL for your requests:

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

##### Examples

**curl -- OCR an image by URL**

```bash
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**

```bash
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**

```bash
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**

```python
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](https://console.apify.com/actors/google-lens-ocr), click **Start**, and download results from the dataset.

##### Quick Start Input

**Minimal**

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

**With options**

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

**Text only (smallest output)**

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

##### Using the Apify API Client

**Python**

```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**

```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](https://docs.apify.com/platform/schedules) in the Apify Console to run the Actor on a recurring basis.

***

### Getting Your Apify API Token

1. Go to the [Apify Console](https://console.apify.com/settings/integrations)
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

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `imageUrl` | string | Image URL to extract text from | *required* |
| `outputDetail` | string | Level of detail: `full`, `paragraphs`, `lines`, `words`, `text_only` | `full` |
| `language` | string | Language hint (ISO 639-1 code) | `en` |
| `region` | string | Region hint (ISO 3166-1 alpha-2) | `US` |
| `translateTo` | string | Translate 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:

| Field | Type | Description |
|-------|------|-------------|
| `imageUrl` | string | Source image URL |
| `language` | string | Detected language code |
| `fullText` | string | All extracted text joined |
| `lines` | array | Lines with text and bounding boxes (when detail >= `lines`) |
| `paragraphs` | array | Paragraphs with nested lines/words (when detail >= `paragraphs`) |
| `error` | string | Error message if processing failed |

#### Bounding Box Format

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

```json
{
  "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](https://tesseract.projectnaptha.com/img/eng_bw.png) with `outputDetail: "full"`:

```json
{
  "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.

### Legal Compliance

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).

# Actor input Schema

## `imageUrl` (type: `string`):

Image URL to extract text from.<br><br>Supported formats: JPEG, PNG, WebP, BMP, TIFF, HEIC<br><br>The image is downloaded and sent directly for OCR processing.

## `outputDetail` (type: `string`):

Controls the level of detail in the output.<br><br><b>Full</b> — paragraphs, lines, words, and bounding boxes<br><b>Paragraphs</b> — paragraph text and bounding boxes<br><b>Lines</b> — line text and bounding boxes<br><b>Words</b> — lines with individual word bounding boxes<br><b>Text only</b> — just the extracted text, no coordinates

## `language` (type: `string`):

ISO 639-1 language code to hint the OCR engine.<br><br>Common codes: <code>en</code> English, <code>de</code> German, <code>fr</code> French, <code>es</code> Spanish, <code>ja</code> Japanese, <code>zh</code> Chinese, <code>ar</code> Arabic, <code>ko</code> Korean<br><br>Improves accuracy for the specified language but doesn't prevent detection of other languages in the same image.

## `region` (type: `string`):

Country used as a region hint for OCR processing. Can improve accuracy for region-specific text formats like addresses, phone numbers, and dates.

## `translateTo` (type: `string`):

Translate detected text to this language using an ISO 639-1 code.<br><br>Examples: <code>en</code> English, <code>de</code> German, <code>fr</code> French, <code>es</code> Spanish, <code>ja</code> Japanese<br><br>Leave empty to return the original text without translation.

## Actor input object example

```json
{
  "imageUrl": "https://tesseract.projectnaptha.com/img/eng_bw.png",
  "outputDetail": "full",
  "language": "en",
  "region": "US"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrl": "https://tesseract.projectnaptha.com/img/eng_bw.png"
};

// Run the Actor and wait for it to finish
const run = await client.actor("zen-studio/google-lens-ocr").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "imageUrl": "https://tesseract.projectnaptha.com/img/eng_bw.png" }

# Run the Actor and wait for it to finish
run = client.actor("zen-studio/google-lens-ocr").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrl": "https://tesseract.projectnaptha.com/img/eng_bw.png"
}' |
apify call zen-studio/google-lens-ocr --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zen-studio/google-lens-ocr",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/pF3ocmhEeA8vmAaPN/builds/GneXvMubN43Vhm9Kg/openapi.json
