Zwischen einem leeren Editor und einem gelösten Token liegen genau zwei HTTP-Aufrufe: ein POST an in.php, der die Aufgabe übermittelt, und ein GET an res.php, der das Ergebnis abholt. Alles andere ist Feinarbeit – Parameter korrekt setzen, im richtigen Takt abfragen, Fehlercodes deuten.
Wer diesen Ablauf einmal durchgespielt hat, überträgt ihn in Minuten auf jeden anderen unterstützten CAPTCHA-Typ: Es ändern sich nur method und die Parameter.
Das Muster hinter jeder Lösung
Ob Turnstile-Token, reCAPTCHA-Token oder erkannter Text aus einem Bild-CAPTCHA – der Ablauf bleibt derselbe:
- Übermitteln – die Daten der CAPTCHA-Abfrage an
in.phpsenden - Task-ID sichern – die ID aus der Antwort speichern
- Abfragen –
res.phpalle 5 Sekunden pollen, bis ein Ergebnis vorliegt - Token einsetzen – den gelösten Wert in das Formularfeld der Zielseite eintragen
Schritt 0: API-Schlüssel aus dem Dashboard holen
- Auf captchaai.com ein Konto anlegen
- Das Dashboard öffnen
- Den 32-stelligen API-Schlüssel kopieren
Ohne aktive Threads nimmt die API keine Aufgaben an. Wenn Sie den Dienst nur evaluieren, fragen Sie beim Support nach Test-Threads.
Legen Sie den Schlüssel als Umgebungsvariable ab, statt ihn im Skript zu hinterlegen – das hält ihn aus Screenshots, Logs und Git-Commits heraus.
Schritt 1: CAPTCHA-Abfrage an die CaptchaAI-API übermitteln
Das Beispiel löst ein Cloudflare Turnstile. Zwei Werte lesen Sie vorher von der Zielseite aus:
- sitekey – der öffentliche Schlüssel des Widgets, zu finden im Attribut
data-sitekeyoder in den Skriptparametern; er beginnt mit0x - pageurl – die vollständige URL der Seite, auf der das Widget geladen wird
cURL
curl -X POST "https://ocr.captchaai.com/in.php" \
-d "key=YOUR_API_KEY" \
-d "method=turnstile" \
-d "sitekey=0x4AAAAAAAC3DHQFLr1GavNl" \
-d "pageurl=https://example.com/login" \
-d "json=1"
Python
import requests
response = requests.post("https://ocr.captchaai.com/in.php", data={
"key": "YOUR_API_KEY",
"method": "turnstile",
"sitekey": "0x4AAAAAAAC3DHQFLr1GavNl",
"pageurl": "https://example.com/login",
"json": 1,
})
print(response.json())
Node.js
const response = await fetch("https://ocr.captchaai.com/in.php", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: "YOUR_API_KEY",
method: "turnstile",
sitekey: "0x4AAAAAAAC3DHQFLr1GavNl",
pageurl: "https://example.com/login",
json: "1",
}),
});
console.log(await response.json());
PHP
<?php
$response = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
"key" => "YOUR_API_KEY",
"method" => "turnstile",
"sitekey" => "0x4AAAAAAAC3DHQFLr1GavNl",
"pageurl" => "https://example.com/login",
"json" => 1,
]));
echo $response;
Schritt 2: Task-ID aus der Antwort sichern
Läuft alles glatt, antwortet die API so:
{
"status": 1,
"request": "71823469"
}
Das Feld request enthält die Task-ID – ohne sie kommen Sie in Schritt 3 nicht an das Ergebnis.
Steht in status eine 0, enthält request stattdessen den Fehlercode. Diese fünf decken den ersten Tag ab:
| Fehlercode | Bedeutung | Was zu tun ist |
|---|---|---|
ERROR_WRONG_USER_KEY |
Format des Schlüssels stimmt nicht | 32 Zeichen prüfen, Leerzeichen entfernen |
ERROR_KEY_DOES_NOT_EXIST |
Schlüssel unbekannt | Wert erneut aus dem Dashboard kopieren |
ERROR_ZERO_BALANCE |
Kein freier Thread | Laufende Aufgaben abwarten oder größeren Plan wählen |
ERROR_PAGEURL |
Parameter pageurl fehlt |
Vollständige URL inklusive https:// senden |
ERROR_WRONG_GOOGLEKEY |
Sitekey leer oder ungültig | Sitekey neu auslesen; bei Turnstile beginnt er mit 0x |
Schritt 3: Ergebnis per Polling abfragen
Warten Sie zunächst 15 Sekunden, danach fragen Sie alle 5 Sekunden nach. Die erste Wartezeit erspart Ihnen eine Reihe von Antworten mit CAPCHA_NOT_READY.
Python
import time
time.sleep(15)
while True:
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": "71823469",
"json": 1,
}).json()
if result.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result.get("status") == 1:
token = result["request"]
print(f"Solved! Token: {token[:60]}...")
break
raise RuntimeError(result)
Node.js
await new Promise((r) => setTimeout(r, 15000));
while (true) {
const r = await fetch(
`https://ocr.captchaai.com/res.php?key=YOUR_API_KEY&action=get&id=71823469&json=1`,
);
const data = await r.json();
if (data.request === "CAPCHA_NOT_READY") {
await new Promise((r) => setTimeout(r, 5000));
continue;
}
if (data.status === 1) {
console.log("Solved:", data.request.slice(0, 60));
break;
}
throw new Error(JSON.stringify(data));
}
Bauen Sie eine Obergrenze ein – etwa 180 Sekunden. Schleifen ohne Abbruchbedingung sind ein häufiger Grund für hängende CI-Jobs.
Schritt 4: Token in das Formular eintragen
Wohin der gelöste Wert gehört, hängt vom CAPTCHA-Typ ab:
- Cloudflare Turnstile – in das Feld
cf-turnstile-responseschreiben oder den Callback des Widgets aufrufen - reCAPTCHA v2 und v3 – analog über
g-recaptcha-response - Bild- und Rasterbild-CAPTCHAs – den erkannten Text in das zugehörige Antwortfeld eintragen
- GeeTest v3 und BLS – die zurückgegebenen Felder gemäß Vorgabe der Zielseite zusammensetzen
Im Browser genügen dafür zwei Zeilen:
document.querySelector('[name="cf-turnstile-response"]').value = token;
document.querySelector("form").submit();
Tokens sind Einwegware: Turnstile und reCAPTCHA erklären sie nach rund 120 Sekunden für ungültig. Lösen Sie deshalb unmittelbar vor dem Absenden.
Praxisbeispiel: nächtlicher Login-Test in der GitLab CI
Ein Muster, das im DACH-Raum oft auftaucht: Die Staging-Instanz eines Shopware-Shops läuft auf einem Hetzner-Server, und in der GitLab CI meldet jede Nacht ein Selenium-Test einen Testkunden an und spielt eine Bestellung bis zum Checkout durch. Vor dem Login-Formular steht Cloudflare Turnstile – der Lauf scheitert also reproduzierbar am Widget, nicht an der Anwendung.
Am Testcode ändert sich dafür wenig: Der Runner liest den API-Schlüssel aus einer maskierten CI-Variablen, übermittelt Sitekey und Page-URL der Staging-Domain, wartet auf das Token und trägt es vor dem Absenden ein. Cloudflare Turnstile wird in der Regel in unter 10 Sekunden gelöst, mit hoher Erfolgsquote auf den unterstützten Typen – der nächtliche Lauf verlängert sich um Sekunden, nicht um Minuten.
Zwei Punkte gehören dabei auf die Checkliste: Testen Sie ausschließlich mit synthetischen Kundendaten und prüfen Sie Ihre Datenflüsse – IP-Adressen sind nach DSGVO personenbezogene Daten. Die Preise nennt CaptchaAI in US-Dollar; die Umrechnung bleibt Ihre Aufgabe.
Wie viele Threads brauchen Sie?
Abgerechnet wird pro gleichzeitigem Thread – nicht pro Lösung. Ein Thread ist eine CAPTCHA-Abfrage in Bearbeitung; danach nimmt er die nächste an. Die Lösungen pro Thread sind im Abrechnungsmonat nicht gedeckelt.
Für den Einstieg heißt das:
- BASIC (15 $/Monat, 5 Threads) genügt für einen einzelnen CI-Job und erste Integrationstests.
- STANDARD (30 $/Monat, 15 Threads) passt, sobald mehrere Pipelines parallel laufen.
- ADVANCE (90 $/Monat, 50 Threads) ist eine übliche Größe für dauerhafte Scraping- oder QA-Workloads.
Übermitteln Sie mehr Aufgaben gleichzeitig, als Ihr Plan Threads bereitstellt, antwortet die API mit ERROR_ZERO_BALANCE – kein Guthabenproblem, sondern eine Frage der Gleichzeitigkeit.
Typische Stolperfallen beim ersten Aufruf
- Leerzeichen im API-Schlüssel. Beim Kopieren aus dem Dashboard rutscht gern eines mit hinein.
- Fehlendes Protokoll in
pageurl. Der Wert muss mithttps://beginnen, sonst kommtERROR_PAGEURL. - Zu früh abgefragt. Erst 15 Sekunden warten, danach im 5-Sekunden-Takt.
json=1vergessen. Ohne den Parameter antwortet die API im Klartext (OK|71823469), und der JSON-Parser bricht ab.- Sitekey von der falschen Seite. Sitekeys sind seitengebunden; ein fremder Wert liefert ein abgelehntes Token.
- Threads ausgeschöpft. Details dazu in der Übersicht der API-Fehlercodes.
Häufige Fragen
Wie lange dauert die erste Lösung?
Cloudflare Turnstile wird in der Regel in unter 10 Sekunden gelöst. Dass die Beispiele trotzdem 15 Sekunden warten, ist Absicht: So läuft die erste Abfrage seltener ins Leere. Bild-CAPTCHAs sind schneller, reCAPTCHA v2 braucht länger.
Warum kommt ERROR_ZERO_BALANCE, obwohl mein Plan aktiv ist?
Weil gerade alle Threads belegt sind. Laufende Aufgaben geben ihren Thread erst frei, wenn sie abgeschlossen sind. Drosseln Sie die Gleichzeitigkeit oder wechseln Sie in einen größeren Plan.
Muss ich für jeden CAPTCHA-Typ eine eigene Integration schreiben?
Nein. Übermitteln, abfragen, eintragen bleibt gleich; es ändern sich method und die Parameter. Abgedeckt sind reCAPTCHA v2 und v3 (auch Enterprise), Cloudflare Turnstile und Challenge, GeeTest v3, Bild- und Rasterbild-CAPTCHAs sowie BLS. CaptchaFox, Friendly Captcha und Lemin laufen als Beta. hCaptcha und FunCaptcha stehen nicht zur Verfügung; GeeTest v4 ist nur als bald verfügbar angekündigt.
Wie lange ist ein gelöstes Token gültig?
Bei Cloudflare Turnstile und reCAPTCHA rund 120 Sekunden. Lösen Sie das CAPTCHA deshalb direkt vor dem Absenden des Formulars, verwenden Sie das Token genau einmal und speichern Sie es nirgends zwischen.
Brauche ich für die Integration einen Browser?
Nein. Für token-basierte Typen reichen zwei HTTP-Aufrufe plus ein POST an das Zielformular. Ein Headless-Browser wie Selenium oder Puppeteer wird erst nötig, wenn die Seite das Token über einen JavaScript-Callback erwartet.
Nächste Schritte
Weiter geht es mit dem CAPTCHA-Typ, der Ihnen am häufigsten begegnet:
- reCAPTCHA v2 per API lösen
- Cloudflare Turnstile per API lösen
- GeeTest v3 per API lösen
- Bild-CAPTCHAs per API lösen
Holen Sie sich Ihren Schlüssel im Dashboard und schließen Sie die erste Lösung ab – Konfiguration, Wiederholungslogik und Monitoring kommen danach.