Quando um usuário conclui um desafio reCAPTCHA v2, o Google chama uma função de retorno de chamada JavaScript definida pelo site. Esse retorno de chamada normalmente ativa um botão de envio, valida o formulário ou envia uma solicitação AJAX. Após injetar um token resolvido de CaptchaAI, você precisa acionar o mesmo callback — caso contrário, o formulário não reconhecerá que o CAPTCHA foi resolvido.
Como funcionam os retornos de chamada
O site define um retorno de chamada no widget reCAPTCHA:
<div class="g-recaptcha"
data-sitekey="6Le-SITEKEY"
data-callback="onCaptchaSuccess"
data-expired-callback="onCaptchaExpired">
</div>
<script>
function onCaptchaSuccess(token) {
document.getElementById('submit-btn').disabled = false;
document.getElementById('captcha-token').value = token;
}
</script>
Quando o usuário resolve o CAPTCHA, o JavaScript do Google chama onCaptchaSuccess(token). A função recebe a string do token como único argumento.
Encontrando a função de retorno de chamada
Método 1: verifique o atributo de retorno de chamada de dados
// In browser console
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
console.log('Callback:', callbackName);
Método 2: verificar os componentes internos do grecaptcha
Alguns sites usam grecaptcha.render() com uma opção de retorno de chamada em vez do atributo data-callback:
// Search page source for grecaptcha.render
document.querySelectorAll('script:not([src])').forEach(s => {
if (s.textContent.includes('grecaptcha.render')) {
console.log(s.textContent.match(/callback\s*:\s*(\w+)/)?.[1]);
}
});
Método 3: interceptar o registro de retorno de chamada
Execute isso no DevTools antes de a página carregar (Fontes → Snippets):
const origRender = grecaptcha.render;
grecaptcha.render = function(container, params) {
console.log('Render callback:', params.callback);
console.log('Expired callback:', params['expired-callback']);
return origRender.apply(this, arguments);
};
Acionando o retorno de chamada após envio controlado ao endpoint QA
Python (Selênio)
import requests
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
API_KEY = "YOUR_API_KEY"
driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")
# Extract sitekey and callback
sitekey = driver.find_element(
By.CSS_SELECTOR, ".g-recaptcha"
).get_attribute("data-sitekey")
callback = driver.find_element(
By.CSS_SELECTOR, ".g-recaptcha"
).get_attribute("data-callback")
# Solve with CaptchaAI
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": driver.current_url,
"json": "1",
}).json()
task_id = resp["request"]
token = None
for _ in range(24):
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["status"] == 1:
token = result["request"]
break
# Inject token into textarea
driver.execute_script("""
document.querySelector('textarea[name="g-recaptcha-response"]').value = arguments[0];
""", token)
# Trigger the callback
if callback:
driver.execute_script(f"window['{callback}'](arguments[0]);", token)
print(f"Triggered callback: {callback}")
else:
# Fallback: try ___grecaptcha_cfg
driver.execute_script("""
try {
var widgetId = Object.keys(___grecaptcha_cfg.clients)[0];
var callback = ___grecaptcha_cfg.clients[widgetId].aa.l.callback;
if (typeof callback === 'function') callback(arguments[0]);
} catch(e) {}
""", token)
print("Triggered callback via ___grecaptcha_cfg")
JavaScript (titereiro)
const puppeteer = require('puppeteer');
// After solving and getting the token...
await page.evaluate((token, callbackName) => {
// Set textarea value
const textarea = document.querySelector(
'textarea[name="g-recaptcha-response"]'
);
textarea.value = token;
textarea.style.display = 'block'; // sometimes hidden
// Trigger callback
if (callbackName && typeof window[callbackName] === 'function') {
window[callbackName](token);
console.log(`Called ${callbackName}()`);
} else {
// Fallback: search grecaptcha config
try {
const clients = ___grecaptcha_cfg.clients;
const widgetId = Object.keys(clients)[0];
const cb = clients[widgetId]?.aa?.l?.callback;
if (typeof cb === 'function') cb(token);
} catch (e) {}
}
}, token, callbackName);
Sites sem retorno de chamada de dados
Alguns sites não usam retorno de chamada. Em vez disso, eles verificam grecaptcha.getResponse() quando o formulário é enviado. Para esses sites, substitua a função:
driver.execute_script("""
const token = arguments[0];
document.querySelector('textarea[name="g-recaptcha-response"]').value = token;
// Override getResponse to return the token
if (typeof grecaptcha !== 'undefined') {
grecaptcha.getResponse = function() { return token; };
}
""", token)
# Then submit the form normally
driver.find_element(By.CSS_SELECTOR, "form").submit()
Retornos de chamada expirados
Alguns sites definem data-expired-callback para desabilitar o botão de envio quando o token expirar. Se o seu token estiver próximo da expiração, esse retorno de chamada poderá ser acionado e bloquear novamente o formulário. Resolva próximo ao momento do envio para evitar isso.
// Check for expired callback
const expiredCallback = document.querySelector('.g-recaptcha')
?.getAttribute('data-expired-callback');
console.log('Expired callback:', expiredCallback);
Solução de problemas
| Problema | Causa | Correção |
|---|---|---|
| Formulário ainda desativado após injeção | Retorno de chamada não acionado | Encontre e chame a função de retorno de chamada |
ReferenceError: function not defined |
Retorno de chamada definido em um encerramento | Usar substituto ___grecaptcha_cfg |
| Token injetado mas AJAX não enviado | O retorno de chamada aciona AJAX, não o envio do formulário | Verifique o que a função de retorno de chamada faz |
| Token aceito, mas a página mostra erro | O token expirou antes do retorno de chamada | Resolva mais perto do momento do envio |
Perguntas frequentes
E se não houver nenhum retorno de chamada?
Alguns sites verificam o token apenas no lado do servidor quando o formulário é enviado. Nesse caso, basta definir o valor da área de texto g-recaptcha-response e enviar o formulário.
O nome da função de retorno de chamada pode mudar entre carregamentos de página?
Sim, em alguns sites. Sempre extraia o nome do retorno de chamada dinamicamente do DOM, em vez de codificá-lo.
reCAPTCHA v3 usa o mesmo mecanismo de retorno de chamada?
Não. reCAPTCHA v3 usa grecaptcha.execute() que retorna uma promessa. Não há widget visível ou atributo data-callback.
Resolva reCAPTCHA v2 com tratamento de retorno de chamada adequado usando CaptchaAI
Obtenha sua chave API emcaptchaai.com.
Guias relacionados
- reCAPTCHA v2 Invisível: Detecção de gatilho
- Extraindo parâmetros reCAPTCHA da origem da página
- Lidando com vários CAPTCHAs em uma única página