Troubleshooting

Erreurs et correctifs courants de résolution de reCAPTCHA v2

Un token revient bien de l'API mais votre formulaire ne part pas ? Neuf fois sur dix, l'erreur était présente avant même l'appel : un googlekey copié sur la mauvaise page, un pageurl qui pointe vers la page parente au lieu de l'iframe, ou un token soumis trop tard. Les échecs de reCAPTCHA v2 sont nombreux à nommer mais peu à comprendre, et ils se rangent en trois familles :

  • Côté requête — de mauvais paramètres envoyés à l'API, qui refuse la tâche d'entrée.
  • Côté résultat — un polling mal réglé ou une tâche que le service ne peut pas résoudre.
  • Côté page cible — l'API renvoie un token valide, mais la page l'ignore ou le refuse.

Ce guide traite chaque famille avec le correctif exact, code à l'appui. Si vous débutez avec la résolution de reCAPTCHA v2, commencez plutôt par le tutoriel de résolution via l'API.


Diagnostic express : partez de votre symptôme

Vous avez un message précis sous les yeux ? Repérez-le dans cette table de triage, appliquez le premier réflexe, puis descendez à la section détaillée correspondante.

Symptôme Première chose à vérifier
ERROR_GOOGLEKEY ou ERROR_WRONG_GOOGLEKEY Le sitekey est-il copié tel quel depuis data-sitekey ?
ERROR_PAGEURL Avez-vous transmis l'URL complète de la page ?
ERROR_BAD_TOKEN_OR_PAGEURL Le widget est-il dans une iframe ? Utilisez l'URL de l'iframe.
CAPCHA_NOT_READY pendant plus de 3 minutes Normal pour les défis difficiles. Portez le timeout à 180 s.
ERROR_CAPTCHA_UNSOLVABLE Relancez une tâche. Si ça se répète, revérifiez sitekey + pageurl.
Le token arrive mais la page ne réagit pas Cherchez data-callback et appelez la fonction de callback.
Le token revient mais le formulaire échoue Token peut-être expiré (> 2 min). Soumettez plus vite.
Échecs intermittents Ajoutez une logique de retry avec un nouvel ID de tâche.

Les quatre causes à vérifier en premier

À elles seules, ces quatre erreurs d'entrée expliquent environ 80 % des échecs. Passez-les en revue avant de plonger dans les codes un par un.

Cause Ce qui se passe Symptôme typique
googlekey erroné ou absent Le sitekey est faux, vide ou récupéré sur une autre page. Il provient de l'attribut data-sitekey du widget ou du paramètre k de l'URL d'ancrage. ERROR_GOOGLEKEY, ERROR_WRONG_GOOGLEKEY
pageurl qui ne correspond pas L'URL transmise n'est pas celle où le widget se charge. Widget en iframe : c'est l'URL de l'iframe qu'il faut, pas celle de la page parente. ERROR_PAGEURL, ERROR_BAD_TOKEN_OR_PAGEURL
Callback jamais exécuté Vous remplissez le champ masqué g-recaptcha-response, mais la page attend l'appel d'une fonction de callback JavaScript. Le formulaire ne se soumet jamais
Token expiré ou réutilisé Les tokens sont à usage unique et expirent après environ 2 minutes ; trop de délai ou une réutilisation et la page refuse en silence. Rejet silencieux côté page

Pour le premier point, voici où récupérer le bon sitekey :

# Look for data-sitekey in the page HTML
# <div class="g-recaptcha" data-sitekey="6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-"></div>

# Or find it in the anchor URL
# https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-

Erreurs côté requête : ce que in.php refuse

Ces erreurs remontent au moment où vous soumettez la tâche à https://ocr.captchaai.com/in.php.

Code d'erreur Cause Correctif
ERROR_WRONG_USER_KEY Format de clé API invalide (pas 32 caractères) Vérifiez votre clé API sur captchaai.com/api.php
ERROR_KEY_DOES_NOT_EXIST La clé API n'existe pas dans le système Confirmez que la clé est copiée en entier, sans espace parasite
ERROR_ZERO_BALANCE Le solde du compte est à zéro Rechargez le compte ou vérifiez le nombre de threads actifs
ERROR_PAGEURL Le paramètre pageurl est absent Ajoutez l'URL complète où apparaît le widget reCAPTCHA
ERROR_GOOGLEKEY googlekey est mal formé ou vide Extrayez le bon sitekey depuis la page
ERROR_WRONG_GOOGLEKEY Le paramètre googlekey est entièrement absent Ajoutez googlekey à votre requête API
ERROR_BAD_TOKEN_OR_PAGEURL Le couple googlekey + pageurl est invalide Le widget est-il dans une iframe ? Utilisez l'URL de l'iframe
ERROR_BAD_PARAMETERS Paramètres requis absents ou mal formés Consultez la documentation de l'API pour les champs obligatoires

Exemple — une requête robuste qui intercepte chaque erreur d'entrée :

import requests

def submit_recaptcha_v2(api_key, sitekey, page_url):
    response = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": 1
    })

    data = response.json()

    if data.get("status") == 1:
        return data["request"]  # task ID

    error = data.get("request", "UNKNOWN_ERROR")

    if error == "ERROR_WRONG_USER_KEY":
        raise ValueError("API key format is invalid. Must be 32 characters.")
    elif error == "ERROR_ZERO_BALANCE":
        raise RuntimeError("Account balance is zero. Top up at captchaai.com")
    elif error == "ERROR_PAGEURL":
        raise ValueError("pageurl parameter is missing from request")
    elif error in ("ERROR_GOOGLEKEY", "ERROR_WRONG_GOOGLEKEY"):
        raise ValueError(f"Invalid sitekey. Verify the data-sitekey value on the page.")
    elif error == "ERROR_BAD_TOKEN_OR_PAGEURL":
        raise ValueError("Sitekey/pageurl mismatch. Check if widget is in an iframe.")
    else:
        raise RuntimeError(f"API error: {error}")

# Usage
task_id = submit_recaptcha_v2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://example.com/login")
print(f"Task submitted: {task_id}")
async function submitRecaptchaV2(apiKey, sitekey, pageUrl) {
  const params = new URLSearchParams({
    key: apiKey,
    method: "userrecaptcha",
    googlekey: sitekey,
    pageurl: pageUrl,
    json: 1,
  });

  const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
  const data = await res.json();

  if (data.status === 1) return data.request;

  const error = data.request || "UNKNOWN_ERROR";
  const fixes = {
    ERROR_WRONG_USER_KEY: "API key format is invalid. Must be 32 characters.",
    ERROR_ZERO_BALANCE: "Account balance is zero. Top up at captchaai.com",
    ERROR_PAGEURL: "pageurl parameter is missing from request",
    ERROR_GOOGLEKEY: "Invalid sitekey. Check the data-sitekey attribute.",
    ERROR_BAD_TOKEN_OR_PAGEURL: "Sitekey/pageurl mismatch. Check iframe context.",
  };

  throw new Error(fixes[error] || `API error: ${error}`);
}

// Usage
const taskId = await submitRecaptchaV2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://example.com/login");
console.log(`Task submitted: ${taskId}`);

Erreurs côté résultat : le polling sur res.php

Ces erreurs surviennent pendant que vous interrogez https://ocr.captchaai.com/res.php pour récupérer le résultat.

Code d'erreur Cause Correctif
CAPCHA_NOT_READY La résolution est encore en cours Attendez 5 secondes et interrogez à nouveau. C'est normal.
ERROR_CAPTCHA_UNSOLVABLE Le CAPTCHA n'a pas pu être résolu Soumettez une nouvelle tâche avec des paramètres neufs
ERROR_WRONG_ID_FORMAT Le format de l'ID de tâche est invalide Vérifiez l'ID renvoyé par in.php
ERROR_WRONG_CAPTCHA_ID L'ID de tâche n'existe pas Assurez-vous d'avoir conservé le bon ID de tâche
ERROR_EMPTY_ACTION Le paramètre action=get est absent Ajoutez action=get à votre requête de polling

Exemple — un polling qui distingue l'attente normale d'une vraie erreur :

import time
import requests

def poll_result(api_key, task_id, timeout=120):
    start = time.time()

    while time.time() - start < timeout:
        time.sleep(5)

        response = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key,
            "action": "get",
            "id": task_id,
            "json": 1
        })

        data = response.json()

        if data.get("status") == 1:
            return data["request"]  # solved token

        error = data.get("request", "")

        if error == "CAPCHA_NOT_READY":
            continue  # normal — keep waiting
        elif error == "ERROR_CAPTCHA_UNSOLVABLE":
            raise RuntimeError("CAPTCHA unsolvable. Submit a new task with fresh params.")
        elif error in ("ERROR_WRONG_ID_FORMAT", "ERROR_WRONG_CAPTCHA_ID"):
            raise ValueError(f"Invalid task ID: {task_id}")
        else:
            raise RuntimeError(f"Polling error: {error}")

    raise TimeoutError(f"Solve timed out after {timeout}s")

# Usage
token = poll_result("YOUR_API_KEY", task_id)
print(f"Token: {token[:50]}...")
async function pollResult(apiKey, taskId, timeout = 120000) {
  const start = Date.now();

  while (Date.now() - start < timeout) {
    await new Promise((r) => setTimeout(r, 5000));

    const params = new URLSearchParams({
      key: apiKey,
      action: "get",
      id: taskId,
      json: 1,
    });

    const res = await fetch(`https://ocr.captchaai.com/res.php?${params}`);
    const data = await res.json();

    if (data.status === 1) return data.request;

    if (data.request === "CAPCHA_NOT_READY") continue;
    if (data.request === "ERROR_CAPTCHA_UNSOLVABLE")
      throw new Error("Unsolvable. Submit a new task.");
    throw new Error(`Polling error: ${data.request}`);
  }

  throw new Error(`Solve timed out after ${timeout / 1000}s`);
}

Côté rythme d'interrogation, inutile de marteler res.php :

  • Laissez 5 secondes entre deux tentatives : plus rapide ne raccourcit pas la résolution.
  • Fixez un délai d'expiration autour de 120 s, porté à 180 s pour les défis difficiles.
  • Comptez 15 à 60 secondes de temps de résolution habituel pour reCAPTCHA v2.

Le token est valide, mais la page le rejette

L'API a renvoyé un token correct et pourtant le site cible le refuse. Ce sont les pannes les plus retorses à déboguer : de son côté, l'API considère que tout s'est bien passé.

Le token est injecté dans le mauvais champ

Une page lit le token de trois façons : dans le textarea masqué g-recaptcha-response, via grecaptcha.getResponse(), ou en déclenchant un callback. Choisissez la mauvaise voie et la soumission échoue sans le moindre message. Inspectez la page, puis appliquez la méthode attendue :

# Method 1: Hidden field injection
driver.execute_script(
    'document.getElementById("g-recaptcha-response").innerHTML = arguments[0];',
    token
)

# Method 2: Callback execution (check data-callback attribute)
driver.execute_script(f'onCaptchaSuccess("{token}");')

# Method 3: Direct form field + submit
driver.execute_script(
    'document.querySelector("[name=g-recaptcha-response]").value = arguments[0];',
    token
)
driver.find_element("css selector", "form").submit()

Le callback n'est jamais appelé

Si le widget porte un data-callback="onSuccess" ou passe par grecaptcha.render() avec une propriété callback, remplir le champ masqué ne suffit pas : rien ne se déclenche. Récupérez le nom du callback et invoquez-le vous-même.

// In browser console or Puppeteer/Playwright
// Check for data-callback
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
  window[callbackName](token);
}

Le token a expiré

Au-delà de 2 minutes environ entre la réception du token et l'envoi du formulaire, Google le refuse — un cas fréquent dans les pipelines d'automatisation lents.

Un worker déployé sur Scaleway à Paris reçoit le token, enchaîne trois requêtes intermédiaires (récupération d'un panier, calcul de frais, appel d'une API tierce), puis soumet le formulaire deux minutes et demie plus tard : le token est déjà mort. La latence réseau depuis une région européenne n'y change rien, le compteur des 2 minutes court côté Google. Correctif : envoyez le formulaire immédiatement après réception du token et déclenchez la résolution au plus près de l'étape de soumission, jamais en début de parcours.

Le widget vit dans une iframe

Quand le reCAPTCHA se charge dans une iframe issue d'un autre domaine, le pageurl à transmettre est l'URL source de l'iframe, pas celle de la page parente ; l'erreur ERROR_BAD_TOKEN_OR_PAGEURL signale presque toujours ce cas. Inspectez la page, repérez l'iframe qui contient le reCAPTCHA et utilisez l'URL de son attribut src comme pageurl.


FAQ

Comment savoir si le problème vient de la requête ou de la page ?

Regardez d'où sort l'erreur. Si in.php ou res.php renvoie un code ERROR_*, le problème est côté requête ou résolution : vérifiez d'abord googlekey, pageurl et le format de l'ID de tâche. Si l'API vous rend un token valide mais que le formulaire ne part pas, le problème est côté page : callback, mauvais champ d'injection ou token expiré.

Que signifie l'erreur CAPCHA_NOT_READY ?

Que le CAPTCHA est encore en cours de résolution. Ce n'est pas une erreur, seulement un état d'attente. Patientez 5 secondes puis interrogez de nouveau res.php. Les temps de résolution typiques de reCAPTCHA v2 vont de 15 à 60 secondes.

Combien de temps un token reCAPTCHA v2 reste-t-il valide ?

Environ 2 minutes, et pour un seul usage. Passé ce délai, ou si le token a déjà été soumis une fois, la page cible le refuse. Résolvez le CAPTCHA au plus près de l'envoi du formulaire plutôt qu'en début de parcours pour éviter que le token n'expire dans un pipeline lent.

reCAPTCHA v2 Enterprise génère-t-il les mêmes erreurs ?

Les codes d'erreur sont les mêmes, mais reCAPTCHA v2 Enterprise attend des paramètres différents (notamment une action et parfois un enterprise=1). Si ERROR_CAPTCHA_UNSOLVABLE revient de façon répétée sur une page qui semble correcte, vérifiez que vous traitez bien du reCAPTCHA v2 standard et non de la variante Enterprise.

Faut-il consigner les codes d'erreur, et comment rester conforme au RGPD ?

Oui : journaliser le code d'erreur, l'horodatage et l'ID de tâche accélère nettement le diagnostic. Restez sobre côté données personnelles pour respecter vos obligations RGPD — ne stockez ni le token complet, ni les URL cibles contenant des identifiants de session. Le code d'erreur et le sitekey suffisent à reproduire un incident.


Remettez votre workflow reCAPTCHA v2 d'aplomb

  1. Vérifiez vos entrées — extrayez googlekey depuis data-sitekey et utilisez l'URL exacte de la page (attention aux iframes).
  2. Confirmez la méthode d'injection — champ masqué, callback, ou les deux : la page décide, pas vous.
  3. Soumettez sans attendre — consommez le token dans les 2 minutes qui suivent sa réception.
  4. Ajoutez la gestion des erreurs — reprenez les exemples ci-dessus pour intercepter et traiter chaque type d'erreur.

Lancez-vous avec le solveur CaptchaAI et récupérez votre clé API sur captchaai.com/api.php.


Guides associés

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