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 :
- Erreur à l'envoi — votre soumission à l'API est rejetée avant même la résolution.
- Erreur à l'interrogation — le polling échoue, expire, ou renvoie un code inattendu.
- 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
pageurlest 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
actionmanque 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=1dans vos requêtes d'interrogation. La réponse JSON peut renvoyer leuser_agentdu solveur, dont certaines pages protégées par Cloudflare ont besoin pour valider le token. Sansjson=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 Turnstileg-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 :
- Vérifiez le sitekey — extrayez-le de
data-sitekeyou deturnstile.render(). - Vérifiez le pageurl — utilisez l'URL exacte, protocole et chemin compris.
- Contrôlez le chemin du token — la page attend-elle
cf-turnstile-response,g-recaptcha-response, ou un callback ? - Conservez
json=1— gardez les réponses JSON lors de l'interrogation des résultats Turnstile. - 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.