Troubleshooting

Ошибки Cloudflare Turnstile: диагностика и устранение

Turnstile вернул токен, а форма всё равно отвечает ошибкой? В большинстве случаев дело не в самом решении капчи, а в двух вещах: какие параметры вы отправили в API и куда потом подставили токен. Решатель отдаёт валидный токен — а дальше страница его отклоняет из-за неточного pageurl, чужого sitekey или неправильного поля.

Почти каждый сбой Cloudflare Turnstile попадает на один из трёх этапов, и диагностику стоит начинать именно с того, чтобы определить этот этап:

  • Этап отправки — задачу не приняли (in.php вернул код ошибки).
  • Этап опроса — задача принята, но опрос res.php не доходит до готового токена.
  • Этап проверки на странице — токен получен, но целевая страница его не принимает.

CaptchaAI решает Cloudflare Turnstile с высокой долей успешных решений, как правило, менее чем за 10 секунд. Поэтому если интеграция «падает», причину почти всегда стоит искать в своих параметрах, а не в решателе.

Три ошибки, которые дают больше всего провалов именно с Turnstile:

  1. Неточный pageurl — особенно на страницах проверки Cloudflare, где контекст строже.
  2. Не тот sitekey — снят с чужого элемента или другого экземпляра виджета.
  3. Токен подставлен не туда — страница ждёт cf-turnstile-response, обратный вызов или и то и другое.

Шпаргалка: ошибка → причина → исправление

Начните диагностику с этой таблицы: найдите свой симптом, определите этап и переходите к нужному разделу ниже.

Ошибка / симптом Этап Вероятная причина Что делать
ERROR_WRONG_USER_KEY Отправка Неверный API-ключ Проверьте 32-значный ключ
ERROR_KEY_DOES_NOT_EXIST Отправка Ключ не привязан к аккаунту Проверьте панель управления
ERROR_ZERO_BALANCE Отправка Нет свободных потоков Подождите или смените тариф
ERROR_PAGEURL Отправка Отсутствует pageurl Добавьте полный URL
ERROR_BAD_PARAMETERS Отправка Нет sitekey, method или pageurl Проверьте все обязательные поля
CAPCHA_NOT_READY Опрос Решение ещё идёт Подождите 5 секунд, повторите
ERROR_WRONG_ID_FORMAT Опрос Нечисловой ID капчи Используйте точный ID из in.php
ERROR_WRONG_CAPTCHA_ID Опрос Неверный ID капчи Сверьте ID из ответа на отправку
ERROR_EMPTY_ACTION Опрос Нет action=get Добавьте параметр action
Токен отклонён страницей Проверка Не то поле, не сработал обратный вызов, не тот URL Проверьте имя поля, вызовите обратный вызов, сверьте точный URL
Второе решение не проходит Проверка Повторное использование токена Запрашивайте новый токен на каждую отправку

Turnstile или Cloudflare Challenge: что перед вами

Сначала убедитесь, с чем вы вообще имеете дело. Часть «отклонённых токенов» на самом деле объясняется тем, что перед вами не встроенный виджет Turnstile, а полноэкранная проверка Cloudflare Challenge — а это другой сценарий интеграции.

Сигнал Cloudflare Turnstile Cloudflare Challenge
Что вы видите Встроенный виджет на странице (флажок или невидимый) Полноэкранный экран проверки Cloudflare
Что возвращает CaptchaAI Токен для подстановки в форму Cookie, подтверждающий прохождение проверки
Метод API turnstile cloudflare_challenge
Нужен ли прокси Необязателен Обязателен

Если перед вами полноэкранная проверка Cloudflare, а не встроенный виджет, используйте решатель Cloudflare Challenge: он возвращает cookie прохождения проверки и требует прокси. Если же это обычный виджет — читайте дальше.


Ошибки на этапе отправки задачи

Эти ошибки возникают при отправке задачи на https://ocr.captchaai.com/in.php — то есть до самого решения дело ещё не дошло, задачу просто не приняли в очередь.

Код ошибки Причина Что делать
ERROR_WRONG_USER_KEY Неверный формат API-ключа: он должен быть длиной 32 символа. Сверьте ключ на странице captchaai.com/api.php и скопируйте его целиком, без пробелов и переносов.
ERROR_KEY_DOES_NOT_EXIST Ключ отформатирован правильно, но не привязан к активной учётной записи. Откройте панель управления, убедитесь, что аккаунт активен, а ключ актуален.
ERROR_ZERO_BALANCE Нет свободных потоков в вашем тарифе — все заняты другими задачами. Дождитесь освобождения потоков, снизьте параллелизм или перейдите на тариф с большим числом потоков — например, с BASIC ($15/мес, 5 потоков) на STANDARD ($30/мес, 15 потоков).
ERROR_PAGEURL Отсутствует параметр pageurl. Добавьте полный URL — протокол, домен и путь (пример ниже).
ERROR_BAD_PARAMETERS Обязательные параметры отсутствуют или переданы в неверном формате. Проверьте набор обязательных полей (таблица ниже).
Ответ HTML или коды 500/502 Временный сбой на стороне сервера. Подождите 5–10 секунд и повторите запрос.

Для ERROR_PAGEURL передавайте URL целиком — протокол, домен и путь:

pageurl=https://https://staging.example.com/qa-login

Для ERROR_BAD_PARAMETERS проверьте, что для Turnstile переданы все обязательные параметры:

Параметр Тип Обязателен Описание
key Строка Да Ваш API-ключ CaptchaAI
method Строка Да Должно быть turnstile
sitekey Строка Да sitekey виджета Turnstile
pageurl Строка Да Полный URL страницы

Необязательные, но полезные параметры:

Параметр Тип Описание
action Строка Значение data-action или параметра action из turnstile.render()
proxy Строка Формат: login:password@IP:PORT
proxytype Строка HTTP, HTTPS, SOCKS4, SOCKS5

Где искать sitekey виджета Turnstile

sitekey — параметр, который чаще всего оказывается неправильным. Вот три места, где его можно взять.

Вариант 1 — атрибут data-sitekey:

<div class="cf-turnstile" data-sitekey="0x4AAAAAAAB1example"></div>

Вариант 2 — вызов turnstile.render():

turnstile.render('#captcha-container', {
  sitekey: '0x4AAAAAAAB1example',
  callback: function(token) {
    document.getElementById('cf-turnstile-response').value = token;
  }
});

Вариант 3 — перехват вызова рендеринга (для продвинутых):

Если sitekey подгружается динамически, переопределите turnstile.render до инициализации виджета и перехватите его параметры:

// Inject this before the Turnstile script loads
const originalRender = window.turnstile.render;
window.turnstile.render = function(container, params) {
  console.log('Sitekey:', params.sitekey);
  console.log('Action:', params.action);
  return originalRender.call(this, container, params);
};

Ошибки на этапе опроса результата

Эти ошибки возникают при опросе https://ocr.captchaai.com/res.php — задача уже принята, но до готового токена опрос не доходит.

Ответ Что это значит Что делать
CAPCHA_NOT_READY Это не ошибка: решение ещё идёт. Turnstile на CaptchaAI обычно решается менее чем за 10 секунд. Подождите 5 секунд и повторите опрос.
ERROR_WRONG_ID_FORMAT Идентификатор капчи содержит нечисловые символы. Используйте точный ID, который вернул in.php, без изменений.
ERROR_WRONG_CAPTCHA_ID Идентификатор не соответствует ни одной отправленной задаче. Сверьте ID с ответом на отправку задачи.
ERROR_EMPTY_ACTION В запросе на опрос нет параметра action. Всегда указывайте action=get (пример ниже).
ERROR_CAPTCHA_UNSOLVABLE Решить не удалось — вероятно, неверный sitekey или неподдерживаемая конфигурация страницы. Проверьте sitekey, обновите запрос и повторите попытку.
ERROR_INTERNAL_SERVER_ERROR Сбой на стороне сервера. Подождите 10 секунд и повторите запрос.

Правильный запрос на опрос с обязательным action=get выглядит так:

https://ocr.captchaai.com/res.php?key=YOUR_KEY&action=get&id=CAPTCHA_ID&json=1

Примечание. Для Turnstile всегда опрашивайте результат с json=1. В JSON-ответе может прийти user_agent решателя — некоторым страницам под защитой Cloudflare он нужен, чтобы токен успешно прошёл проверку.


Чем Turnstile отличается от других капч

Дальше начинаются самые неочевидные сбои — когда токен получен, но страница его не принимает. Прежде чем разбирать их, держите в голове три особенности Turnstile: именно из-за них большинство таких ошибок и возникает.

1. Точный URL страницы важнее, чем обычно

Токены Turnstile жёстко привязаны к контексту страницы. На страницах проверки Cloudflare (полноэкранный экран верификации) даже чуть-чуть другой путь в pageurl приводит к тому, что токен отклоняется. Это не «мелочь» — это самая частая причина, по которой валидный токен не проходит.

2. Два пути подстановки токена

Полученный токен подставляют одним из двух способов, и неправильный вариант просто не сработает:

Способ Когда применять
Скрытое поле — записать в cf-turnstile-response (иногда и в g-recaptcha-response) Когда на странице обычная форма со скрытым полем
Функция обратного вызова — вызвать функцию из turnstile.render() или data-callback Когда страница проверяет токен программно, без формы

3. Токен одноразовый

Токен Turnstile проверяется только один раз. Если автоматизация случайно отправит его дважды или возникнет состояние гонки, вторая попытка завершится ошибкой.


Когда токен получен, но страница его отклоняет

Такие сбои отлаживать сложнее всего: API успешно вернул токен, а целевая страница всё равно его не принимает.

Сбой 1: токен записан не в то поле

Симптом: форма отправляется, но страница выдаёт ошибку проверки или перезагружается.

Страницы Turnstile ждут токен в разных полях:

  • cf-turnstile-response — основное скрытое поле Turnstile;
  • g-recaptcha-response — некоторые страницы используют его как запасной вариант.

Исправление: проверьте форму на наличие обоих полей. В автоматизации браузера удобно записать токен сразу в оба:

# Selenium — inject into both fields for safety
driver.execute_script("""
    var cfField = document.querySelector('[name="cf-turnstile-response"]');
    var gField = document.querySelector('[name="g-recaptcha-response"]');
    if (cfField) cfField.value = arguments[0];
    if (gField) gField.value = arguments[0];
""", token)

Сбой 2: не сработал обратный вызов

Симптом: токен в поле есть, но форма всё равно не отправляется.

Причина: страница использует функцию обратного вызова вместо скрытого поля (или вдобавок к нему). Обратный вызов выполняет дополнительную логику — например, разблокирует кнопку отправки или шлёт AJAX-запрос.

Исправление: найдите и вызовите обратный вызов вручную:

// Check data-callback attribute
const callbackName = document.querySelector('.cf-turnstile').getAttribute('data-callback');
if (callbackName && window[callbackName]) {
  window[callbackName](token);
}

// Or if it was passed in turnstile.render()
// You may need to intercept the render call to capture it

Сбой 3: не тот контекст страницы

Симптом: токен отклонён, хотя sitekey верный и решение свежее.

Причина: pageurl в запросе к API не совпадает с фактическим контекстом страницы. Особенно часто это встречается на:

  • страницах проверки Cloudflare — в URL могут быть важные параметры запроса или части пути;
  • одностраничных приложениях (SPA) — видимый URL может отличаться от того, по которому загрузился виджет Turnstile.

Исправление: во вкладке «Сеть» DevTools найдите точный URL, с которого подгружается виджет Turnstile, и передавайте именно его в pageurl.

Сбой 4: повторное использование токена

Симптом: первое решение проходит, последующие — нет.

Причина: токены Turnstile одноразовые. После проверки на стороне Cloudflare токен становится недействительным.

Исправление: запрашивайте новое решение под каждую отправку формы. Не кэшируйте и не переиспользуйте токены.


Python: полный цикл решения Turnstile

import time
import requests

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "0x4AAAAAAAB1example"
PAGE_URL = "https://https://staging.example.com/qa-login"

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


def solve_turnstile(api_key, sitekey, pageurl):
    """Submit a Turnstile challenge and return the solved token."""

    # Submit
    submit_resp = requests.post(
        SUBMIT_URL,
        data={
            "key": api_key,
            "method": "turnstile",
            "sitekey": sitekey,
            "pageurl": pageurl,
            "json": 1,
        },
        timeout=30,
    )
    submit_resp.raise_for_status()
    submit_data = submit_resp.json()

    if submit_data.get("status") != 1:
        raise RuntimeError(f"Submit failed: {submit_data}")

    captcha_id = submit_data["request"]
    print(f"Task created — captcha ID: {captcha_id}")

    # Wait before first poll (Turnstile is fast — 10 seconds is usually enough)
    time.sleep(10)

    # Poll for result
    for _ in range(60):
        result_resp = requests.get(
            RESULT_URL,
            params={
                "key": api_key,
                "action": "get",
                "id": captcha_id,
                "json": 1,
            },
            timeout=30,
        )
        result_resp.raise_for_status()
        result_data = result_resp.json()

        if result_data.get("request") == "CAPCHA_NOT_READY":
            time.sleep(5)
            continue

        if result_data.get("status") == 1:
            return result_data["request"]

        raise RuntimeError(f"Polling error: {result_data}")

    raise TimeoutError("Turnstile solve timed out")


# Usage
token = solve_turnstile(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

# Inject into cf-turnstile-response and/or g-recaptcha-response
# Then submit the form

Node.js: полный цикл решения Turnstile

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "0x4AAAAAAAB1example";
const PAGE_URL = "https://https://staging.example.com/qa-login";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveTurnstile(apiKey, sitekey, pageurl) {
  // Submit
  const submitResp = await fetch(SUBMIT_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      key: apiKey,
      method: "turnstile",
      sitekey: sitekey,
      pageurl: pageurl,
      json: "1",
    }),
  });

  const submitData = await submitResp.json();
  if (submitData.status !== 1) {
    throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
  }

  const captchaId = submitData.request;
  console.log(`Task created — captcha ID: ${captchaId}`);

  // Turnstile is fast — wait 10 seconds before first poll
  await sleep(10_000);

  // Poll for result
  for (let i = 0; i < 60; i++) {
    const resultResp = await fetch(
      `${RESULT_URL}?${new URLSearchParams({
        key: apiKey,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );

    const resultData = await resultResp.json();

    if (resultData.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (resultData.status === 1) {
      return resultData.request;
    }

    throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
  }

  throw new Error("Turnstile solve timed out");
}

// Usage
solveTurnstile(API_KEY, SITEKEY, PAGE_URL)
  .then((token) => {
    console.log(`Solved token: ${token.slice(0, 80)}...`);
    // Inject into cf-turnstile-response and/or g-recaptcha-response
  })
  .catch(console.error);

Пример: парсер под нагрузкой из европейского региона

Практический сценарий из тех, что встречаются у RU-команд. Парсер развёрнут в европейском облачном регионе или на площадке в Центральной Азии, идёт пакетный сбор данных, и на пике Turnstile встречается на каждой сессии. Здесь всплывают сразу две проблемы:

  • Нехватка потоков. Если задачи уходят быстрее, чем решаются, часть из них упирается в ERROR_ZERO_BALANCE. Считайте число потоков от пиковой параллельной нагрузки, а не от среднего.
  • Нестабильная сеть. На мобильных и трансграничных каналах запросы к res.php иногда обрываются, поэтому опрос должен переживать таймауты: повторяйте попытку с экспоненциальной задержкой, а не одним циклом без запаса.

И отдельная оговорка про данные: собирайте только те данные, которые вы вправе обрабатывать (для RF-читателей ориентир — 152-ФЗ «О персональных данных»). Это вопрос вашей осмотрительности, а не функция CaptchaAI.


Часто задаваемые вопросы

За сколько CaptchaAI решает Turnstile?

Как правило, менее чем за 10 секунд. Пока решение идёт, res.php возвращает CAPCHA_NOT_READY — это не ошибка, а сигнал повторить опрос через 5 секунд.

Сколько потоков нужно, чтобы решать Turnstile параллельно?

Один поток — это одна задача в работе. Если отправлять капчи быстрее, чем они решаются, часть запросов упрётся в ERROR_ZERO_BALANCE. Считайте потоки от пиковой нагрузки: BASIC ($15/мес, 5 потоков) держит до пяти одновременных решений, STANDARD ($30/мес, 15 потоков) — до пятнадцати.

Почему первый токен проходит, а второй — нет?

Токены Turnstile одноразовые: после проверки на стороне Cloudflare токен становится недействительным. Запрашивайте новое решение под каждую отправку формы и не кэшируйте токены.

Обязателен ли параметр action при опросе результата?

Да. В запросе к res.php всегда указывайте action=get, иначе вернётся ERROR_EMPTY_ACTION. Параметр action из turnstile.render() — это другое: его передают при отправке задачи, если страница его использует.

Нужен ли прокси для Turnstile?

Для отдельного виджета Turnstile прокси необязателен — добавляйте proxy и proxytype, только если этого требует ваш сценарий. А вот для полноэкранной проверки Cloudflare Challenge прокси обязателен.


Как починить интеграцию Turnstile

Если интеграция Turnstile не работает, пройдитесь по чек-листу:

  1. Проверьте sitekey — возьмите его из data-sitekey или turnstile.render().
  2. Проверьте pageurl — используйте точный URL, включая протокол и путь.
  3. Проверьте путь токена — страница ждёт cf-turnstile-response, g-recaptcha-response или обратный вызов?
  4. Опрашивайте с json=1 — для результатов Turnstile всегда используйте JSON-ответ.
  5. Не переиспользуйте токены — запрашивайте новое решение на каждую отправку.

Начните с решателя Cloudflare Turnstile от CaptchaAI, сверьте параметры с документацией по API, а если нужен разбор механики виджета — прочитайте статью как устроен Cloudflare Turnstile.


Похожие статьи

Комментарии для этой статьи отключены.