Lorsqu'un utilisateur termine un défi reCAPTCHA v2, Google appelle une fonction de rappel JavaScript définie par le site. Ce rappel active généralement un bouton de soumission, valide le formulaire ou envoie une requête AJAX. Après avoir injecté un jeton résolu depuis CaptchaAI, vous devez déclencher le même rappel, sinon le formulaire ne reconnaîtra pas que le CAPTCHA a été résolu.
Comment fonctionnent les rappels
Le site définit un rappel dans le 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>
Lorsque l'utilisateur résout le CAPTCHA, le JavaScript de Google appelle onCaptchaSuccess(token). La fonction reçoit la chaîne de jeton comme seul argument.
Trouver la fonction de rappel
Méthode 1 : vérifier l'attribut de rappel de données
// In browser console
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
console.log('Callback:', callbackName);
Méthode 2 : vérifier les composants internes de grecaptcha
Certains sites utilisent grecaptcha.render() avec une option de rappel au lieu de l'attribut 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éthode 3 : Intercepter l’enregistrement du rappel
Exécutez ceci dans DevTools avant le chargement de la page (Sources → 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);
};
Déclencher le rappel après injection de token
Python (sélénium)
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://example.com/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 (Marionnette)
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 sans rappel de données
Certains sites n'utilisent pas de rappel. Au lieu de cela, ils vérifient grecaptcha.getResponse() lorsque le formulaire est soumis. Pour ces sites, remplacez la fonction :
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()
Rappels expirés
Certains sites définissent data-expired-callback pour désactiver le bouton de soumission lorsque le jeton expire. Si votre jeton est sur le point d'expirer, ce rappel peut se déclencher et reverrouiller le formulaire. Résolvez à l'approche de l'heure de soumission pour éviter cela.
// Check for expired callback
const expiredCallback = document.querySelector('.g-recaptcha')
?.getAttribute('data-expired-callback');
console.log('Expired callback:', expiredCallback);
Dépannage
| Problème | Parce que | Corriger |
|---|---|---|
| Formulaire toujours désactivé après injection | Rappel non déclenché | Rechercher et appeler la fonction de rappel |
ReferenceError: function not defined |
Rappel défini dans une fermeture | Utiliser la solution de secours ___grecaptcha_cfg |
| Jeton injecté mais AJAX non envoyé | Le rappel déclenche AJAX, pas la soumission du formulaire | Vérifiez ce que fait la fonction de rappel |
| Jeton accepté mais la page affiche une erreur | Le jeton a expiré avant le rappel | Résolvez plus près de l’heure de soumission |
FAQ
Et s'il n'y a aucun rappel ?
Certains sites ne vérifient le jeton côté serveur que lorsque le formulaire est soumis. Dans ce cas, il suffit de définir la valeur de la zone de texte g-recaptcha-response et de soumettre le formulaire.
Le nom de la fonction de rappel peut-il changer entre les chargements de page ?
Oui, sur certains sites. Extrayez toujours le nom de rappel dynamiquement du DOM plutôt que de le coder en dur.
reCAPTCHA v3 utilise-t-il le même mécanisme de rappel ?
Non. reCAPTCHA v3 utilise grecaptcha.execute() qui renvoie une promesse. Il n'y a pas de widget visible ni d'attribut data-callback.
Résolvez reCAPTCHA v2 avec une gestion appropriée des rappels à l'aide de CaptchaAI
Obtenez votre clé API surcaptchaai.com.
Guides associés
- reCAPTCHA v2 Invisible : Détection de déclenchement
- Extraction des paramètres reCAPTCHA de la source de la page
- Gestion de plusieurs CAPTCHA sur une seule page