Troubleshooting

Erreurs Cloudflare Turnstile et dépannage

Quand un token Cloudflare Turnstile est refusé, le solveur est rarement en cause : dans la quasi-totalité des cas, l'erreur vient de trois paramètres que votre code envoie ou de la façon dont vous réinjectez le token dans la page. Un sitekey capturé sur le mauvais widget, un pageurl qui ne correspond pas exactement à la page, ou un token appliqué dans le mauvais champ — voilà le trio responsable de la majorité des échecs.

Pour dépanner efficacement, commencez par situer la panne dans l'une des trois étapes du cycle de résolution :

  1. Erreur à l'envoi — votre soumission à l'API est rejetée avant même la résolution.
  2. Erreur à l'interrogation — le polling échoue, expire, ou renvoie un code inattendu.
  3. Rejet par la page cible — l'API renvoie un token valide, mais la page le refuse quand même.

CaptchaAI résout Turnstile avec un taux de réussite élevé et constant en moins de 10 secondes. Si votre intégration casse, le problème se trouve donc presque toujours dans les paramètres envoyés ou dans le chemin d'application du token — pas dans la résolution elle-même.


Turnstile ou Cloudflare Challenge : lequel avez-vous en face ?

Avant tout dépannage, confirmez le produit auquel vous avez affaire : un widget Turnstile intégré et un défi Cloudflare pleine page ne se résolvent pas de la même manière, et les confondre est l'erreur la plus fréquente en amont.

Signal Turnstile Cloudflare Challenge
Ce que vous voyez Widget intégré à la page (case à cocher ou invisible) Écran de vérification Cloudflare pleine page
Ce que renvoie CaptchaAI Un token à injecter dans le formulaire Un cookie cf_clearance
Méthode API turnstile cloudflare_challenge
Proxy requis ? Facultatif Oui (obligatoire)

Face à un défi Cloudflare pleine page — et non à un widget intégré — vous avez besoin du solveur Cloudflare Challenge, qui renvoie un cookie cf_clearance et exige un proxy. Le reste de ce guide porte sur le widget Turnstile.


Trois particularités de Turnstile à connaître avant de déboguer

Avant d'entrer dans les codes d'erreur, gardez en tête ce qui distingue Turnstile des autres types de CAPTCHA. Ces trois points expliquent la plupart des échecs difficiles à reproduire.

L'URL exacte de la page pèse plus lourd

Les tokens Turnstile sont étroitement liés au contexte de la page. Sur les pages de défi Cloudflare (l'écran de vérification pleine page), un pageurl légèrement différent — un simple segment de chemin ou un paramètre de requête manquant — suffit à faire rejeter le token. Prenez l'URL au caractère près.

Deux chemins pour appliquer le token

Le token renvoyé s'applique de deux façons, et vous tromper de chemin fait échouer la soumission en silence :

Méthode Quand l'utiliser
Champ caché — écrire dans cf-turnstile-response (et parfois g-recaptcha-response) La page utilise un formulaire standard avec une entrée masquée
Fonction de callback — appeler la fonction définie dans turnstile.render() ou data-callback La page valide par code au lieu de soumettre un formulaire

Les tokens sont à usage unique

Un token Turnstile ne se vérifie qu'une seule fois. Si votre automatisation le soumet deux fois par accident, ou en cas de condition de concurrence, la seconde tentative échoue systématiquement.


Tableau de diagnostic rapide

Repérez votre symptôme dans ce tableau, puis rendez-vous à la section détaillée correspondante pour le correctif complet.

Erreur / symptôme Étape Cause probable Correctif
ERROR_WRONG_USER_KEY Envoi Clé API mal formée Vérifier la clé de 32 caractères
ERROR_KEY_DOES_NOT_EXIST Envoi Clé invalide Contrôler le tableau de bord
ERROR_ZERO_BALANCE Envoi Aucun thread libre Attendre ou changer de forfait
ERROR_PAGEURL Envoi pageurl manquant Ajouter l'URL complète
ERROR_BAD_PARAMETERS Envoi Sitekey, méthode ou pageurl manquant Vérifier tous les champs obligatoires
CAPCHA_NOT_READY Interrogation Résolution en cours Attendre 5 secondes, relancer
ERROR_WRONG_ID_FORMAT Interrogation ID non numérique Reprendre l'ID exact de in.php
ERROR_WRONG_CAPTCHA_ID Interrogation ID invalide Vérifier l'ID d'envoi
ERROR_EMPTY_ACTION Interrogation action=get manquant Ajouter le paramètre action
Token rejeté par la page Validation Mauvais champ, callback non déclenché, mauvaise URL Vérifier le champ, appeler le callback, contrôler le pageurl exact
Deuxième résolution en échec Validation Token rejoué Demander un token neuf par soumission

Erreurs à l'envoi de la tâche (in.php)

Ces erreurs surviennent lors de la soumission de la tâche à https://ocr.captchaai.com/in.php.

ERROR_WRONG_USER_KEY

  • Cause : le format de la clé API est incorrect (elle doit comporter 32 caractères).
  • Correctif : vérifiez la clé depuis votre page API CaptchaAI.

ERROR_KEY_DOES_NOT_EXIST

  • Cause : la clé est bien formée mais n'est rattachée à aucun compte actif.
  • Correctif : contrôlez votre tableau de bord. Assurez-vous que le compte est actif et que la clé est la bonne.

ERROR_ZERO_BALANCE

  • Cause : aucun thread libre sur votre forfait.
  • Correctif : attendez qu'un thread se libère, réduisez la simultanéité, ou passez à un forfait supérieur. Le plus petit forfait, BASIC ($15/mois, 5 threads), donne déjà cinq résolutions en parallèle.

ERROR_PAGEURL

  • Cause : le paramètre pageurl est absent.
  • Correctif : ajoutez l'URL complète — protocole, domaine et chemin :
pageurl=https://example.com/login

ERROR_BAD_PARAMETERS

Cause : des paramètres obligatoires sont absents ou mal formés. Pour Turnstile, les paramètres requis sont :

Paramètre Type Obligatoire Description
key Chaîne Oui Votre clé API CaptchaAI
method Chaîne Oui Doit valoir turnstile
sitekey Chaîne Oui Le sitekey du widget Turnstile
pageurl Chaîne Oui L'URL complète de la page

Facultatifs mais utiles :

Paramètre Type Description
action Chaîne Valeur de data-action ou du paramètre action de turnstile.render()
proxy Chaîne Format : login:password@IP:PORT
proxytype Chaîne HTTP, HTTPS, SOCKS4, SOCKS5

Correctif : vérifiez que tous les champs obligatoires sont présents et correctement typés.

Réponses HTML ou codes 500/502

  • Cause : erreur transitoire côté serveur.
  • Correctif : patientez 5 à 10 secondes, puis relancez la requête.

Où récupérer le sitekey Turnstile

Le sitekey est de loin le paramètre le plus souvent erroné. Voici trois manières de le récupérer, de la plus simple à la plus avancée.

Option 1 — l'attribut data-sitekey :

<div class="cf-turnstile" data-sitekey="0x4AAAAAAAB1example"></div>

Option 2 — un appel turnstile.render() :

turnstile.render('#captcha-container', {
  sitekey: '0x4AAAAAAAB1example',
  callback: function(token) {
    document.getElementById('cf-turnstile-response').value = token;
  }
});

Option 3 — intercepter l'appel de rendu (avancé) :

Si le sitekey est chargé dynamiquement, redéfinissez turnstile.render avant l'initialisation du widget pour capturer les paramètres au vol :

// Inject this before the Turnstile script loads
const originalRender = window.turnstile.render;
window.turnstile.render = function(container, params) {
  console.log('Sitekey:', params.sitekey);
  console.log('Action:', params.action);
  return originalRender.call(this, container, params);
};

Erreurs à l'interrogation du résultat (res.php)

Ces erreurs surviennent lors du polling de https://ocr.captchaai.com/res.php.

CAPCHA_NOT_READY

Ce n'est pas une erreur. La résolution est encore en cours. Chez CaptchaAI, une résolution Turnstile prend en général moins de 10 secondes.

  • Correctif : attendez 5 secondes et interrogez à nouveau le résultat.

ERROR_WRONG_ID_FORMAT

  • Cause : l'identifiant du CAPTCHA contient des caractères non numériques.
  • Correctif : utilisez l'ID exact renvoyé par in.php, sans le modifier.

ERROR_WRONG_CAPTCHA_ID

  • Cause : l'identifiant ne correspond à aucune tâche soumise.
  • Correctif : vérifiez que vous interrogez bien l'ID issu de la réponse d'envoi.

ERROR_EMPTY_ACTION

  • Cause : le paramètre action manque dans votre requête d'interrogation.
  • Correctif : incluez toujours action=get :
https://ocr.captchaai.com/res.php?key=YOUR_KEY&action=get&id=CAPTCHA_ID&json=1

À noter : pour Turnstile, conservez json=1 dans vos requêtes d'interrogation. La réponse JSON peut renvoyer le user_agent du solveur, dont certaines pages protégées par Cloudflare ont besoin pour valider le token. Sans json=1, l'endpoint répond en texte brut (OK|<token>), sans cette information.

ERROR_CAPTCHA_UNSOLVABLE

  • Cause : la résolution a échoué — sitekey probablement incorrect, ou configuration de page non prise en charge.
  • Correctif : vérifiez le sitekey, renvoyez une nouvelle tâche et réessayez. Si l'erreur persiste sur la même page, capturez à nouveau le sitekey depuis DevTools plutôt que de rejouer l'ancienne valeur, et espacez vos tentatives avec un backoff progressif pour éviter d'accumuler des échecs.

ERROR_INTERNAL_SERVER_ERROR

  • Cause : incident côté serveur.
  • Correctif : patientez 10 secondes, puis relancez.

Le token est valide, mais la page le refuse

Ce sont les cas les plus délicats : l'API renvoie bien un token, et pourtant la page cible le rejette. Voici les quatre scénarios les plus fréquents et leur correctif.

Cas 1 : token inséré dans le mauvais champ

Symptôme : le formulaire est soumis, mais la page affiche une erreur de validation ou se recharge.

Selon leur intégration, les pages Turnstile attendent le token dans des champs différents :

  • cf-turnstile-response — l'entrée masquée principale de Turnstile
  • g-recaptcha-response — certaines pages l'utilisent comme repli

Correctif : inspectez le formulaire pour repérer les deux champs. En automatisation de navigateur :

# Selenium — inject into both fields for safety
driver.execute_script("""
    var cfField = document.querySelector('[name="cf-turnstile-response"]');
    var gField = document.querySelector('[name="g-recaptcha-response"]');
    if (cfField) cfField.value = arguments[0];
    if (gField) gField.value = arguments[0];
""", token)

Cas 2 : callback non déclenché

  • Symptôme : le token est bien dans le champ, mais le formulaire refuse toujours la soumission.
  • Cause : la page repose sur une fonction de callback à la place (ou en plus) du champ masqué. Ce callback gère une logique supplémentaire : activation du bouton d'envoi, requête AJAX, etc.
  • Correctif : repérez le callback et appelez-le vous-même :
// Check data-callback attribute
const callbackName = document.querySelector('.cf-turnstile').getAttribute('data-callback');
if (callbackName && window[callbackName]) {
  window[callbackName](token);
}

// Or if it was passed in turnstile.render()
// You may need to intercept the render call to capture it

Cas 3 : contexte de page inexact

Symptôme : token rejeté malgré un sitekey correct et une résolution fraîche.

Cause : le pageurl envoyé à l'API ne correspond pas au contexte réel de la page. C'est particulièrement fréquent dans deux situations :

  • Pages de défi Cloudflare — l'URL peut contenir des paramètres de requête ou des segments de chemin déterminants.
  • Applications monopages (SPA) — l'URL affichée peut différer de celle qui a chargé le widget Turnstile.

Correctif : ouvrez l'onglet Réseau de DevTools pour trouver l'URL exacte depuis laquelle le widget se charge, et utilisez-la comme pageurl.

Cas 4 : réutilisation du token

  • Symptôme : la première résolution passe, les suivantes échouent.
  • Cause : les tokens Turnstile sont à usage unique. Une fois vérifié par le serveur de Cloudflare, le token est invalidé.
  • Correctif : demandez une nouvelle résolution à chaque envoi de formulaire. Ne mettez jamais un token en cache pour le rejouer.

Un exemple concret côté QA

Supposons que vous automatisiez les tests QA du tunnel de connexion d'un SaaS francophone hébergé chez OVHcloud, avec Turnstile devant le formulaire. En local, tout passe ; en préproduction, le token est systématiquement refusé. Neuf fois sur dix, la cause est le cas 3 : votre script envoie l'URL affichée (/login), alors que le widget est chargé depuis une route de rendu différente (/auth/challenge?next=/dashboard). L'onglet Réseau tranche la question en quelques secondes. Pensez aussi RGPD : ne journalisez que les métadonnées de diagnostic nécessaires, jamais les identifiants de test.


Python : résolution Turnstile de bout en bout

import time
import requests

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "0x4AAAAAAAB1example"
PAGE_URL = "https://example.com/login"

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


def solve_turnstile(api_key, sitekey, pageurl):
    """Submit a Turnstile challenge and return the solved token."""

    # Submit
    submit_resp = requests.post(
        SUBMIT_URL,
        data={
            "key": api_key,
            "method": "turnstile",
            "sitekey": 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}")

    # Wait before first poll (Turnstile is fast — 10 seconds is usually enough)
    time.sleep(10)

    # 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("Turnstile solve timed out")


# Usage
token = solve_turnstile(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

# Inject into cf-turnstile-response and/or g-recaptcha-response
# Then submit the form

Node.js : résolution Turnstile complète

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "0x4AAAAAAAB1example";
const PAGE_URL = "https://example.com/login";

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 solveTurnstile(apiKey, sitekey, pageurl) {
  // Submit
  const submitResp = await fetch(SUBMIT_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      key: apiKey,
      method: "turnstile",
      sitekey: 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}`);

  // Turnstile is fast — wait 10 seconds before first poll
  await sleep(10_000);

  // 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("Turnstile solve timed out");
}

// Usage
solveTurnstile(API_KEY, SITEKEY, PAGE_URL)
  .then((token) => {
    console.log(`Solved token: ${token.slice(0, 80)}...`);
    // Inject into cf-turnstile-response and/or g-recaptcha-response
  })
  .catch(console.error);

FAQ

Combien de temps prend une résolution Turnstile ?

En général moins de 10 secondes chez CaptchaAI. Tant que le résultat n'est pas prêt, l'API renvoie CAPCHA_NOT_READY : c'est normal, il suffit d'attendre 5 secondes avant chaque nouvelle interrogation.

Pourquoi le token est-il refusé alors que la requête semble correcte ?

Trois causes reviennent presque toujours : un pageurl légèrement inexact (surtout sur les pages de défi Cloudflare), un sitekey capturé sur le mauvais élément, ou un token injecté dans le mauvais champ ou le mauvais chemin de callback. Vérifiez ces trois points dans cet ordre.

Faut-il un proxy pour résoudre Turnstile ?

Pas pour un widget Turnstile autonome : le paramètre proxy y est facultatif. En revanche, sur une page de défi Cloudflare, un proxy (avec proxytype) est recommandé, voire obligatoire selon la protection en place.

Peut-on réutiliser un token Turnstile pour plusieurs soumissions ?

Non. Un token Turnstile est à usage unique : dès que le serveur de Cloudflare l'a vérifié, il est invalidé. Demandez une nouvelle résolution pour chaque envoi de formulaire plutôt que de mettre le token en cache.

CaptchaAI résout-il hCaptcha ou FunCaptcha en plus de Turnstile ?

Non — hCaptcha et FunCaptcha (Arkose Labs) ne sont pas pris en charge. CaptchaAI couvre reCAPTCHA v2/v3, Cloudflare Turnstile et Challenge, GeeTest v3, ainsi que les CAPTCHA image/OCR et en grille.


Remettez votre intégration Turnstile d'aplomb

Si votre intégration Turnstile échoue, déroulez cette checklist dans l'ordre :

  1. Vérifiez le sitekey — extrayez-le de data-sitekey ou de turnstile.render().
  2. Vérifiez le pageurl — utilisez l'URL exacte, protocole et chemin compris.
  3. Contrôlez le chemin du token — la page attend-elle cf-turnstile-response, g-recaptcha-response, ou un callback ?
  4. Conservez json=1 — gardez les réponses JSON lors de l'interrogation des résultats Turnstile.
  5. Ne rejouez jamais un token — demandez une résolution neuve à chaque soumission.

Démarrez avec le solveur Turnstile de CaptchaAI, confrontez vos paramètres à la documentation de l'API, et lisez le fonctionnement de Cloudflare Turnstile si vous avez besoin de comprendre la mécanique du widget.


Articles connexes

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