Hintergründe

Cloudflare Turnstile Widget-Modi: Verwaltet, Nicht interaktiv, Unsichtbar

Die wichtigste Erkenntnis vorweg: Turnstile kennt drei Widget-Modi, aber alle drei liefern dasselbe cf-turnstile-response-Token und werden mit demselben Aufruf gelöst – method=turnstile, Sitekey plus Page-URL. Der Modus ändert nicht, wie Sie lösen, sondern nur, wie schwer er im HTML zu finden ist: Der Managed-Modus zeigt oft sichtbares Markup, der Non-Interactive-Modus nur einen Spinner, der Invisible-Modus gar keinen Container. Wer diese Muster kennt, weiß auf jeder Seite, wo der Sitekey steckt.


Welchen Modus haben Sie vor sich?

So ordnen Sie ein Turnstile-Widget in wenigen Sekunden dem richtigen Modus zu:

  1. Sichtbares Kontrollkästchen, das nur manchmal erscheint? Das ist der Managed-Modus.
  2. Nur ein Spinner, aber nie ein Kontrollkästchen? Dann läuft der Non-Interactive-Modus.
  3. Kein sichtbarer Container, nur Skript und Antwortfeld im HTML? Dann ist der Invisible-Modus aktiv.

Schneller geht es über das gesetzte Attribut:

HTML-Signal Modus
data-appearance="interaction-only" Non-Interactive
data-size="invisible" Invisible
keine Modus-Angabe Managed (Standard)

Die drei Modi im Überblick

Token-Feld und CaptchaAI-Methode sind überall identisch; anders sind nur Sichtbarkeit, Interaktion und Fehlerverhalten.

Funktion Verwaltet Nicht interaktiv Unsichtbar
Widget sichtbar? Manchmal Nie (nur Spinner) Niemals
Containerelement erforderlich? Ja Ja Ja (versteckt)
Benutzerinteraktion erforderlich? Manchmal (Kontrollkästchen) Nein Nein
Proof-of-Work-Abfrage? Ja (kann eskalieren) Ja (immer) Ja (immer)
Interaktives Kontrollkästchen-Fallback? Ja Nein (schlägt stattdessen fehl) Nein (schlägt stattdessen fehl)
Token-Ausgabe cf-turnstile-response cf-turnstile-response cf-turnstile-response
CaptchaAI-Methode turnstile turnstile turnstile
Empfohlen für Login, Registrierung Reibungsarme Formulare Hintergrundprüfung

Managed-Modus: Cloudflare entscheidet (Standard)

Der Managed-Modus ist die Voreinstellung: Cloudflare legt die Prüfstufe pro Besucher fest und rendert das Widget je nach Reputation unterschiedlich:

  • Hohes Vertrauen: unsichtbarer Pass, keine sichtbare Benutzeroberfläche
  • Mittleres Vertrauen: Kontrollkästchen-Widget zum Bestätigen
  • Geringes Vertrauen: interaktive Abfrage oder Blockierung

Für die Automatisierung ist das der häufigste und variabelste Fall: Derselbe Sitekey zeigt im Test mal ein Kontrollkästchen, mal gar nichts – die Stufe entscheidet sich zur Laufzeit, nicht im Markup.

Einbindung im HTML

<!-- Managed mode (default) -->
<div class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-theme="light">
</div>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

Managed-Modus im HTML erkennen

Der Managed-Modus hat kein eigenes Attribut – er ist die Abwesenheit einer expliziten Modus-Angabe. Prüfen Sie also, ob cf-turnstile vorhanden ist und keine Modus-Option gesetzt wurde:

def is_managed_mode(html):
    """Check if Turnstile is using managed mode (default)."""
    # Managed mode is the default — no explicit mode attribute
    has_turnstile = "cf-turnstile" in html
    has_explicit_mode = 'data-appearance="interaction-only"' in html or \
                        'data-appearance="always"' in html or \
                        'appearance: "interaction-only"' in html
    return has_turnstile and not has_explicit_mode

Non-Interactive-Modus: nur Proof-of-Work

Im Non-Interactive-Modus erscheint nie ein Kontrollkästchen. Turnstile rechnet im Hintergrund eine Proof-of-Work-Abfrage und zeigt nur einen Lade-Spinner.

Lässt sie sich nicht ohne Interaktion abschließen, schlägt sie fehl – anders als der Managed-Modus eskaliert sie nicht zum Kontrollkästchen.

Einbindung

<!-- Non-interactive mode -->
<div class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-appearance="interaction-only">
</div>

Oder über die JavaScript-API:

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

Ablauf

Page loads → Widget initializes
    ↓
Background proof-of-work runs
    ↓
Success → Token generated (no visible UI)
    OR
Failure → Widget reports error (no fallback to checkbox)

Wo der Non-Interactive-Modus üblich ist

  • Kommentarformulare und Feedback-Widgets
  • Newsletter-Anmeldungen
  • Aktionen mit geringem Wert und minimaler Reibung
  • API-Endpunkte mit browserseitigem Schutz

Beispiel: Newsletter mit Double-Opt-In

Newsletter-Anmeldungen mit Double-Opt-In – im DACH-Raum rechtlicher Standard – setzen häufig auf den Non-Interactive-Modus. Für Ihre QA heißt das: kein Kontrollkästchen zum Anklicken – Sie lösen das Token per API und tragen es vor dem Absenden in cf-turnstile-response ein.


Invisible-Modus: ganz ohne sichtbaren Container

Der Invisible-Modus ist tatsächlich unsichtbar – im Ansichtsfenster erscheint kein Containerelement.

Das Widget läuft beim Laden der Seite oder per Auslöser und erzeugt ein Token ohne sichtbare Anzeige.

<!-- Invisible mode — container is hidden -->
<div id="turnstile-invisible"
     class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-size="invisible">
</div>

Oder komplett per JavaScript:

// Programmatic invisible Turnstile
turnstile.render('#hidden-container', {
    sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
    size: 'invisible',
    callback: function(token) {
        // Token ready — submit form automatically
        submitForm(token);
    },
    'error-callback': function() {
        // Challenge failed
        console.error('Invisible Turnstile failed');
    },
});

Warum die Erkennung hier schwieriger ist

Weil der Container keine sichtbaren Abmessungen hat, greift die reine Sicht-Erkennung nicht. Nützlicher ist ein Bündel von Signalen, aus denen Sie eine Konfidenz ableiten:

  • das geladene Turnstile-Skript von challenges.cloudflare.com
  • das Attribut data-size="invisible"
  • ein turnstile.render-Aufruf im JavaScript
  • das Antwortfeld cf-turnstile-response
import re

def detect_invisible_turnstile(html):
    """Detect invisible Turnstile on a page."""
    indicators = {
        "script_loaded": "challenges.cloudflare.com/turnstile" in html,
        "size_invisible": 'data-size="invisible"' in html or
                          "size: 'invisible'" in html or
                          'size: "invisible"' in html,
        "api_render_call": "turnstile.render" in html,
        "response_field": "cf-turnstile-response" in html,
    }

    if indicators["script_loaded"] and indicators["size_invisible"]:
        return {"mode": "invisible", "confidence": "high"}
    elif indicators["script_loaded"] and indicators["api_render_call"]:
        return {"mode": "invisible_or_programmatic", "confidence": "medium"}
    elif indicators["response_field"]:
        return {"mode": "turnstile_present", "confidence": "low"}

    return {"mode": "none", "confidence": "high"}

Sitekey aus jedem Modus extrahieren

Unabhängig vom Modus brauchen Sie zum Lösen nur den Sitekey. Er kann an drei Stellen im HTML stehen:

  • im data-sitekey-Attribut des Containers
  • in einem JavaScript-render-Aufruf
  • in einem Konfigurationsobjekt der Seite

Die folgende Funktion deckt alle drei Fundstellen ab:

import re

def extract_turnstile_sitekey(html):
    """Extract Turnstile sitekey from page HTML (works for all modes)."""

    # Pattern 1: data-sitekey attribute in HTML
    match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', html)
    if match:
        return match.group(1)

    # Pattern 2: JavaScript render call
    match = re.search(r"sitekey:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
    if match:
        return match.group(1)

    # Pattern 3: Turnstile config object
    match = re.search(r"siteKey['\"]?\s*[:=]\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
    if match:
        return match.group(1)

    return None

Alle drei Modi mit CaptchaAI lösen

Hier zahlt sich die Eingangsbeobachtung aus. Sie übergeben nur zwei Werte:

  • den Sitekey aus dem HTML
  • die Page-URL der Seite mit dem Widget

Anschließend fragen Sie per Polling ab und erhalten dasselbe Token – egal welcher Modus.

Python

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_turnstile(sitekey, page_url):
    """Solve any Turnstile mode — managed, non-interactive, or invisible."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": page_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("Turnstile solve timed out")


# Use with any mode
token = solve_turnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://example.com/login")
print(f"Token: {token[:50]}...")

Node.js

const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveTurnstile(sitekey, pageUrl) {
  const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method: "turnstile",
      sitekey,
      pageurl: pageUrl,
      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("Turnstile solve timed out");
}

// Same function works for all Turnstile modes
solveTurnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://example.com/login")
  .then((token) => console.log("Token:", token.substring(0, 50)));

DSGVO-Hinweis: Wenn Sie Page-URLs oder Tokens protokollieren, beachten Sie den Datenschutz – URLs und Proxy-IP-Adressen können personenbezogene Daten sein.


Fehlerbehebung

Symptom Ursache Beheben
Token gültig, aber Formular lehnt es ab Falscher Sitekey (anders als sichtbares Widget) Suchen Sie nach einem mit JavaScript gerenderten Sitekey
Widget nicht in HTML gefunden Invisible-Modus, der erst nach dem ersten Rendern lädt Warten Sie, bis die Seite vollständig geladen ist, und prüfen Sie die XHR-Antworten
Mehrere Turnstile-Widgets auf der Seite Verschiedene Sitekeys für verschiedene Formulare Ordnen Sie den Sitekey dem konkreten Formular zu
data-size="compact" verwirrt die Erkennung Compact ist eine Größenvariante, kein Modus Compact nutzt standardmäßig den Managed-Modus
data-action-Attribut vorhanden Aktions-Tag für Analysen, kein Modus Aktion in die Lösung einbeziehen, falls für die Validierung nötig
Token läuft vor der Übermittlung ab Turnstile-Token laufen nach 300 Sekunden ab Unmittelbar vor dem Absenden lösen

Häufige Fragen

Was unterscheidet data-appearance="interaction-only" von data-size="invisible"?

Die beiden Attribute steuern verschiedene Dinge:

  • data-appearance="interaction-only" schaltet den Non-Interactive-Modus – Spinner, aber nie ein Kontrollkästchen.
  • data-size="invisible" schaltet den Invisible-Modus – der Container hat keine sichtbaren Abmessungen.

Kurz gesagt: das eine steuert die Interaktion, das andere die Größe.

Warum schlägt der Non-Interactive-Modus fehl, statt ein Kontrollkästchen zu zeigen?

Weil das genau seine Aufgabe ist:

  • Der Managed-Modus darf zum Kontrollkästchen eskalieren.
  • Der Non-Interactive-Modus nicht – scheitert die Proof-of-Work-Abfrage ohne Interaktion, meldet das Widget einen Fehler, ohne Fallback.

Wie lange ist ein Turnstile-Token gültig?

Turnstile-Token laufen nach 300 Sekunden ab.

Lösen Sie deshalb erst kurz vor dem Absenden, nicht Minuten im Voraus – ein abgelaufenes Token weist der Server ab, obwohl es formal korrekt aussieht.

Muss ich das data-action-Attribut beim Lösen mitgeben?

Meist nicht. data-action ist ein Label für die serverseitige Auswertung und ändert weder Modus noch Token-Format.

Nur wenn die Zielseite die Aktion bei der Validierung erwartet, nehmen Sie sie in Ihren Lösungsablauf auf.


Fazit

Die drei Turnstile-Modi steuern die Nutzererfahrung, liefern aber dasselbe cf-turnstile-response-Token und werden identisch gelöst – mit dem Turnstile-Solver von CaptchaAI, mit hoher Erfolgsquote auf allen unterstützten Modi. Der Unterschied liegt allein in der Erkennung:

  • Managed: sichtbares HTML, am leichtesten zu finden
  • Non-Interactive: nur ein Spinner, erkennbar am data-appearance-Attribut
  • Invisible: kein Container, erfordert eine tiefere Seitenanalyse

Verwandte Artikel

Kommentare sind für diesen Artikel deaktiviert.