Comparisons

Défi géré Cloudflare vs défi interactif

Le statut HTTP renvoyé par la page vous dit presque tout : un 503 pointe vers un Managed Challenge, un 403 vers un Interactive Challenge. Ce sont les deux actions de défi que Cloudflare expose dans les règles WAF, et elles se pilotent différemment. Le Managed Challenge est l'option moderne et adaptative — Cloudflare choisit la difficulté visiteur par visiteur, et environ 90 % des requêtes légitimes passent sans rien afficher. L'Interactive Challenge est l'option héritée : il montre toujours un CAPTCHA visible. Savoir lequel vous avez en face détermine la méthode CaptchaAI à appeler — turnstile ou cloudflare_challenge.

En pratique, deux réflexes suffisent pour démarrer :

  • 503 → Managed Challenge → méthode turnstile (ou cloudflare_challenge quand aucun widget n'apparaît).
  • 403 → Interactive Challenge → méthode turnstile.

Comparaison rapide : Managed vs Interactive Challenge

Caractéristique Managed Challenge Interactive Challenge
Année d'apparition 2021 Hérité (avant 2021)
Adaptatif ? Oui — Cloudflare décide visiteur par visiteur Non — toujours interactif
Passage invisible possible ? Oui (~90 % des visiteurs passent sans widget) Non — affiche toujours un CAPTCHA
Types de défis mobilisés Invisible → Turnstile → défi JS CAPTCHA toujours visible
Recommandé par Cloudflare ? Oui — défaut des nouvelles règles Non — conservé pour la rétrocompatibilité
Friction utilisateur Faible — la plupart ne voient rien Élevée — interaction systématique
Statut HTTP 503 403
Méthode CaptchaAI turnstile ou cloudflare_challenge turnstile

Reconnaître le défi au premier coup d'œil

Quelques signaux permettent de deviner le type avant même de lire le HTML.

Signal observé Plutôt Managed Challenge Plutôt Interactive Challenge
Expérience utilisateur Une partie des visiteurs passe sans voir de widget Chaque visiteur voit un défi explicite
Type de page Page de vérification adaptative ou widget Turnstile contextuel Page de défi pleine page avec interaction obligatoire
Code HTTP Souvent 503 ou flux intermédiaire Souvent 403 avec défi visible
Logique à coder Gérer parfois un passage invisible ou un défi non interactif Résoudre presque toujours un widget visible

Managed Challenge : le défi adaptatif moderne

Le Managed Challenge est l'action de défi que Cloudflare recommande. Plutôt que d'imposer une épreuve à tout le monde, il évalue chaque visiteur et présente le défi le moins gênant possible — souvent aucun.

Le flux de décision de Cloudflare

Cloudflare combine plusieurs signaux avant de choisir le niveau de défi :

WAF rule triggers Managed Challenge
    ↓
Cloudflare evaluates visitor signals:
  ├─ Browser fingerprint quality
  ├─ IP reputation score
  ├─ TLS fingerprint (JA3/JA4)
  ├─ Request history
  ├─ Behavioral signals
  └─ Device capabilities
    ↓
Risk assessment → Challenge level selected:
  ├─ LOW risk → Invisible pass (no visible UI)
  ├─ MEDIUM risk → Non-interactive Turnstile (background PoW)
  ├─ HIGH risk → Interactive Turnstile (checkbox/widget)
  └─ VERY HIGH risk → JavaScript challenge page (5s wait)
    ↓
Challenge completed
    ↓
cf_clearance cookie issued

Ce que voient réellement les visiteurs

La difficulté suit le profil de risque estimé ; dans la grande majorité des cas, rien ne s'affiche.

  • Navigateur classique, bonne IP : rien du tout, passage invisible (~90 % des visiteurs).
  • Nouveau navigateur, IP neutre : un bref indicateur de chargement (~5 %).
  • Signaux suspects : une case à cocher Turnstile (~4 %).
  • Signaux à haut risque : la page « Checking your browser… » (~1 %).

À quoi ressemble le HTML

Quand il devient visible, le défi s'appuie sur la plateforme de Cloudflare :

<!-- Managed Challenge page (when visible) -->
<body>
    <div id="challenge-stage">
        <div id="challenge-body-text">
            Verifying you are human. This may take a few seconds.
        </div>

        <!-- Turnstile widget (when rendered) -->
        <div class="cf-turnstile"
             data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg">
        </div>
    </div>

    <!-- Challenge platform script -->
    <script src="/cdn-cgi/challenge-platform/h/g/orchestrate/managed/v1?ray=...">
    </script>
</body>

Interactive Challenge : le défi hérité toujours visible

L'Interactive Challenge montre toujours un CAPTCHA visible : aucun passage invisible, chaque visiteur doit le résoudre pour continuer.

Le déroulé côté visiteur

WAF rule triggers Interactive Challenge
    ↓
Full-page CAPTCHA served (HTTP 403)
    ↓
Visitor must interact with CAPTCHA widget
    ↓
CAPTCHA solved
    ↓
cf_clearance cookie issued

Le HTML de la page

Chaque visiteur reçoit une page complète avec un widget de type Turnstile :

<!-- Interactive Challenge page -->
<body>
    <div id="challenge-running">
        <div class="main-wrapper">
            <h2>Please verify you are human</h2>

            <!-- Always-visible challenge widget -->
            <div class="challenge-widget">
                <!-- Checkbox + verification -->
            </div>
        </div>
    </div>
</body>

Pourquoi Cloudflare le déconseille

  • Toujours visible : tous les visiteurs voient le défi, sans exception.
  • Friction accrue : chaque visiteur doit interagir avant de continuer.
  • Taux de rebond plus élevé : une partie des utilisateurs abandonnent au lieu de terminer.
  • Aucune adaptation au risque : même les visiteurs de confiance sont défiés.
  • Accessibilité : l'interaction est imposée à tout le monde.

Migration d'Interactive vers Managed

Cloudflare pousse à migrer d'Interactive vers Managed. Si un site que vous automatisez bascule, voici ce qui change :

Changement observé Effet sur votre automatisation
Interactive → Managed Peut se mettre à passer sans défi visible (~90 % des cas)
HTTP 403 → 503 Mettez à jour vos contrôles de code de statut
Toujours visible → adaptatif Le widget peut ne plus figurer dans le HTML
Même sitekey Votre code de résolution CaptchaAI reste identique
Même sortie cf_clearance La gestion du cookie ne change pas

Scénario concret : un portail passe de 403 à 503

Une équipe QA à Lyon surveille chaque nuit la disponibilité d'un espace partenaire hébergé derrière Cloudflare, avec des workers sur Scaleway (région Paris). Pendant des mois, le portail renvoie un 403 avec widget visible : un Interactive Challenge, résolu via turnstile. Un matin, les logs montrent des 503 et le widget a disparu. Rien n'est cassé : l'opérateur a migré vers un Managed Challenge, et une bonne partie des requêtes passe désormais sans défi visible.

Le bon réflexe : ne traitez pas le 503 comme une erreur. Vérifiez d'abord si la réponse contient déjà le contenu attendu (passage invisible), et ne relancez une résolution que si une page de vérification s'affiche. Côté conformité, limitez la journalisation aux métadonnées techniques utiles (statut, cf-ray, horodatage) : un réflexe RGPD sain en Europe.


Identifier le défi rencontré par le code

Pour trancher automatiquement le type avant de lancer une résolution, le statut HTTP et quelques marqueurs dans le HTML suffisent le plus souvent :

import requests
import re

def identify_challenge_type(url):
    """Determine if a URL uses Managed or Interactive Challenge."""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0",
        "Accept": "text/html,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    }

    response = requests.get(url, headers=headers, timeout=15, allow_redirects=False)
    html = response.text
    status = response.status_code

    result = {
        "url": url,
        "status": status,
        "challenge_type": None,
        "cf_ray": response.headers.get("cf-ray", ""),
        "solve_method": None,
    }

    if status == 200:
        # Check for inline Turnstile widget (not a challenge page)
        if "cf-turnstile" in html:
            result["challenge_type"] = "turnstile_widget"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "none"
        return result

    if status == 503:
        # 503 indicates Managed Challenge or IUAM
        if "managed" in html or "challenge-platform" in html:
            result["challenge_type"] = "managed_challenge"
            result["solve_method"] = "turnstile"  # Managed renders as Turnstile
        elif "jschl" in html:
            result["challenge_type"] = "iuam_js_challenge"
            result["solve_method"] = "cloudflare_challenge"
        else:
            result["challenge_type"] = "unknown_503"
        return result

    if status == 403:
        if "challenge" in html.lower():
            result["challenge_type"] = "interactive_challenge"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "waf_block"
            result["solve_method"] = None  # Hard block, not solvable
        return result

    return result


# Usage
info = identify_challenge_type("https://protected-site.com/login")
print(f"Challenge: {info['challenge_type']}")
print(f"Solve with: {info['solve_method']}")

Table de signaux de détection

Signal Managed Challenge Interactive Challenge IUAM Blocage WAF
Statut HTTP 503 403 503 403
challenge-platform dans le HTML
Chemin managed dans le script
jschl dans le HTML
Widget toujours affiché
Passage invisible possible

Dépannage

Ces symptômes se lisent d'abord au statut HTTP, puis au contenu de la page ; le tableau relie chaque cas à la méthode à appeler juste après.

Symptôme Cause probable Correctif
503 sans widget visible Managed Challenge passé sans défi visible Aucune action : la requête est passée
503 avec « Checking your browser » Managed élevé en défi JavaScript Utilisez la méthode cloudflare_challenge
403 avec CAPTCHA visible Interactive Challenge (hérité) Utilisez la méthode turnstile
403 sans défi Blocage WAF, pas un défi Changez d'IP ou de schéma de requêtes
Le type de défi varie aléatoirement Managed Challenge s'adapte aux signaux Gérez à la fois Turnstile et défi JS
cf_clearance d'un type refusé pour un autre Flux de défis distincts sur le même domaine Résolvez le défi effectivement présenté

Résoudre chaque type avec CaptchaAI

Une fois le type identifié, la résolution passe par l'API CaptchaAI : vous soumettez la tâche sur in.php, puis vous interrogez le résultat sur res.php jusqu'à récupérer le token.

Résoudre un Managed Challenge

Les Managed Challenges s'affichent le plus souvent comme des widgets Turnstile. Utilisez turnstile ; sans widget, basculez sur cloudflare_challenge :

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_managed_challenge(url, sitekey=None):
    """Solve Cloudflare Managed Challenge."""
    # If sitekey not provided, extract from page
    if not sitekey:
        import re
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 Chrome/120.0.0.0",
        }
        page = requests.get(url, headers=headers, timeout=15)
        match = re.search(
            r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page.text
        )
        sitekey = match.group(1) if match else None

    if not sitekey:
        # No visible Turnstile — try cloudflare_challenge method
        return solve_js_challenge(url)

    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": url,
        "json": 1,
    })

    task_id = submit.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }).json()

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

    raise TimeoutError("Solve timed out")


def solve_js_challenge(url):
    """Fallback to cloudflare_challenge method."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "cloudflare_challenge",
        "sitekey": "managed",
        "pageurl": url,
        "json": 1,
    })

    task_id = submit.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }).json()

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

    raise TimeoutError("Solve timed out")

Résoudre un Interactive Challenge

L'Interactive Challenge expose toujours un widget visible. La même méthode turnstile s'applique :

def solve_interactive_challenge(url, sitekey):
    """Solve Cloudflare Interactive Challenge (legacy)."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": url,
        "json": 1,
    })

    task_id = submit.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }).json()

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

    raise TimeoutError("Solve timed out")

En Node.js pour les deux types

En Node.js, la logique tient dans une fonction qui choisit la méthode selon le type :

const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveCloudflareChallenge(url, type = "managed") {
  const method = type === "js_challenge" ? "cloudflare_challenge" : "turnstile";
  const sitekey =
    type === "js_challenge" ? "managed" : await extractSitekey(url);

  const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method,
      sitekey: sitekey || "managed",
      pageurl: url,
      json: 1,
    },
  });

  const taskId = submit.data.request;

  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));

    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId, json: 1 },
    });

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

  throw new Error("Solve timed out");
}

async function extractSitekey(url) {
  try {
    const response = await axios.get(url, {
      headers: { "User-Agent": "Mozilla/5.0 Chrome/120.0.0.0" },
      validateStatus: () => true,
    });
    const match = response.data.match(
      /data-sitekey=["']([0-9x][A-Za-z0-9_-]+)["']/
    );
    return match ? match[1] : null;
  } catch {
    return null;
  }
}

Questions fréquentes

CaptchaAI peut-il résoudre un Managed Challenge sans widget Turnstile visible ?

Oui, dans la plupart des cas. Sans widget dans le HTML, basculez sur cloudflare_challenge avec sitekey réglé sur managed : c'est le chemin prévu pour les pages de défi JavaScript (503 « Checking your browser »). Avec un data-sitekey présent, restez sur turnstile.

Dois-je changer mon code après une migration Interactive → Managed ?

Non, votre code de résolution reste identique. La méthode turnstile, le sitekey et la gestion du cookie cf_clearance ne changent pas. Adaptez seulement vos contrôles de statut HTTP : le code passe généralement de 403 à 503, et le widget peut disparaître du HTML.

Quels défis Cloudflare CaptchaAI prend-il en charge ?

CaptchaAI prend en charge Cloudflare Turnstile et Cloudflare Challenge, via les méthodes turnstile et cloudflare_challenge. Ces deux méthodes couvrent l'essentiel des Managed et Interactive Challenges. hCaptcha et FunCaptcha, en revanche, ne sont pas pris en charge.


En résumé

Le Managed Challenge choisit la difficulté visiteur par visiteur — de l'invisible au défi JavaScript complet — tandis que l'Interactive Challenge affiche systématiquement un CAPTCHA. Les deux produisent le même cookie cf_clearance et se résolvent avec CaptchaAI : turnstile pour la majorité des cas, cloudflare_challenge pour les pages de défi JavaScript. Le Managed Challenge est le défaut moderne ; l'Interactive Challenge relève de l'héritage.

Articles connexes

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