O formulário emperra no checkbox "Não sou um robô"? Isso é reCAPTCHA v2, e dá para resolvê-lo com quatro chamadas de API: capture sitekey e pageurl, envie a tarefa ao solver reCAPTCHA v2 da CaptchaAI, aguarde o token e injete-o de volta no formulário antes de reenviar. Sem teoria — só o código Python e Node.js para copiar e rodar.
Ainda não sabe se é v2, v3 ou Enterprise? Confira antes como identificar a versão do reCAPTCHA.
Pré-requisitos para resolver reCAPTCHA v2 via API
| Requisito | Detalhes |
|---|---|
| API key da CaptchaAI | Pegue em captchaai.com/api.php. 32 caracteres. |
| URL completa da página | Onde o widget reCAPTCHA v2 é carregado. |
| sitekey | A chave pública do widget naquela página. |
| Cliente HTTP | requests, axios, fetch ou curl. |
| Threads disponíveis | Sua conta precisa de threads livres no plano contratado. |
Passo 1: capture o sitekey e o pageurl
O pageurl é a URL completa da página, com o esquema (https://). O sitekey costuma aparecer em três lugares:
1. No HTML — procure o atributo data-sitekey no container do widget:
<div class="g-recaptcha" data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"></div>
2. Na URL do iframe — algo como https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-&... — o parâmetro k= é o sitekey.
3. No tráfego de rede — DevTools → Network, filtre por recaptcha e veja o k em qualquer requisição.
Passo 2: envie a tarefa ao endpoint in.php
import requests
API_KEY = "YOUR_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGEURL = "https://staging.example.com/qa-login"
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": SITEKEY,
"pageurl": PAGEURL,
"json": 1,
}).json()
assert submit["status"] == 1, submit
task_id = submit["request"]
print("task id:", task_id)
Mesma chamada em Node.js:
const r = await fetch("https://ocr.captchaai.com/in.php", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: API_KEY,
method: "userrecaptcha",
googlekey: SITEKEY,
pageurl: PAGEURL,
json: "1",
}),
});
const { status, request: taskId } = await r.json();
if (status !== 1) throw new Error(taskId);
reCAPTCHA invisível? Acrescente
invisible=1ao payload. Detalhes em como funciona o reCAPTCHA invisível.
Passo 3: faça polling no res.php até sair o token
O reCAPTCHA v2 costuma resolver entre 15 e 60 segundos. Espere 20 s antes da primeira consulta e repita a cada 5 s.
import time
time.sleep(20)
while True:
res = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if res.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if res.get("status") == 1:
token = res["request"]
print("token:", token[:60], "…")
break
raise RuntimeError(res)
O token devolvido é uma string longa, normalmente começando com 03AGdBq25....
Passo 4: injete o token de volta no formulário
Depende de como o site espera recebê-lo. O caso mais comum é o textarea g-recaptcha-response:
document.querySelector('textarea[name="g-recaptcha-response"]').value = token;
document.querySelector("form").submit();
Com Selenium:
driver.execute_script(
"document.querySelector('[name=\"g-recaptcha-response\"]').value = arguments[0];",
token,
)
driver.find_element(By.CSS_SELECTOR, "form").submit()
Com Playwright:
await page.evaluate((t) => {
document.querySelector('[name="g-recaptcha-response"]').value = t;
}, token);
await page.click('button[type="submit"]');
Se o widget tiver data-callback, chame a função também:
const callback = document.querySelector(".g-recaptcha").dataset.callback;
if (callback && window[callback]) window[callback](token);
Exemplo completo em Python
import time
import requests
API_KEY = "YOUR_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGEURL = "https://staging.example.com/qa-login"
def solve_recaptcha_v2():
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY, "method": "userrecaptcha",
"googlekey": SITEKEY, "pageurl": PAGEURL, "json": 1,
}).json()
if submit["status"] != 1:
raise RuntimeError(submit)
task_id = submit["request"]
time.sleep(20)
for _ in range(40):
res = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1,
}).json()
if res.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if res.get("status") == 1:
return res["request"]
raise RuntimeError(res)
raise TimeoutError("solve timed out")
if __name__ == "__main__":
token = solve_recaptcha_v2()
print("token:", token[:80])
Erros comuns da API e como resolver
| Erro | Causa | O que fazer |
|---|---|---|
ERROR_GOOGLEKEY |
sitekey vazio ou inválido | Extraia o sitekey de novo, direto da página atual |
ERROR_PAGEURL |
Faltou o parâmetro pageurl |
Envie a URL completa, com o esquema https:// |
ERROR_ZERO_BALANCE |
Sem threads livres | Aguarde liberar ou faça upgrade de plano |
ERROR_CAPTCHA_UNSOLVABLE |
O site endureceu o desafio | Tente de novo; veja erros comuns do reCAPTCHA v2 |
| Site rejeita o token mesmo assim | O token expirou | Use o token em até ~110 s após recebê-lo |
Quando o token chega mas o site não aceita
| Sintoma | Causa provável | Correção |
|---|---|---|
| Token volta, mas o formulário segue bloqueado | O site tem handler próprio no callback | Localize data-callback e chame a função direto, em vez de só preencher o textarea |
| Site rejeita mesmo com token válido | Cookies/User-Agent diferentes dos usados ao pedir o token |
Reenvie os mesmos cookies e o mesmo User-Agent que estavam ativos na captura do sitekey |
| reCAPTCHA sensível ao IP de origem | O solver resolveu com um IP diferente do esperado pelo site | Inclua proxy e proxytype no envio para o solver usar seu pool de IPs |
Consultas ao res.php chegam cedo demais |
Worker rodando fora dos EUA, RTT alto até a CaptchaAI | Ajuste o tempo de espera (ver seção de latência abaixo) |
Latência ao resolver a partir de workers no Brasil
Rodar o worker em sa-east-1 (São Paulo) ou em outra região próxima ao Brasil reduz o RTT até os servidores da CaptchaAI, mas também significa que o tempo de ida e volta já consome parte da janela de espera padrão. Se as primeiras consultas ao res.php costumam voltar com CAPCHA_NOT_READY mais vezes do que o esperado, meça o RTT real do seu ambiente e ajuste os 20 s iniciais e o intervalo de 5 s entre tentativas — o valor do código é um ponto de partida seguro, não um limite fixo da API.
Se o seu pipeline grava pageurl, sitekey ou outros parâmetros de requisição em log para depuração, trate esses campos como dado pessoal sob a LGPD (ou o RGPD, para operações em Portugal): defina retenção curta e evite persistir URLs que contenham identificadores de sessão ou de usuário.
Perguntas frequentes
Quanto tempo leva para resolver um reCAPTCHA v2 pela API?
Entre 15 e 60 segundos. Espere 20 s antes da primeira consulta ao res.php e repita a cada 5 s.
O token do reCAPTCHA v2 expira?
Sim, vale por cerca de 110–120 s após emitido. Se o fluxo demora mais, gere um token novo.
Dá para reaproveitar esse código para Turnstile ou GeeTest v3?
Sim. A estrutura de envio e polling em in.php/res.php é a mesma usada em Cloudflare Turnstile — muda o method e o parâmetro da sitekey.
Recebi o token, mas o site continua bloqueando. O que fazer?
Confirme o campo (g-recaptcha-response ou callback do widget), a validade do token e se o handler pós-token dispara corretamente. Compare o tráfego de rede de uma resolução manual com o da automação para achar a diferença.
Preciso de um navegador para chamar a API do reCAPTCHA v2?
Não. A submissão ao in.php e a consulta ao res.php são chamadas HTTP simples — funcionam em qualquer linguagem com cliente HTTP. Um navegador (ou Selenium/Playwright) só entra na etapa de injeção do token, se o fluxo de login exigir uma página real.