# Image to text

> Read the letters and digits in an image with YesCaptcha. ImageToTextTaskOcrBase and ImageToTextTaskMuggle return synchronously; ImageToTextTask and ImageToTextTaskM1 are asynchronous and support case, digits-only, math and length options; custom models available.

Source: https://docs.yescaptcha.com/en/tasks/image-to-text/ · Last verified: 2026-10-15

Send a text captcha image as Base64 and get back the letters and digits in it (`solution.text`). `ImageToTextTaskOcrBase` costs 2 points (¥0.002) per image and is synchronous: a single `createTask` request returns the result. If you need options such as case sensitivity, digits only or math, use the asynchronous `ImageToTextTask`.

- POST `https://api.yescaptcha.com/createTask` (Global endpoint)
- POST `https://cn.yescaptcha.com/createTask` (China endpoint)

The request body is JSON authenticated with your `clientKey`.

## Task types and pricing

| Task type | Price | Mode | Notes |
| --- | --- | --- | --- |
| `ImageToTextTaskOcrBase` | 2 points (¥0.002) | Synchronous |  |
| `ImageToTextTaskMuggle` | 2 points (¥0.002) | Synchronous | Does not support case/numeric options; use project\_name to select a custom model |
| `ImageToTextTask` | 4 points (¥0.004) | Asynchronous |  |
| `ImageToTextTaskM1` | 15 points (¥0.015) | Asynchronous |  |

| You need | Use |
| --- | --- |
| Ordinary alphanumeric captchas, cheapest and fastest | `ImageToTextTaskOcrBase`, `ImageToTextTaskMuggle` (synchronous) |
| A model trained for you | `ImageToTextTaskMuggle` with `project_name` |
| Case sensitivity, digits only, math, length limits | `ImageToTextTask`, `ImageToTextTaskM1` (asynchronous) |

The types use different models and routes, so results on the same kind of image may differ; test them and pick the best.

## Request parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | Yes | Task type; see "Task types and pricing" on this page |
| `body` | string | Yes | Base64-encoded image without the `data:image/...;base64,` prefix and without line breaks |
| `project_name` | string | No | Name of a custom model, supported only by `ImageToTextTaskMuggle`. Omit to use the general alphanumeric model. Contact support for a custom model (ImageToTextTaskMuggle only) |
| `phrase` | boolean | No | true means the answer contains at least one space (ImageToTextTask, ImageToTextTaskM1 only) |
| `case` | boolean | No | true means the answer is case-sensitive (ImageToTextTask, ImageToTextTaskM1 only) |
| `numeric` | integer | No | 0 no requirement; 1 digits only; 2 no digits (ImageToTextTask, ImageToTextTaskM1 only) |
| `math` | boolean | No | true means the image is a math expression and the answer is its result (ImageToTextTask, ImageToTextTaskM1 only) |
| `minLength` | integer | No | Minimum answer length; 0 means no limit (ImageToTextTask, ImageToTextTaskM1 only) |
| `maxLength` | integer | No | Maximum answer length; 0 means no limit (ImageToTextTask, ImageToTextTaskM1 only) |

`body` is the Base64 of the image file, without a `data:image/...;base64,` prefix and without line breaks. WebP images are converted automatically.

## Request example

POST https://api.yescaptcha.com/createTask

```json
{
  "clientKey": "YOUR_CLIENT_KEY",
  "task": {
    "type": "ImageToTextTaskOcrBase",
    "body": "BASE64_IMAGE"
  }
}
```

Complete code (reads `captcha.png` from the current directory):

**curl**

```bash
curl -s https://api.yescaptcha.com/createTask \
  -H 'Content-Type: application/json' \
  -d '{
  "clientKey": "YOUR_CLIENT_KEY",
  "task": {
    "type": "ImageToTextTaskOcrBase",
    "body": "BASE64_IMAGE"
  }
}'
```

**Python**

solve.py

```python
import os
import base64

import requests

API = "https://api.yescaptcha.com"
CLIENT_KEY = os.environ["YESCAPTCHA_CLIENT_KEY"]  # Read the clientKey from an environment variable

def call(method, payload):
    r = requests.post(f"{API}/{method}", json={"clientKey": CLIENT_KEY, **payload}, timeout=30)
    data = r.json()
    if data.get("errorId"):
        raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
    return data

def solve(task):
    return call("createTask", {"task": task})["solution"]

# Base64-encode the image (no data: prefix)
with open("captcha.png", "rb") as f:
    image_b64 = base64.b64encode(f.read()).decode()

solution = solve({
    "type": "ImageToTextTaskOcrBase",
    "body": image_b64,
})
print(solution["text"])
```

**Node.js**

solve.mjs

```js
import { readFileSync } from 'node:fs';

const API = 'https://api.yescaptcha.com';
const CLIENT_KEY = process.env.YESCAPTCHA_CLIENT_KEY; // Read the clientKey from an environment variable

async function call(method, payload) {
  const res = await fetch(`${API}/${method}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ clientKey: CLIENT_KEY, ...payload }),
  });
  const data = await res.json();
  if (data.errorId) throw new Error(`${data.errorCode}: ${data.errorDescription}`);
  return data;
}

async function solve(task) {
  const { solution } = await call('createTask', { task });
  return solution;
}

// Base64-encode the image (no data: prefix)
const imageB64 = readFileSync('captcha.png').toString('base64');

const solution = await solve({
  type: "ImageToTextTaskOcrBase",
  body: imageB64,
});
console.log(solution.text);
```

An asynchronous task with options:

POST https://api.yescaptcha.com/createTask

```json
{
  "clientKey": "YOUR_CLIENT_KEY",
  "task": {
    "type": "ImageToTextTask",
    "body": "BASE64_IMAGE",
    "case": true,
    "numeric": 0,
    "minLength": 4,
    "maxLength": 6
  }
}
```

## Result

Synchronous types return directly from `createTask`:

```json
{
  "errorId": 0,
  "status": "ready",
  "solution": { "text": "LMResm" },
  "taskId": "2376919c-1863-11ec-a012-94e6f7355a0b"
}
```

Asynchronous types (`ImageToTextTask`, `ImageToTextTaskM1`) first return a `taskId`; poll `getTaskResult` every 5 seconds until the same `solution` arrives.

| Field | Type | Description |
| --- | --- | --- |
| `text` | string | The recognized text |

## Custom models

The general model works on any alphanumeric captcha but is slightly less accurate than a model trained for one style. If your images always look the same, [contact support](https://docs.yescaptcha.com/en/help/contact/) for a custom model and then select it with `ImageToTextTaskMuggle` and `project_name`.

## FAQ

### Am I charged when the text is wrong?

Synchronous types are charged whenever a result is returned, even if it is wrong. Compare other types or ask for a custom model.

### I get `ERROR_ZERO_CAPTCHA_FILESIZE` or `ERROR_PARSE_IMAGE_FAIL`

The Base64 is incomplete, or contains a `data:` prefix or line breaks. Check the encoding; see [Error codes](https://docs.yescaptcha.com/en/api/errors/).

## Related

-   [Quickstart](https://docs.yescaptcha.com/en/getting-started/quickstart/): a first request with `ImageToTextTaskOcrBase`
-   [Python samples](https://docs.yescaptcha.com/en/samples/python/)
