Форма отправляется без единого клика по чекбоксу, а в HTML нет g-recaptcha-response — это и есть invisible reCAPTCHA. Проверка выполняется в фоне и завершается вызовом JS-колбэка, а не заполнением скрытого поля. Для CaptchaAI разница минимальна: к обычному запросу userrecaptcha достаточно добавить параметр invisible=1. А вот на стороне сайта разница критична — если не найти и не вызвать нужный колбэк, готовый токен просто некуда девать, и форма зависает.
Ошибка, с которой сталкивается большинство команд, — не в получении токена (это стандартный вызов in.php/res.php), а в его внедрении: разработчики по привычке ищут скрытое поле g-recaptcha-response, хотя в подавляющем большинстве invisible-реализаций сайт ждёт window['имяКолбэка'](token). Ниже — рабочий процесс целиком: как распознать invisible reCAPTCHA, отправить задачу в CaptchaAI и корректно вернуть токен на страницу, включая запасной вариант на случай, если явного колбэка не видно.
Не уверены, перед вами стандартная v2 или invisible-версия? Как отличить reCAPTCHA v2 от invisible — признаки, по которым это видно за секунды.
Коротко весь сценарий выглядит так:
- находите на странице признак invisible-виджета;
- добавляете
invisible=1к обычному запросуuserrecaptcha; - получаете токен через
in.php/res.php, как для стандартной v2; - отдаёте токен не в скрытое поле, а в JS-колбэк сайта.
Что понадобится для решения
- API-ключ CaptchaAI — получить можно на captchaai.com/api.php
- Sitekey — значение атрибута
data-sitekeyна виджете или кнопке - URL страницы — полный адрес страницы, где запускается invisible-проверка
- Инструмент автоматизации — Selenium, Puppeteer или Playwright, чтобы выполнить колбэк в браузере
Шаг 1. Определите invisible reCAPTCHA на странице
Прежде чем звать API, убедитесь, что перед вами действительно invisible-версия, а не обычная v2 с автосабмитом. В разметке страницы встречается один из трёх вариантов:
<!-- Option 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..." data-size="invisible" data-callback="onSubmit"></div>
<!-- Option 2: button with data-sitekey (invisible by default) -->
<button data-sitekey="6LdKlZEU..." data-callback="onSubmit">Submit</button>
<!-- Option 3: programmatic execution -->
<script>
grecaptcha.execute('6LdKlZEU...', {action: 'submit'});
</script>
Если нашли data-size="invisible", кнопку с data-sitekey без обёртки-виджета рядом или вызов grecaptcha.execute() без видимого контейнера — перед вами invisible reCAPTCHA, и дальше в запрос понадобится параметр invisible=1.
Шаг 2. Отправьте задачу в CaptchaAI
Запрос почти не отличается от обычной reCAPTCHA v2 — меняется один параметр. invisible=1 сообщает CaptchaAI, что решение адресовано именно этой разметке; без него совместимость с частью invisible-виджетов не гарантирована.
import requests
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6LdKlZEUAAAAAPoxm...",
"pageurl": "https://example.com/signup",
"invisible": 1,
"json": 1
})
task_id = response.json()["request"]
const params = new URLSearchParams({
key: "YOUR_API_KEY", method: "userrecaptcha",
googlekey: "6LdKlZEUAAAAAPoxm...",
pageurl: "https://example.com/signup",
invisible: 1, json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const { request: taskId } = await res.json();
Если виджет ещё и Enterprise-версии, добавьте к тем же параметрам enterprise=1 — остальной процесс не меняется.
Шаг 3. Опросите res.php до готовности токена
Задача решается асинхронно, поэтому сразу в ответе токена нет — только id. Опрашивайте res.php с паузой в несколько секунд, пока status не станет 1.
import time
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
break
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Error: {result['request']}")
Шаг 4. Передайте токен через колбэк, а не через поле
Это ключевой шаг всего сценария — большинство ошибок интеграции invisible reCAPTCHA случается именно здесь, а не на этапе решения. Сайт с invisible-виджетом обычно ждёт вызов JS-функции: имя колбэка указано в атрибуте data-callback на том же элементе, где стоит data-sitekey. Найдите это имя через DOM и вызовите функцию с полученным токеном в качестве аргумента.
# Selenium example
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com/signup")
# Find the callback name
callback = driver.execute_script("""
var el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
var btn = document.querySelector('[data-sitekey]');
if (btn) return btn.getAttribute('data-callback');
return null;
""")
# Execute the callback with the token
if callback:
driver.execute_script(f"window['{callback}']('{token}');")
else:
# Fallback: fill hidden field and submit
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.querySelector('form').submit();
""")
// Puppeteer example
await page.evaluate((token) => {
const el = document.querySelector('[data-callback]') || document.querySelector('[data-sitekey]');
const callbackName = el?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
window[callbackName](token);
} else {
document.getElementById('g-recaptcha-response').innerHTML = token;
document.querySelector('form').submit();
}
}, token);
Если явного data-callback нет, а форма всё равно не отправляется сама, сработает запасной вариант из примера выше: заполнить скрытое поле g-recaptcha-response и вызвать submit() формы вручную — так устроена часть старых invisible-реализаций, унаследованных от обычной v2.
Пример: прогон из удалённого региона
Команда в Алматы или Минске нередко гоняет автотесты формы регистрации против стенда, который физически стоит в Европе. Это меняет цифры, на которые стоит ориентироваться при интеграции invisible reCAPTCHA:
- RTT в 150–250 мс на каждый запрос к
res.php— обычное дело для межрегионального прогона, а не признак проблемы на стороне CaptchaAI; - при нестабильном мобильном или Wi-Fi-соединении тестового окружения задержка может скакать ещё сильнее — закладывайте запас, а не сокращайте цикл опроса;
- если форма собирает персональные данные пользователя (email, телефон, паспортные поля), тестируйте только на staging-данных, которые вы вправе обрабатывать — это касается и российских проектов под 152-ФЗ, и команд, ориентирующихся на GDPR.
Практический вывод: 40 попыток опроса с паузой 5 секунд из примера выше — стартовая точка, а не жёсткое правило. Для стендов в другом регионе разумно увеличить либо число попыток, либо паузу между ними.
Полная рабочая функция
Тот же цикл «отправить → опросить → вернуть токен», собранный в одну функцию, которую можно переиспользовать в пайплайне без копирования кода по шагам:
import requests
import time
def solve_invisible_recaptcha(api_key, sitekey, page_url):
submit = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key, "method": "userrecaptcha", "googlekey": sitekey,
"pageurl": page_url, "invisible": 1, "json": 1
}).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit error: {submit.get('request')}")
task_id = submit["request"]
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {result.get('request')}")
raise TimeoutError("Timed out")
token = solve_invisible_recaptcha("YOUR_API_KEY", "6LdKlZEU...", "https://example.com/signup")
Полный рабочий пример
Фрагментов кода из шагов 1–4 достаточно для интеграции, но в готовом репозитории есть то, что обычно дописывают отдельно:
- настройка окружения и переменных (
.env, зависимости); - повторные попытки при сетевых сбоях, а не только при
CAPCHA_NOT_READY; - обработка ошибок API и логирование.
Смотрите полный пример на GitHub →
Частые вопросы
Вопросы ниже — то, что обычно всплывает уже после первого успешного решения, на этапе продакшен-нагрузки и разбора граничных случаев.
Сколько потоков тарифа CaptchaAI заложить под invisible reCAPTCHA на нагруженной форме?
Отдельного тарифа под invisible-версию нет — тарификация такая же, как у обычной v2, по числу одновременных потоков, а не по количеству отправок формы за день. Ориентир по параллельности запросов, а не по общему трафику за день:
- при нескольких десятках одновременных заявок в пике (invisible reCAPTCHA обычно укладывается в SLA до 30 секунд) уровня BASIC ($15/мес, 5 потоков) обычно мало;
- STANDARD ($30/мес, 15 потоков) закрывает такую нагрузку с запасом на пиковые всплески.
Как отличить invisible reCAPTCHA от обычной v2 на странице?
Два быстрых признака:
- на виджете стоит
data-size="invisible", а не видимый чекбокс «Я не робот»; - в коде страницы есть прямой вызов
grecaptcha.execute()без контейнера рядом.
Если оба признака совпадают — это invisible-версия, и дальше применяется сценарий из этого руководства.
Что будет, если отправить задачу без invisible=1?
Возможны два сценария:
- CaptchaAI обработает задачу как обычную reCAPTCHA v2, и в части случаев токен всё равно примется;
- для реализаций с колбэком сайт нередко отклоняет такой токен как невалидный.
Если на шаге 1 вы определили invisible-версию, параметр стоит передавать всегда, а не рассчитывать на первый сценарий.
Обязательно ли использовать headless-браузер, или колбэк можно вызвать без него?
Обязательно нужен движок с поддержкой DOM и JS — invisible reCAPTCHA ожидает вызов функции в контексте страницы, а не HTTP-запрос. Чистый requests/fetch-клиент без Selenium, Puppeteer или Playwright не сможет ни найти data-callback, ни выполнить его.
Можно ли использовать один колбэк для нескольких invisible-виджетов на одной странице?
Технически да, но у каждого виджета должно быть собственное имя функции в data-callback:
- общий колбэк на несколько виджетов — последний вызов перезапишет токен предыдущего;
- уникальное имя под каждый
sitekey— единственный надёжный вариант для форм с несколькими invisible-полями.
Похожие материалы
Прежде чем переходить к следующей интеграции, пригодятся ещё несколько руководств:
- Как работает invisible reCAPTCHA
- Типичные ошибки invisible reCAPTCHA и как их избежать
- reCAPTCHA v2 против invisible: как отличить
- Как решить callback reCAPTCHA v2 через API
Начните решать invisible reCAPTCHA
Получите API-ключ на captchaai.com/api.php, добавьте invisible=1 к уже работающему запросу reCAPTCHA v2 и подключите шаблон внедрения токена через колбэк из шага 4 — обычно это единственное место, которое приходится дорабатывать при переходе с обычной v2 на invisible.