# Google Lens OCR API - Image to Text & Coordinates (`thodor/google-lens-ocr`) Actor

Google Lens OCR API. Extract text from images with word, line and paragraph bounding boxes in pixels, plus object detection and translation.

- **URL**: https://apify.com/thodor/google-lens-ocr.md
- **Developed by:** [Thodor](https://apify.com/thodor) (community)
- **Categories:** SEO tools, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 22 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 ocrs

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

An **image to text API** powered by **Google Lens OCR**. Paste an image URL, a screenshot, a scan, a manga page, an invoice, and get the text back as JSON with **bounding box coordinates for every word, line, and paragraph**. 0.5 to 1 second per image. No Google Cloud project, no API key to manage.

Google offers no official Lens API; this actor is the programmatic way to use Lens OCR. The coordinates are what separate it from a text dump: overlay a translation onto the original image, black out personal data, build a searchable PDF, or map a form label to the value sitting beside it. Looking for where an image appears online instead? That's the [Reverse Image Search API](https://apify.com/thodor/google-lens-exact-matches); this one reads text only.

### 📋 How to extract text from an image

1. Paste one or more image URLs into **Image URLs**. JPEG, PNG, WebP, and GIF all work.
2. Optional: open **🌍 Translation & language** and pick a **Translate to** language.
3. Click **Start**.
4. Open the **Output** tab and click **Export** for JSON, CSV, Excel, or HTML.

Measured on real images: a 900x300 PNG returned in 566 ms, an 800x400 PNG in 642 ms, and a 2878x1918 JPEG photo in 766 ms, each including the time to download the source file. Images process in parallel, so a batch costs little more wall time than its slowest image.

### 🎁 So what do you get?

| 📝 Extracted text | 📦 Boxes for every word, line, and paragraph | 🌍 Detected language |
| --- | --- | --- |
| 🔁 Built-in translation | 🧭 Writing direction per paragraph | ➗ Math formulas as LaTeX |
| 🎯 Detected objects and salient regions | 📐 Pixel and normalized coordinates | 🔄 Rotation angle per box |
| #️⃣ Word, line, and paragraph counts | 🖼️ Image dimensions | 🚫 Failed URLs logged, never billed |

### ⚖️ Compared to Cloud Vision and Tesseract

| | This actor | Google Cloud Vision | Tesseract |
|---|---|---|---|
| **Line** bounding boxes | ✅ | ❌ Words and paragraphs only | ✅ |
| Coordinates | ✅ Pixel and normalized | ⚠️ Pixels only | ⚠️ Pixels only |
| Writing direction per paragraph | ✅ | ❌ | ❌ |
| Math as LaTeX | ✅ | ❌ | ❌ |
| Translation | ✅ Built in | ❌ Separate Translate API | ❌ |
| Objects and salient regions | ✅ Included | ⚠️ Separate feature, billed per call | ❌ |
| Accuracy on photos and angled text | ✅ Strong | ✅ Strong | ⚠️ Weak |
| Setup | ✅ Register on Apify, $5 free monthly credit | ❌ GCP project, billing, API key | ⚠️ Install and self-host |

Cloud Vision has no line level and no translation, and you need a GCP project, billing, and an API key before your first request. Tesseract is free, but you host it yourself, feed it the language up front, and accuracy drops sharply on photographs. This actor is an image URL in, JSON out.

### 🎯 Three things people run this for

| | How |
|---|---|
| 🈴 **Manga and comic translation** | Set `translateTo`, get each speech bubble's text, box, and `writing_direction`. Vertical Japanese comes back correctly ordered, ready to render the translation in place |
| 🕶️ **Redaction before storage** | Find the name or card number, take its word-level pixel box, black it out. OCR becomes a PII-removal step in your pipeline |
| 🧾 **Invoice and form extraction** | A label means nothing until you know which value sits next to it. Boxes give you the spatial layout, so `Total due` maps to `$99.50` instead of a guess from reading order |

### 📥 Input

```json
{
  "imageUrls": ["https://example.com/screenshot.png"],
  "translateTo": "en"
}
```

- `imageUrls`: images to extract text from, as many as you like
- `translateTo`: ISO 639-1 target language. Empty = no translation
- `language`: default `en`. A hint for the text in the image, not a filter
- `region`: default `US`. Locale hint for region-specific formatting

In the Console, the last three sit under the collapsible **🌍 Translation & language** section.

> 💡 **Tip:** send the largest version of the image you have; text under roughly 15 pixels tall is unreliable. For non-Latin scripts, setting `language` measurably improves accuracy on Japanese, Arabic, Thai, and Cyrillic.

### 📤 Output

One dataset row per image. Failed images are never charged and never appear in the dataset; the failed URLs and reasons land in the `FAILURES` record of the run's key-value store.

![Google Lens OCR API output in the Apify Console: one dataset row per image with the extracted text, word, line and paragraph counts, detected language and detected objects](https://api.apify.com/v2/key-value-stores/LHcvkclm26dcJvwP1/records/google-lens-ocr-output-example.png)

```json
{
  "image_url": "https://example.com/invoice.png",
  "text": "Invoice 12345\n\nTotal due $99.50",
  "language": "en",
  "paragraph_count": 2,
  "line_count": 2,
  "word_count": 6,
  "paragraphs": [
    {
      "text": "Invoice 12345",
      "language": "en",
      "writing_direction": "LEFT_TO_RIGHT",
      "bounding_box": {
        "x": 0.2489, "y": 0.2499, "width": 0.5011, "height": 0.19,
        "center_x": 0.4994, "center_y": 0.3449, "rotation": 0.0,
        "pixels": { "x": 224, "y": 75, "width": 451, "height": 57 }
      },
      "lines": [
        {
          "text": "Invoice 12345",
          "words": [
            { "text": "Invoice", "separator": " ", "bounding_box": { "pixels": { "x": 224, "y": 75, "width": 227, "height": 57 } } }
          ]
        }
      ]
    }
  ],
  "objects": [
    { "id": "SalientRegion-Top", "kind": "salient_region",
      "bounding_box": { "pixels": { "x": 178, "y": 70, "width": 547, "height": 154 } } }
  ],
  "image_width": 900,
  "image_height": 300
  // HIDDEN: translation (when translateTo is set), image_size_bytes,
  // word type and latex fields, line-level bounding boxes
}
```

#### Fields

| Field | Description |
|---|---|
| `text` | Full extracted text, paragraphs separated by blank lines |
| `language` | Detected language of the text |
| `paragraphs[]` | Each with `text`, `language`, `writing_direction`, `bounding_box`, and `lines[]` |
| `paragraphs[].lines[].words[]` | Each word with `text`, `separator`, `bounding_box`, `type`, and `latex` when it is a formula |
| `objects[]` | Detected objects and salient regions with boxes. Populated even when the image has no text, so a blank result is still a real result |
| `translation` | Translated text plus detected source language, when `translateTo` is set |
| `paragraph_count`, `line_count`, `word_count` | Counts for quick filtering |
| `image_width`, `image_height`, `image_size_bytes` | Source image properties |

Every `bounding_box` carries normalized coordinates (`x`, `y`, `width`, `height`, `center_x`, `center_y`, `rotation`) plus a `pixels` object with the same box in image pixels. Use `pixels` for cropping and drawing, the normalized values if you resize afterwards.

### ⚙️ Use it as an image to text API

Every run is an HTTP endpoint: POST the same JSON as the form and the records come back in the response body, usually within seconds.

#### Python

```python
import requests

resp = requests.post(
    "https://api.apify.com/v2/acts/thodor~google-lens-ocr/run-sync-get-dataset-items",
    params={"token": "YOUR_APIFY_TOKEN"},
    json={"imageUrls": ["https://example.com/screenshot.png"], "translateTo": "en"},
)

for item in resp.json():
    print(item["text"])
```

#### Node.js

```javascript
import axios from "axios";

const { data } = await axios.post(
  "https://api.apify.com/v2/acts/thodor~google-lens-ocr/run-sync-get-dataset-items",
  { imageUrls: ["https://example.com/screenshot.png"] },
  { params: { token: process.env.APIFY_TOKEN } }
);

console.log(data[0].text, data[0].word_count);
```

#### curl

```bash
curl -X POST "https://api.apify.com/v2/acts/thodor~google-lens-ocr/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"imageUrls":["https://example.com/screenshot.png"]}'
```

Swap `run-sync-get-dataset-items` for `runs` to fire async with a webhook when you batch thousands of images. The `apify-client` SDK works too, in Python and JavaScript, and the n8n, Make, and Zapier integrations take the same input.

> 💡 **Tip:** no need to write the JSON by hand. Fill in the form on the Input tab, switch the editor from **Form** to **JSON**, and copy the result into your code.

### 💰 How much does OCR cost?

Billing is per image processed, at the rate on the price card on this page. No subscription, no monthly minimum, no per-run start fee. Images that fail are not charged.

### ❓ FAQ

**Is there an official Google Lens API?**
No, Google has never published one. Cloud Vision is a different engine with different output. This actor drives Lens itself and returns its results as JSON.

**Can I use this image to text API for free?**
Yes. Registering on Apify comes with $5 of free platform credit every month, no credit card needed, enough for roughly 1,250 images at current rates.

**How accurate is Google Lens OCR?**
Very good on printed text, including photos taken at an angle, and strong on non-Latin scripts. Low resolution, heavy compression, and stylised fonts reduce accuracy. Handwriting works partially: neat sometimes, cursive generally not.

**What languages are supported?**
Lens detects the language automatically and handles more than 100, including right-to-left scripts like Arabic and Hebrew and vertical Japanese.

**What image formats work?**
JPEG, PNG, WebP, and GIF. Animated GIFs are read as their first frame. If your host serves AVIF or HEIC, convert first.

**Is OCR on images legal?**
Extracting text from images you are entitled to process is ordinary data processing. What matters is what the images contain and what you do with the results; if they hold personal data, GDPR or CCPA applies to you.

### 🛟 Support

Something not working, or a field missing? Message me in the Issues tab and I'll look into it quickly. I'm a solo dev, so don't hesitate.

Need to find where an image appears online instead of what it says? The [Reverse Image Search API](https://apify.com/thodor/google-lens-exact-matches) covers that side.

- Thodor

# Actor input Schema

## `imageUrls` (type: `array`):

Images to extract text from. Screenshots, photos, scans, documents — JPEG, PNG, WebP or GIF.

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

Translate the extracted text into this language. Leave on 'No translation' to keep the original only.

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

Language of the text in the image. A hint, not a filter — improves accuracy on non-Latin scripts.

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

Affects locale-specific formatting such as dates and currency.

## Actor input object example

```json
{
  "imageUrls": [
    "https://placehold.co/900x300/000000/FFFFFF/png?text=Invoice+12345"
  ],
  "translateTo": "",
  "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 = {
    "imageUrls": [
        "https://placehold.co/900x300/000000/FFFFFF/png?text=Invoice+12345"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thodor/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 = { "imageUrls": ["https://placehold.co/900x300/000000/FFFFFF/png?text=Invoice+12345"] }

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

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

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

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://placehold.co/900x300/000000/FFFFFF/png?text=Invoice+12345"
  ]
}' |
apify call thodor/google-lens-ocr --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thodor/google-lens-ocr"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mi8hgKprrauqmNDzt/builds/uN4HWFjvv7auCXfpb/openapi.json
