Tutoriels API

Comment résoudre le rappel reCAPTCHA v2 à l'aide de l'API

Certains sites Web implémentent reCAPTCHA v2 avec une fonction de rappel au lieu du champ caché standard g-recaptcha-response. Lorsque vous résolvez le CAPTCHA et injectez le jeton dans le champ masqué, rien ne se passe : la page l'ignore. En effet, le site s'attend à ce que vous appeliez une fonction JavaScript avec le jeton à la place.

Ce guide vous montre comment détecter reCAPTCHA v2 basé sur le rappel, le résoudre via l'API CaptchaAI et appeler correctement le rappel. L'appel API est identique au standard reCAPTCHA v2 — seule l'étape d'injection du jeton change.

Nouveau sur reCAPTCHA v2 ? Commencez parComment résoudre reCAPTCHA v2 à l'aide de l'APIpour le flux standard, puis revenez ici pour la variante de rappel.


Ce dont vous avez besoin avant de commencer

Exigence Détails
Clé API CaptchaAI Obtenez-en un auprès decaptchaai.com/api.php. Chaîne de 32 caractères.
URL de la page cible L'URL complète où le widget reCAPTCHA v2 se charge.
Clé de site reCAPTCHA v2 La clé publique liée à l'instance du widget.
Outil d'automatisation du navigateur Selenium, Puppeteer ou Playwright : vous devez exécuter JavaScript pour appeler le rappel.
Nom de la fonction de rappel La fonction JavaScript que le site s'attend à recevoir le jeton.

Comment identifier une implémentation de rappel

Le standard reCAPTCHA v2 écrit le jeton résolu dans une zone de texte cachée g-recaptcha-response. Les implémentations de rappel ignorent cela et appellent directement une fonction JavaScript. Voici comment faire la différence.

Méthode 1 : vérifiez l'attribut data-callback

Inspectez le div du widget reCAPTCHA dans la source de la page :

<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
     data-callback="SubmitToken">
</div>

Si data-callback existe, le site utilise un rappel. La valeur (SubmitToken) est le nom de la fonction dont vous avez besoin.

Méthode 2 : Vérifiez les appels grecaptcha.render()

Recherchez grecaptcha.render dans le JavaScript de la page :

grecaptcha.render('recaptcha-container', {
  sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
  callback: userVerified
});

La propriété callback nomme la fonction. Dans ce cas, userVerified.

Méthode 3 : Inspecter la configuration interne de reCAPTCHA

Ouvrez la console du navigateur sur la page cible et exécutez :

___grecaptcha_cfg.clients[0]

Parcourez l'arborescence des objets pour rechercher la propriété callback. Le chemin exact varie selon le site : il peut s'agir de clients[0].aa.l.callback ou autre chose en fonction de la version et de la minification de reCAPTCHA. Si la page comporte plusieurs instances reCAPTCHA, cochez clients[1], clients[2], etc.

Script de détection rapide

Exécutez ceci dans la console du navigateur pour rechercher automatiquement les noms de rappel :

// Check data-callback attributes
document.querySelectorAll('[data-callback]').forEach(el => {
  console.log('data-callback:', el.getAttribute('data-callback'));
});

// Check internal config
if (typeof ___grecaptcha_cfg !== 'undefined') {
  Object.keys(___grecaptcha_cfg.clients).forEach(key => {
    const client = ___grecaptcha_cfg.clients[key];
    console.log(`Client ${key}:`, JSON.stringify(client, null, 2));
  });
}

En quoi la résolution de rappel diffère de la version 2 standard

L'appel API à CaptchaAI est identique. La seule différence réside dans ce que vous faites avec le jeton après l’avoir reçu.

Étape Norme v2 Rappel v2
1. Soumettre à CaptchaAI method=userrecaptcha + clé de site + URL de page Idem
2. Sondage pour le résultat action=get + identifiant captcha Idem
3. Recevez un jeton Même format de jeton Idem
4. Injecter le jeton Définir la valeur du champ g-recaptcha-response Appelez la fonction de rappel avec le jeton
5. Soumettre le formulaire Soumettre le formulaire de déclenchement Généralement automatique : le rappel s'en charge

Critique : Ne définissez pas g-recaptcha-response sur les implémentations basées sur le rappel. La page ignore ce champ et attend que la fonction de rappel se déclenche. Définir le champ sans appeler le rappel donnera l’impression que le CAPTCHA n’a jamais été résolu.


Flux de résolution

Page → extract sitekey + pageurl + callback name
                    ↓
      POST to in.php (method=userrecaptcha)
                    ↓
           receive captcha ID
                    ↓
         wait 15–20 seconds
                    ↓
      GET res.php (action=get, id=…)
          ↓                    ↓
   CAPCHA_NOT_READY       status=1 → token
    (wait 5s, retry)            ↓
                     invoke callback(token)
                              ↓
               site processes token automatically

Implémentation Python (Sélénium)

import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://example.com/login"
CALLBACK_NAME = "SubmitToken"  # The callback function name from the page

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


def solve_recaptcha_v2(api_key, sitekey, pageurl):
    """Submit a reCAPTCHA v2 task and return the solved token."""

    # Step 1: Submit the captcha
    submit_resp = requests.post(
        SUBMIT_URL,
        data={
            "key": api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "json": 1,
        },
        timeout=30,
    )
    submit_resp.raise_for_status()
    submit_data = submit_resp.json()

    if submit_data.get("status") != 1:
        raise RuntimeError(f"Submit failed: {submit_data}")

    captcha_id = submit_data["request"]
    print(f"Task created — captcha ID: {captcha_id}")

    # Step 2: Wait before first poll
    time.sleep(15)

    # Step 3: Poll for result
    for _ in range(60):
        result_resp = requests.get(
            RESULT_URL,
            params={
                "key": api_key,
                "action": "get",
                "id": captcha_id,
                "json": 1,
            },
            timeout=30,
        )
        result_resp.raise_for_status()
        result_data = result_resp.json()

        if result_data.get("request") == "CAPCHA_NOT_READY":
            time.sleep(5)
            continue

        if result_data.get("status") == 1:
            return result_data["request"]

        raise RuntimeError(f"Polling error: {result_data}")

    raise TimeoutError("reCAPTCHA v2 solve timed out")


def detect_callback_name(driver):
    """Detect the reCAPTCHA callback function name from the page."""

    # Try data-callback attribute first
    callback = driver.execute_script("""
        const el = document.querySelector('[data-callback]');
        if (el) return el.getAttribute('data-callback');
        return null;
    """)
    if callback:
        return callback

    # Try internal reCAPTCHA config
    callback = driver.execute_script("""
        if (typeof ___grecaptcha_cfg === 'undefined') return null;
        const clients = ___grecaptcha_cfg.clients;
        for (const key of Object.keys(clients)) {
            const client = clients[key];
            // Walk the object tree to find a callback function
            const json = JSON.stringify(client);
            const match = json.match(/"callback":"(\\w+)"/);
            if (match) return match[1];
        }
        return null;
    """)
    return callback


# Main workflow
driver = webdriver.Chrome()
driver.get(PAGE_URL)

# Detect the callback name (or use the known name)
detected = detect_callback_name(driver)
callback_name = detected or CALLBACK_NAME
print(f"Using callback: {callback_name}")

# Solve the CAPTCHA
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

# Invoke the callback with the token
driver.execute_script(f"{callback_name}(arguments[0]);", token)
print("Callback invoked — site should process the token automatically")

# Wait for the page to process
time.sleep(3)
driver.quit()

Qu'est-ce que cela fait :

  1. Soumet la clé de site et l'url de page à in.php avec method=userrecaptcha — identique à la norme v2.
  2. Interroge res.php toutes les 5 secondes jusqu'à ce que le jeton soit prêt.
  3. Détecte le nom de la fonction de rappel à partir de la page DOM.
  4. Appelle la fonction de rappel avec le jeton résolu à l'aide de execute_script.
  5. Le JavaScript du site gère le reste : soumission de formulaire, validation ou redirection de page.

Implémentation de Node.js (Puppeteer)

const puppeteer = require("puppeteer");

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://example.com/login";
const CALLBACK_NAME = "SubmitToken";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
  // Step 1: Submit the captcha
  const submitResp = await fetch(SUBMIT_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      key: apiKey,
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: pageurl,
      json: "1",
    }),
  });

  const submitData = await submitResp.json();
  if (submitData.status !== 1) {
    throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
  }

  const captchaId = submitData.request;
  console.log(`Task created — captcha ID: ${captchaId}`);

  // Step 2: Wait before first poll
  await sleep(15_000);

  // Step 3: Poll for result
  for (let i = 0; i < 60; i++) {
    const resultResp = await fetch(
      `${RESULT_URL}?${new URLSearchParams({
        key: apiKey,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );

    const resultData = await resultResp.json();

    if (resultData.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (resultData.status === 1) {
      return resultData.request;
    }

    throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
  }

  throw new Error("reCAPTCHA v2 solve timed out");
}

async function detectCallbackName(page) {
  return page.evaluate(() => {
    // Try data-callback attribute
    const el = document.querySelector("[data-callback]");
    if (el) return el.getAttribute("data-callback");

    // Try internal config
    if (typeof ___grecaptcha_cfg !== "undefined") {
      const clients = ___grecaptcha_cfg.clients;
      for (const key of Object.keys(clients)) {
        const json = JSON.stringify(clients[key]);
        const match = json.match(/"callback":"(\w+)"/);
        if (match) return match[1];
      }
    }

    return null;
  });
}

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto(PAGE_URL, { waitUntil: "networkidle2" });

  // Detect callback
  const detected = await detectCallbackName(page);
  const callbackName = detected || CALLBACK_NAME;
  console.log(`Using callback: ${callbackName}`);

  // Solve the CAPTCHA
  const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
  console.log(`Solved token: ${token.slice(0, 80)}...`);

  // Invoke the callback
  await page.evaluate(
    (name, tkn) => {
      window[name](tkn);
    },
    callbackName,
    token
  );
  console.log("Callback invoked — site should process the token automatically");

  await sleep(3_000);
  await browser.close();
})();

Implémentation PHP

L'appel API est le même en PHP. L’appel de rappel nécessite un contexte de navigateur, cet exemple couvre donc la résolution côté serveur. Utilisez un outil de navigateur sans tête (par exemple, PHP WebDriver) pour l'étape d'injection.

<?php
$apiKey  = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://example.com/login";

// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
    "key"       => $apiKey,
    "method"    => "userrecaptcha",
    "googlekey" => $sitekey,
    "pageurl"   => $pageurl,
    "json"      => 1,
]));

$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
    die("Submit failed: " . $submit);
}

$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";

// Step 2: Wait and poll
sleep(15);

for ($i = 0; $i < 60; $i++) {
    $result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
        "key"    => $apiKey,
        "action" => "get",
        "id"     => $captchaId,
        "json"   => 1,
    ]));

    $resultData = json_decode($result, true);

    if ($resultData["request"] === "CAPCHA_NOT_READY") {
        sleep(5);
        continue;
    }

    if ($resultData["status"] === 1) {
        $token = $resultData["request"];
        echo "Solved token: " . substr($token, 0, 80) . "...\n";
        // Pass $token to your browser automation to invoke the callback
        break;
    }

    die("Polling error: " . $result);
}

Après avoir obtenu le jeton en PHP, utilisez un outil d'automatisation du navigateur (par exemple, php-webdriver) pour exécuter :

SubmitToken("TOKEN_FROM_CAPTCHAAI");

Erreurs courantes

# Erreur Que se passe-t-il Corriger
1 Définition de g-recaptcha-response au lieu d'appeler le rappel La page ignore le jeton – le formulaire n'est jamais soumis Recherchez le nom de rappel et invoquez-le avec le jeton
2 Mauvais nom de la fonction de rappel Erreur JavaScript : fonction non définie Revérifiez data-callback, grecaptcha.render() ou la configuration interne
3 Le rappel est sur un index client différent Mauvaise instance reCAPTCHA ciblée sur des pages multi-widgets Vérifiez ___grecaptcha_cfg.clients[1], clients[2], etc.
4 Appel du rappel avant que la page ne soit prête Fonction non encore définie dans le contexte de la page Attendez DOMContentLoaded ou networkidle avant d'invoquer
5 En utilisant un nom /minified masqué Le nom de rappel dans la source est mutilé Utilisez la console du navigateur d'exécution pour trouver la référence réelle de la fonction
6 Mélange de rappel v2 avec invisible v2 Certaines implémentations invisibles utilisent également des rappels Vérifiez si data-size="invisible" est présent - si c'est le cas, voirComment résoudre reCAPTCHA Invisible à l'aide de l'API

Dépannage

Jeton résolu mais la page ne réagit pas

La cause la plus courante : vous définissez g-recaptcha-response au lieu d'appeler le rappel. Vérifiez si le widget a data-callback ou callback dans grecaptcha.render(). Si tel est le cas, vous devez appeler cette fonction.

ReferenceError: SubmitToken is not defined

La fonction de rappel n'est pas encore chargée ou le nom est erroné. Essayez :

  1. Confirmez le nom en inspectant data-callback ou la configuration interne.
  2. Attendez que la page soit complètement chargée avant de l'appeler.
  3. Sur les sites minifiés, la fonction peut être affectée à une variable — vérifiez window.SubmitToken dans la console.

Le jeton fonctionne sur la version v2 standard mais échoue sur cette page

Vous êtes probablement confronté à une implémentation de rappel. Suivez les étapes de détection ci-dessus pour confirmer, puis passez à l'invocation de rappel.

ERROR_BAD_TOKEN_OR_PAGEURL

La paire sitekey/pageurl n'est pas valide. Il s'agit d'une erreur API, non liée au rappel par rapport au standard. Réextrait les deux valeurs de la page.

La page comporte plusieurs widgets reCAPTCHA

Chaque widget peut avoir son propre rappel. Inspectez chaque div g-recaptcha ou vérifiez ___grecaptcha_cfg.clients pour toutes les instances enregistrées. Faites correspondre le widget au formulaire que vous ciblez.

ERROR_CAPTCHA_UNSOLVABLE

Le défi n’a pas pu être résolu. Réessayez avec une nouvelle demande. Ce n'est pas spécifique au rappel.

Pour la référence complète de l’erreur, voirErreurs courantes de résolution de reCAPTCHA v2.


Pourquoi CaptchaAI fonctionne pour cela

Facteur Détail
Même appel API Le flux submit/poll est identique au flux standard reCAPTCHA v2 — aucun paramètre supplémentaire n'est nécessaire
Taux de réussite 99,5 %+ pour reCAPTCHA v2 (rappel et standard utilisent le même solveur)
Vitesse de résolution Moins de 60 secondes
Compatibilité des jetons Le jeton renvoyé fonctionne à la fois avec l'injection g-recaptcha-response et l'invocation de rappel
Tarif Plans basés sur des threads à partir de 15 $/month pour des résolutions illimitées

Le jeton renvoyé par CaptchaAI est le même quelle que soit la manière dont le site implémente reCAPTCHA v2. La différence réside entièrement dans votre code côté client : la manière dont vous transmettez le jeton à la page.


Exemple entièrement exécutable

Besoin d'un projet de travail complet avec configuration de l'environnement, interrogation, tentatives et gestion des erreurs ?

Voir l'exemple exécutable complet sur GitHub →


FAQ

Qu'est-ce qu'un rappel reCAPTCHA v2 ?

Un rappel est une fonction JavaScript qu'un site Web enregistre pour recevoir le jeton reCAPTCHA résolu. Au lieu d'écrire le jeton dans le champ masqué g-recaptcha-response, reCAPTCHA appelle directement la fonction. La fonction déclenche généralement la soumission, la validation ou une redirection de page d'un formulaire.

En quoi le rappel est-il différent du reCAPTCHA v2 standard pour l'appel API ?

Ce n'est pas différent du tout. Vous envoyez la même requête method=userrecaptcha avec la même clé de site et la même URL de page. La seule différence réside dans ce que vous faites avec le jeton après l'avoir reçu : vous appelez la fonction de rappel au lieu de définir une valeur de champ.

Comment trouver le nom de la fonction de rappel ?

Trois endroits à vérifier : (1) l'attribut data-callback sur le div reCAPTCHA, (2) la propriété callback dans un appel grecaptcha.render() dans la page JavaScript, (3) l'objet ___grecaptcha_cfg.clients[0] dans la console du navigateur — parcourez l'arborescence pour trouver la propriété callback.

Puis-je utiliser le jeton avec les deux méthodes ?

Le jeton lui-même fonctionne dans les deux sens. Mais si le site attend un rappel, le paramètre g-recaptcha-response sera ignoré. Faites toujours correspondre la méthode d’injection à ce que le site attend.

Ai-je besoin d’un navigateur pour appeler le rappel ?

Oui. Le rappel est une fonction JavaScript dans le contexte de la page. Vous avez besoin de Selenium, Puppeteer, Playwright ou d'un outil similaire pouvant exécuter JavaScript sur la page cible.


Commencez à résoudre le rappel reCAPTCHA v2

  1. Obtenez votre clé APIcaptchaai.com/api.php
  2. Détectez le nom de rappel — vérifiez data-callback, grecaptcha.render() ou la configuration interne
  3. Copiez le code Python ou Node.js ci-dessus — remplacez les espaces réservés par votre clé, votre clé de site, votre URL de page et votre nom de rappel
  4. Exécutez-le — le jeton arrive en moins de 60 secondes, le rappel se déclenche et la page traite le résultat
  5. Coincé ? Commencez parErreurs courantes de résolution de reCAPTCHA v2ou lisez l'intégralitéDocumentation sur l'API CaptchaAI

Articles connexes

Les commentaires sont désactivés pour cet article.