Translate text in a photo
A restaurant menu photographed in Tokyo, a warning label shot on a factory floor, a screenshot of a chat in a language your support team doesn't read — this endpoint reads the pixels first, then translates what it finds, in a single call. No separate OCR step, no manual retyping.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
Text trapped in pixels
Most translation tools expect clean, selectable text, but a huge share of real-world text never arrives that way: it's baked into a photo of a sign, a scanned contract, a screenshot shared in a support ticket, or a product label shot on a warehouse floor. Before that text can be translated it first has to be recognized, and recognition quality depends heavily on lighting, angle, font and image resolution — which is exactly the part this endpoint absorbs so the caller doesn't have to stitch two tools together.
One call, two steps under the hood
Send POST /translate/ocr with an image and a target language, and the task first extracts the visible text with optical character recognition, then runs that text through translation, returning both the recognized source text and its translation. Because it's asynchronous, the response is a task_id, and the finished result lands via signed webhook or a signed link kept alive for 24 hours — useful when the image is large or the queue is busy.
A brief note on OCR itself
Optical character recognition dates back to devices built for reading printed numerals in the mid-20th century, long before it became the background technology inside scanners, license-plate readers and phone camera apps; what's changed since is that modern recognition handles messy, real-world photos — skewed angles, mixed fonts, low light — rather than only clean scans, which is what makes photo-to-translation pipelines practical today instead of a lab curiosity.
Where this earns its keep
Travel and hospitality apps translating menus and signage from a user's photo, customer support teams handling screenshots in foreign languages, e-commerce sellers translating product labels and packaging photos from overseas suppliers, and compliance teams reading safety placards or shipping documents captured in the field.
Fitting into a larger workflow
Pricing is transparent and additive — a $0.011 base per request plus $0.0705 per image processed — so cost scales predictably with volume rather than hiding behind bundled credits. Because the task is billed only on success, with three automatic retries before a clear failure is reported, it's safe to wire directly into an intake pipeline, a support-ticket bot, or a mobile app's photo-upload flow without babysitting retries by hand.
What you can do with it
Travel apps
A traveler photographs a menu abroad and the app shows an instant translated overlay without the user typing a single word.
Support ticket triage
A customer support tool automatically translates screenshots that non-native-speaking users attach to tickets, so agents don't need to guess.
Cross-border e-commerce
A seller translates product labels photographed from an overseas supplier's packaging before listing the item in a new market.
Field compliance checks
An inspection app reads and translates safety placards photographed on-site to confirm they match required wording.
FAQ
How does the image translation API actually work?
It runs optical character recognition on the image to extract the visible text, then translates that text into the target language, returning both in one response.
What image formats are accepted?
Standard photo and screenshot formats work; the task is built for real-world photos, not just clean scans, including tilted or low-light shots.
Is there a free trial?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.
How much does it cost to translate text in an image?
A base of $0.011 per request plus $0.0705 per image processed, published upfront with no hidden credits.
Can I bulk translate many photos at once?
Yes, each image is submitted as its own async request and billed independently, which suits batch pipelines well.
How accurate is the text recognition?
Accuracy depends on image quality — angle, lighting and resolution all matter — but the task is designed for typical real-world photos, not just studio scans.
How do I receive the translated result?
Via a signed webhook when the task completes, or a signed link valid for 24 hours if you prefer to pull it.
What if the OCR or translation step fails?
The task retries automatically up to three times and is never billed on failure; you get a clear error after retries are exhausted.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/translate/ocr \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"image":"https://ejemplo.com/imagen.jpg"}'const res = await fetch("https://api.kit.forhosting.com/translate/ocr", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"image": "https://ejemplo.com/imagen.jpg"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/translate/ocr",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"image": "https://ejemplo.com/imagen.jpg"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/translate/ocr", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"image":"https://ejemplo.com/imagen.jpg"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"image":"https://ejemplo.com/imagen.jpg"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/translate/ocr", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"image": "https://ejemplo.com/imagen.jpg"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "translate.ocr",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_tokens | 20000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
422 | task_failed | The task failed after 3 retries. You are never charged for it. |