Combien de temps un jeton Cloudflare Turnstile reste-t-il valable ? Environ 300 secondes après sa génération.
Largement assez pour un formulaire simple, mais pas pour un parcours en plusieurs étapes ou un traitement par lots. Passé ce délai, le site rejette le jeton même si votre script marchait en local. Voici comment repérer le problème et corriger le timing.
En bref :
- Le jeton Turnstile vit ~300 secondes, chronométrées par Cloudflare.
- Formulaires multi-étapes et traitement par lots sont les causes les plus fréquentes d’expiration.
- La correction tient en une règle : résoudre juste à temps, jamais à l’avance.
Combien de temps un jeton Turnstile reste-t-il valable ?
Les jetons Turnstile expirent environ 300 secondes (5 minutes) après leur création — plus généreux que d’autres types, mais les conditions de course apparaissent quand même dans les workflows à plusieurs étapes. Pour comparer :
- reCAPTCHA v2/v3 : ~120 secondes
- Cloudflare Turnstile : ~300 secondes
- hCaptcha : ~120 secondes
Le chronomètre démarre quand Cloudflare génère le jeton, pas quand CaptchaAI vous le renvoie. C’est la confusion la plus fréquente derrière les échecs « aléatoires » en production.
La fenêtre de tir entre résolution et soumission du jeton
Un exemple concret, minute par minute :
Time 0:00 — You submit a Turnstile task to CaptchaAI
Time 0:15 — CaptchaAI begins solving
Time 0:20 — Token is generated (timer starts here)
Time 0:25 — CaptchaAI returns token to you
Time 0:25+ — Your code processes the token
Time ??? — Your code submits the token to the site
L’horloge tourne dès 0:20. Vous avez ~5 minutes 20 pour soumettre — confortable sur le papier, moins en vrai parcours utilisateur :
Time 0:20 — Token generated
Time 0:25 — Received by your code
Time 0:30 — Fill form fields
Time 0:35 — Navigate to next page
Time 1:00 — Handle additional dialogs
Time 2:00 — Wait for page load
Time 4:00 — Network latency spike
Time 5:30 — Submit token → EXPIRED
Sur un worker OVHcloud ou en région AWS eu-west-3 (Paris), un pic de latence suffit à transformer cette marge en soumission ratée — mesurez l’âge réel du jeton, pas le temps de résolution annoncé.
Où les conditions de course se cachent le plus souvent
1. Formulaires en plusieurs étapes
Les parcours à plusieurs pages sont les premiers concernés :
Step 1: Fill personal info → Step 2: Fill address →
Step 3: Solve CAPTCHA → Step 4: Review → Step 5: Submit
Si le CAPTCHA est résolu à l’étape 3 mais soumis à l’étape 5, le délai dépasse facilement les 5 minutes.
2. Files d’attente de traitement par lots
Résoudre tous les jetons à l’avance puis les consommer un par un : l’erreur classique des scripts à fort volume :
# DON'T: Solve all tokens first, then use them
tokens = []
for url in urls:
tokens.append(solve_turnstile(url)) # Tokens age while waiting
for url, token in zip(urls, tokens):
submit_form(url, token) # Early tokens may be expired
3. Nouvelles tentatives avec un ancien jeton
Réutiliser un jeton après un échec de soumission casse deux fois :
- Le jeton a peut-être expiré entre-temps.
- Ou il est déjà consommé côté Cloudflare, même si la première soumission a échoué.
token = solve_turnstile(site_key, page_url)
for attempt in range(3):
result = submit_form(page_url, token)
if result.ok:
break
# BUG: Retrying with the same token — it may be expired OR already consumed
Trois stratégies pour ne jamais laisser un jeton expirer
Trois leviers, du plus simple au plus robuste :
- Résoudre juste à temps.
- Suivre l’âge du jeton.
- Repartir de zéro à chaque tentative.
Stratégie 1 : résoudre juste à temps
Demandez le jeton seulement quand vous êtes prêt à le soumettre — remplissez le formulaire d’abord, résolvez le CAPTCHA en dernier :
import requests
import time
def solve_turnstile(site_key, page_url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": "YOUR_API_KEY",
"method": "turnstile",
"sitekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("Solve timed out")
# Complete all form steps FIRST
fill_personal_info()
fill_address()
navigate_to_review()
# THEN solve and submit immediately
token = solve_turnstile(site_key, page_url)
submit_form(token) # Submit within seconds of receiving the token
Stratégie 2 : suivre l’âge du jeton
Encapsulez le jeton dans un objet qui connaît son âge, avec une marge de sécurité sous les 300 secondes réelles :
import time
class TimedToken:
def __init__(self, token, created_at=None):
self.token = token
self.created_at = created_at or time.time()
self.max_age = 270 # 4.5 min — safety margin from 5 min limit
@property
def is_valid(self):
return (time.time() - self.created_at) < self.max_age
@property
def remaining_seconds(self):
return max(0, self.max_age - (time.time() - self.created_at))
# Usage
timed_token = TimedToken(solve_turnstile(site_key, page_url))
# Check before using
if timed_token.is_valid:
submit_form(timed_token.token)
else:
# Solve a fresh token
timed_token = TimedToken(solve_turnstile(site_key, page_url))
submit_form(timed_token.token)
Stratégie 3 : jeton neuf à chaque nouvelle tentative (JavaScript)
Ne réessayez jamais avec le même jeton. Résolvez-en un nouveau à chaque tentative :
async function submitWithFreshToken(siteKey, pageUrl, formData) {
const maxRetries = 3;
for (let attempt = 0; attempt < maxRetries; attempt++) {
// Always solve a fresh token for each attempt
const token = await solveTurnstile(siteKey, pageUrl);
const response = await fetch(pageUrl, {
method: 'POST',
body: JSON.stringify({ ...formData, 'cf-turnstile-response': token }),
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) return await response.json();
console.log(`Attempt ${attempt + 1} failed, solving fresh token...`);
}
throw new Error('All attempts failed');
}
Repérer un jeton expiré avant qu’il casse votre parcours
Le site ne dit presque jamais « jeton expiré ». Surveillez plutôt ces signaux :
- HTTP 403 après soumission → jeton invalide ou expiré.
- Retour à la page du formulaire → vérification échouée.
- Message « Échec de la vérification » → souvent une expiration.
- Page de défi qui réapparaît → jeton rejeté.
Astuce : loggez l’âge du jeton avant d’ouvrir un ticket — neuf fois sur dix, il dépasse déjà 270 s.
Journaliser pour diagnostiquer plus vite
Consignez l’âge du jeton à chaque soumission — le moyen le plus rapide de confirmer l’expiration :
import time
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("turnstile")
token_received_at = time.time()
token = solve_turnstile(site_key, page_url)
logger.info(f"Token received, length: {len(token)}")
# ... workflow steps ...
submit_time = time.time()
age = submit_time - token_received_at
logger.info(f"Submitting token, age: {age:.1f}s")
if age > 270:
logger.warning(f"Token may be expired (age: {age:.1f}s > 270s safety limit)")
Rafraîchissement automatique : navigateur vs API
Dans un flux navigateur, les widgets Turnstile actualisent automatiquement le jeton avant expiration. Le callback expired-callback se déclenche quand un jeton expire :
turnstile.render('#captcha', {
sitekey: '0x4AAAA...',
callback: (token) => {
console.log('New token:', token);
},
'expired-callback': () => {
console.log('Token expired — widget will auto-refresh');
}
});
En API pure, sans navigateur, il n’y a aucun rafraîchissement automatique : la fraîcheur du jeton est entièrement sous votre responsabilité.
Tableau de dépannage express
| Problème | Cause | Correctif |
|---|---|---|
| OK en test, échoue en production | Flux prod plus lent | Résoudre juste à temps |
| 1er envoi OK, échecs ensuite | Jeton déjà consommé | Nouveau jeton par tentative |
| Échecs sur formulaires longs | Expiration en cours de flux | Résoudre en dernière étape |
| Batch peu fiable | Jetons expirés avant usage | Résoudre à la demande |
FAQ
Peut-on prolonger la validité d’un jeton Turnstile ?
Non. L’expiration est fixée par Cloudflare, pas configurable. Résolvez un nouveau jeton quand l’ancien approche de sa limite.
Le compteur des 300 secondes démarre-t-il à la réception du jeton ou à sa génération ?
À sa génération, côté Cloudflare — pas quand CaptchaAI vous le renvoie. D’où la marge de 270 secondes recommandée plus haut.
Le rafraîchissement automatique du widget fonctionne-t-il aussi en API pure ?
Non. expired-callback n’existe que pour les widgets navigateur. En API (Python, Node.js, headless), suivez vous-même l’âge du jeton.
Faut-il résoudre les jetons à l’avance pour gagner du temps ?
Seulement si le workflow les consomme en quelques minutes. Pour du batch, résolvez à la demande — cause la plus fréquente d’échecs en file d’attente.
Articles connexes
- Cloudflare Challenge face à la détection Turnstile
- GeeTest et Cloudflare Turnstile : quelles différences
- Corriger une erreur 403 après un jeton Turnstile
Prochaines étapes
Récupérez votre clé API CaptchaAI et passez à une résolution juste à temps.