Explications Techniques

Mécanisme de rappel reCAPTCHA v2 : comment fonctionnent les rappels et comment les déclencher

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
Les commentaires sont désactivés pour cet article.