API — Captcha solving

A separate listener speaking the anti-captcha.com protocol: point third-party software at it and solve images, access cookies and reCAPTCHA v2 through your own proxies.

What this is

BlankTrail Proxy can accept captcha-solving tasks over the anti-captcha.com protocol. It is a separate listener on its own port: software that already speaks that protocol only needs to be pointed at your address instead of the solving service's.

The listener is separate rather than a set of routes on the dashboard port, for two reasons. Official protocol clients hit the host root, so they take the root paths entirely. And the captcha API may well be needed on the LAN where the dashboard must not be visible to anyone.

Off by defaultThe captcha API does not start until you enable it, and until then the port is not listened on at all. This is deliberate: a capability you do not use must not open a single port.

Turning it on

Three fields in the captcha_api section of the configuration file. The switch and the address can also be changed in the dashboard: Settings → the Captcha API card.

captcha_api:
  enabled: true
  addr: ":8892"
  allow_lan: false
  max_concurrent: 10
  task_ttl: "5m"
  port_idle_timeout: "10m"
FieldWhat it does
enabledWhether to start the listener. Off by default.
addrListener address. An empty host means loopback until allow_lan is on.
allow_lanWhether to accept requests from other machines. A setting of its own, separate from the dashboard's; on in the Docker image.
max_concurrentCap on concurrent tasks. Zero means no cap at all.
task_ttlHow long a finished task's answer is kept.
port_idle_timeoutHow long an idle port opened for a task's proxy is kept before closing.
Applies at onceThe switch and the address in the dashboard take effect immediately: the listener is raised or lowered on save, and an address already in use comes back as an error right in the dashboard. Editing the configuration file itself is still read at boot — restart the application for that.

In a container

Everything but the switch is already set up in the image: port 8892 is declared, the compose files shipped with it publish the port on 127.0.0.1, and the image configuration lets the listener bind beyond the loopback. All that is left is turning it on — with a variable or right in the dashboard. The override is one-way: variables turn things on and set values, but cannot switch off what the configuration has enabled.

docker run -d \
  -e BT_CAPTCHA_API_ENABLED=1 \
  -p 127.0.0.1:8892:8892 \
  ... blanktrail-proxy
Why allow_lan is on in the imageInside a container a request arrives from the Docker bridge address rather than from the loopback: with allow_lan off the bare host :8892 would bind to 127.0.0.1 and the published port would answer connection refused. The general BT_ALLOW_LAN still does not apply to the captcha API, and BT_CAPTCHA_API_ALLOW_LAN is only needed when you mount a configuration of your own instead of the image one.

Key and access

clientKey is your dashboard's API key — the very same one. There is no separate key for the captcha API: a second secret with its own storage and rotation is not worth introducing for a single surface.

  • The key travels in the request BODY, as the protocol requires, not in a header.
  • Key guessing is rate-limited: after a run of failures an address is refused regardless of whether the next key is correct.
  • Requests from other machines are refused until allow_lan is on — including getQueueStats and test.

Supported task types

TypeWhat it does
ImageToTextTaskReads the text on an image with a local model.
AntiGateTaskPasses the site's protection and returns the access cookies.
RecaptchaV2TaskSolves reCAPTCHA v2 from the page address and site key, through your proxy.
RecaptchaV2TaskProxylessThe same, but without your proxy — a direct exit.

Other protocol types answer ERROR_TASK_NOT_SUPPORTED. That is a normal answer, not a failure: the client sees it right at task creation and can go to another service without waiting.

How it works

  1. Create a task with createTask and get a numeric taskId.
  2. Poll getTaskResult while the answer says processing.
  3. Receive ready and the solution object — its contents depend on the task type.
Always HTTP 200Errors are reported by the errorId and errorCode fields in the body, not by the HTTP status — that is how the protocol works. A client seeing a non-200 would consider the service down and fall back to its own retries.

Reading an image

The image is passed as base64. The answer carries the recognised text in the text field.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "ImageToTextTask",
    "body": "iVBORw0KGgoAAAANSUhEUg..."
  }
}
The model is trained on its own setThe reader was trained on Google text captchas. On captchas drawn differently the accuracy is noticeably lower, and that is a property of the model rather than a setting: measure the success rate on your own material before building a process on it.

Access cookies

AntiGateTask passes the site's protection and returns the cookies. Alongside them the answer carries the address of the port through which those cookies must be presented.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "AntiGateTask",
    "websiteURL": "https://example.com/",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080,
    "proxyLogin": "user",
    "proxyPassword": "pass"
  }
}
The cookies work only through the named portThe solution contains a fingerprint field with a blanktrail.replayProxy address. Access cookies are bound to the exit-plus-fingerprint pair, and presented from another address or another client they will be rejected by the site. Send your request through that port — it is already open for your proxy and lives until the idle time set by port_idle_timeout.

reCAPTCHA v2

The task needs the page address and the site's public key. The variant without your proxy is called RecaptchaV2TaskProxyless and requires no proxy fields.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "RecaptchaV2Task",
    "websiteURL": "https://example.com/login",
    "websiteKey": "6Lc_aCMTAAAAA...",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080
  }
}

What happens to the userAgent you send

The userAgent you send does not go on the wire. It SELECTS the nearest profile by browser family, major version and operating system, and what goes on the wire is that profile's user-agent — together with the TLS and HTTP/2 fingerprints that match it.

Use the userAgent from the answerIn the solution, the userAgent field contains the ACTUAL user-agent the token was obtained under. Put exactly that into your request. A foreign header on top of our wire is precisely the mismatch this product removes: returning it would make the captcha API a source of tells instead of hiding them.

Methods

POST/createTaskclientKey required

Creates a task and returns a numeric taskId.

Response
{
  "errorId": 0,
  "taskId": 12
}
POST/getTaskResultclientKey required

Returns the task's state, and the solution object once it is ready.

Request
{
  "clientKey": "YOUR_API_KEY",
  "taskId": 12
}
Response
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "gRecaptchaResponse": "03AGdBq26...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
POST/getBalanceclientKey required

Returns the balance. The product has no billing, so the value is constant; zero means the licence is inactive.

POST/getQueueStatsno key required

Load: how many tasks are running and how busy the solver pool is.

POST/reportIncorrectImageCaptchaclientKey required

Accepted for compatibility: the product cannot learn from reports.

POST/reportIncorrectRecaptchaclientKey required

The same for reCAPTCHA.

POST/reportCorrectRecaptchaclientKey required

The same, for confirming a correct solution.

POST/testno key required

Returns the parsed request body. Useful when a third-party client sends the wrong thing.

Error codes

The codes and their names are the protocol's: client libraries compare the errorCode string itself. Below are the ones this service returns.

errorIderrorCodeWhen
1ERROR_KEY_DOES_NOT_EXISTThe key is wrong, or the address is temporarily blocked for guessing.
2ERROR_NO_SLOT_AVAILABLENo free solvers right now, or the max_concurrent cap is reached.
10ERROR_ZERO_BALANCEThe licence is inactive: renew it, tasks are not accepted.
11ERROR_IP_NOT_ALLOWEDThe request came from another machine while allow_lan is off.
12ERROR_CAPTCHA_UNSOLVABLESolving failed. You may retry, but the profile stays the same until the port closes on idle; if the failure repeats, check the page address and the site key.
16ERROR_NO_SUCH_CAPCHA_IDNo task with that taskId: it finished and was dropped once task_ttl elapsed, or it belongs to another key.
23ERROR_TASK_NOT_SUPPORTEDThe task type is not supported, or the required model is not installed.
25ERROR_PROXY_CONNECT_REFUSEDYour proxy refused the connection. Fix the proxy; retrying the task is pointless.
26ERROR_PROXY_CONNECT_TIMEOUTYour proxy could not be reached within the allotted time.
27ERROR_PROXY_READ_TIMEOUTYour proxy accepted the connection and went silent.
49ERROR_PROXY_NOT_AUTHORISEDYour proxy rejected the login or the password.
The proxy codes name YOUR proxyThe four codes 25, 26, 27 and 49 refer to the proxy you sent in the task, not to our exit. If your proxy answers correctly but solving failed, you will get ERROR_CAPTCHA_UNSOLVABLE: we do not blame your proxy for our own failure.

Limits

  • Tasks live in memory and do not survive a restart: afterwards the old taskId answers ERROR_NO_SUCH_CAPCHA_ID.
  • A task that does not finish within its budget is declared failed and frees its place in the cap.
  • There is no callback: the callbackUrl field is accepted and ignored, the result is fetched by polling.
  • Tasks for the same site through the same proxy run one after another — a property of the anti-replay design, not a configuration cap.

Where next