Sie haben das reCAPTCHA v2 gelöst, das Token sauber in das versteckte Feld g-recaptcha-response geschrieben – und trotzdem passiert nichts. Kein Formularversand, keine Weiterleitung, keine Reaktion. In den meisten dieser Fälle erwartet die Seite kein ausgefülltes Feld, sondern einen Callback: eine JavaScript-Funktion, die Sie mit dem gelösten Token aufrufen müssen.
Die gute Nachricht: Der API-Aufruf an CaptchaAI bleibt exakt derselbe wie bei Standard-reCAPTCHA-v2. Nur der letzte Schritt – die Token-Übergabe – ändert sich. Diese Anleitung führt Sie durch drei Aufgaben:
- eine Callback-Implementierung im Seitenquelltext erkennen,
- das CAPTCHA über die CaptchaAI-API lösen,
- den Callback mit dem gelösten Token auslösen – statt
g-recaptcha-responsezu setzen.
Neu bei reCAPTCHA v2? Starten Sie mit So lösen Sie reCAPTCHA v2 per API für den Standardablauf und kommen Sie anschließend für die Callback-Variante hierher zurück.
Voraussetzungen
Bevor Sie starten, sollten Sie folgende fünf Dinge zur Hand haben:
- CaptchaAI-API-Schlüssel – erhältlich unter captchaai.com/api.php, eine 32-stellige Zeichenkette.
- URL der Zielseite – die vollständige URL, unter der das reCAPTCHA-v2-Widget geladen wird.
- reCAPTCHA-v2-Sitekey – der öffentliche Schlüssel, der an die Widget-Instanz gebunden ist.
- Browser-Automatisierung – Selenium, Puppeteer oder Playwright; Sie brauchen JavaScript-Ausführung, um den Callback aufzurufen.
- Name der Callback-Funktion – die JavaScript-Funktion, über die die Seite das Token entgegennimmt.
Callback oder Standard-v2: wo der Unterschied liegt
Bevor Sie mit dem Erkennen und Lösen beginnen, hilft es, die eine Stelle zu kennen, an der sich beide Varianten überhaupt unterscheiden. Der API-Aufruf an CaptchaAI ist nämlich identisch – der einzige Unterschied ist, was Sie mit dem Token tun, nachdem Sie es erhalten haben.
| Schritt | Standard-v2 | Callback-v2 |
|---|---|---|
| 1. An CaptchaAI übermitteln | method=userrecaptcha + Sitekey + Page-URL |
identisch |
| 2. Ergebnis abfragen | action=get + Captcha-ID |
identisch |
| 3. Token empfangen | gleiches Token-Format | identisch |
| 4. Token übergeben | Feldwert g-recaptcha-response setzen |
Callback-Funktion mit dem Token aufrufen |
| 5. Formular absenden | Formularversand auslösen | meist automatisch – der Callback übernimmt das |
Wichtig: Setzen Sie bei Callback-Implementierungen niemals
g-recaptcha-response. Die Seite ignoriert dieses Feld und wartet darauf, dass die Callback-Funktion ausgelöst wird. Wenn Sie nur das Feld setzen, ohne den Callback aufzurufen, wirkt es für die Seite so, als wäre das CAPTCHA nie gelöst worden.
So erkennen Sie eine Callback-Implementierung
Standard-reCAPTCHA-v2 schreibt das gelöste Token in ein verstecktes g-recaptcha-response-Textfeld. Callback-Implementierungen überspringen diesen Schritt und rufen direkt eine JavaScript-Funktion auf. Der Name dieser Funktion steht typischerweise an einer dieser drei Stellen:
- im Attribut
data-callbackdes Widget-div, - als Eigenschaft
callbackin einemgrecaptcha.render()-Aufruf, - tief in der internen Laufzeitkonfiguration
___grecaptcha_cfg.
Methode 1: Das Attribut data-callback prüfen
Sehen Sie sich das reCAPTCHA-Widget-div im Seitenquelltext an:
<div class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
data-callback="SubmitToken">
</div>
Ist
data-callbackvorhanden, arbeitet die Seite mit einem Callback. Der Wert (SubmitToken) ist der Funktionsname, den Sie brauchen.
Methode 2: grecaptcha.render()-Aufrufe prüfen
Durchsuchen Sie das Seiten-JavaScript nach grecaptcha.render:
grecaptcha.render('recaptcha-container', {
sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
callback: userVerified
});
Die Eigenschaft
callbackbenennt die Funktion – hieruserVerified.
Methode 3: Die interne reCAPTCHA-Konfiguration prüfen
Öffnen Sie die Browserkonsole auf der Zielseite und führen Sie aus:
___grecaptcha_cfg.clients[0]
Arbeiten Sie sich durch die Objektstruktur bis zur Eigenschaft
callback. Der genaue Pfad hängt von der Seite ab – je nach reCAPTCHA-Version und Minifizierung kann erclients[0].aa.l.callbacklauten oder anders aufgebaut sein. Hat die Seite mehrere reCAPTCHA-Instanzen, prüfen Sieclients[1],clients[2]und so weiter.
Erkennungsskript für die Konsole
Führen Sie dies in der Browserkonsole aus, um Callback-Namen automatisch aufzuspüren:
// Check data-callback attributes
document.querySelectorAll('[data-callback]').forEach(el => {
console.log('data-callback:', el.getAttribute('data-callback'));
});
// Check internal config
if (typeof ___grecaptcha_cfg !== 'undefined') {
Object.keys(___grecaptcha_cfg.clients).forEach(key => {
const client = ___grecaptcha_cfg.clients[key];
console.log(`Client ${key}:`, JSON.stringify(client, null, 2));
});
}
Callback-basierte Widgets begegnen Ihnen besonders häufig bei Login- und Terminbuchungsformularen – etwa bei Visa- und Behörden-Terminportalen, die im DACH-Raum stark nachgefragt sind. Dort löst nicht der Formular-Button den Versand aus, sondern die Callback-Funktion selbst. Ein kurzer Blick in das Widget-div oder in grecaptcha.render() zeigt Ihnen sofort, ob Sie es mit dieser Variante zu tun haben.
Der Ablauf im Überblick
Vom Extrahieren des Sitekeys bis zum ausgelösten Callback durchläuft die Automatisierung immer dieselben Stationen. Das folgende Schema zeigt den kompletten Weg – inklusive der Warteschleife beim Abfragen:
Page → extract sitekey + pageurl + callback name
↓
POST to in.php (method=userrecaptcha)
↓
receive captcha ID
↓
wait 15–20 seconds
↓
GET res.php (action=get, id=…)
↓ ↓
CAPCHA_NOT_READY status=1 → token
(wait 5s, retry) ↓
invoke callback(token)
↓
site processes token automatically
Python-Beispiel (Selenium)
import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://example.com/login"
CALLBACK_NAME = "SubmitToken" # The callback function name from the page
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def solve_recaptcha_v2(api_key, sitekey, pageurl):
"""Submit a reCAPTCHA v2 task and return the solved token."""
# Step 1: Submit the captcha
submit_resp = requests.post(
SUBMIT_URL,
data={
"key": api_key,
"method": "userrecaptcha",
"googlekey": 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}")
# Step 2: Wait before first poll
time.sleep(15)
# Step 3: 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("reCAPTCHA v2 solve timed out")
def detect_callback_name(driver):
"""Detect the reCAPTCHA callback function name from the page."""
# Try data-callback attribute first
callback = driver.execute_script("""
const el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
return null;
""")
if callback:
return callback
# Try internal reCAPTCHA config
callback = driver.execute_script("""
if (typeof ___grecaptcha_cfg === 'undefined') return null;
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const client = clients[key];
// Walk the object tree to find a callback function
const json = JSON.stringify(client);
const match = json.match(/"callback":"(\\w+)"/);
if (match) return match[1];
}
return null;
""")
return callback
# Main workflow
driver = webdriver.Chrome()
driver.get(PAGE_URL)
# Detect the callback name (or use the known name)
detected = detect_callback_name(driver)
callback_name = detected or CALLBACK_NAME
print(f"Using callback: {callback_name}")
# Solve the CAPTCHA
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")
# Invoke the callback with the token
driver.execute_script(f"{callback_name}(arguments[0]);", token)
print("Callback invoked — site should process the token automatically")
# Wait for the page to process
time.sleep(3)
driver.quit()
Was der Code macht:
- Übermittelt Sitekey und Page-URL mit
method=userrecaptchaanin.php– identisch mit Standard-v2. - Fragt
res.phpalle 5 Sekunden ab, bis das Token bereitsteht. - Ermittelt den Namen der Callback-Funktion aus dem DOM der Seite.
- Ruft die Callback-Funktion per
execute_scriptmit dem gelösten Token auf. - Das seiteneigene JavaScript erledigt den Rest – Formularversand, Validierung oder Weiterleitung.
Node.js-Beispiel (Puppeteer)
const puppeteer = require("puppeteer");
const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://example.com/login";
const CALLBACK_NAME = "SubmitToken";
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 solveRecaptchaV2(apiKey, sitekey, pageurl) {
// Step 1: Submit the captcha
const submitResp = await fetch(SUBMIT_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: 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}`);
// Step 2: Wait before first poll
await sleep(15_000);
// Step 3: 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("reCAPTCHA v2 solve timed out");
}
async function detectCallbackName(page) {
return page.evaluate(() => {
// Try data-callback attribute
const el = document.querySelector("[data-callback]");
if (el) return el.getAttribute("data-callback");
// Try internal config
if (typeof ___grecaptcha_cfg !== "undefined") {
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const json = JSON.stringify(clients[key]);
const match = json.match(/"callback":"(\w+)"/);
if (match) return match[1];
}
}
return null;
});
}
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(PAGE_URL, { waitUntil: "networkidle2" });
// Detect callback
const detected = await detectCallbackName(page);
const callbackName = detected || CALLBACK_NAME;
console.log(`Using callback: ${callbackName}`);
// Solve the CAPTCHA
const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
console.log(`Solved token: ${token.slice(0, 80)}...`);
// Invoke the callback
await page.evaluate(
(name, tkn) => {
window[name](tkn);
},
callbackName,
token
);
console.log("Callback invoked — site should process the token automatically");
await sleep(3_000);
await browser.close();
})();
Zwei Punkte, die bei der Puppeteer-Variante gern übersehen werden:
- Der Callback-Name kommt als String aus
detectCallbackName;window[name](token)macht daraus die Funktionsreferenz im Seitenkontext. - Rufen Sie erst auf, wenn das Widget vollständig registriert ist –
waitUntil: "networkidle2"beimgotoist dafür der einfachste Anker.
PHP-Beispiel
Der API-Aufruf ist in PHP identisch. Der Callback-Aufruf braucht einen Browserkontext, deshalb deckt dieses Beispiel nur die serverseitige Lösung ab. Für den Übergabeschritt nutzen Sie ein Headless-Browser-Tool (z. B. PHP WebDriver).
<?php
$apiKey = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://example.com/login";
// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
"key" => $apiKey,
"method" => "userrecaptcha",
"googlekey" => $sitekey,
"pageurl" => $pageurl,
"json" => 1,
]));
$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
die("Submit failed: " . $submit);
}
$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";
// Step 2: Wait and poll
sleep(15);
for ($i = 0; $i < 60; $i++) {
$result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
"key" => $apiKey,
"action" => "get",
"id" => $captchaId,
"json" => 1,
]));
$resultData = json_decode($result, true);
if ($resultData["request"] === "CAPCHA_NOT_READY") {
sleep(5);
continue;
}
if ($resultData["status"] === 1) {
$token = $resultData["request"];
echo "Solved token: " . substr($token, 0, 80) . "...\n";
// Pass $token to your browser automation to invoke the callback
break;
}
die("Polling error: " . $result);
}
Sobald Sie das Token in PHP haben, übergeben Sie es mit einem Browser-Automatisierungstool (z. B. php-webdriver), das folgenden Aufruf ausführt:
SubmitToken("TOKEN_FROM_CAPTCHAAI");
Typische Fehler
| # | Fehler | Folge | Behebung |
|---|---|---|---|
| 1 | g-recaptcha-response setzen, statt den Callback aufzurufen |
Die Seite ignoriert das Token – das Formular wird nie abgesendet | Callback-Namen ermitteln und mit dem Token aufrufen |
| 2 | Falscher Name der Callback-Funktion | JavaScript-Fehler: Funktion nicht definiert | data-callback, grecaptcha.render() oder die interne Konfiguration erneut prüfen |
| 3 | Callback liegt auf einem anderen Client-Index | Auf Seiten mit mehreren Widgets wird die falsche reCAPTCHA-Instanz angesprochen | ___grecaptcha_cfg.clients[1], clients[2] usw. prüfen |
| 4 | Callback aufrufen, bevor die Seite bereit ist | Funktion im Seitenkontext noch nicht definiert | Vor dem Aufruf auf DOMContentLoaded oder networkidle warten |
| 5 | Verschleierten/minifizierten Namen verwenden | Der Callback-Name im Quelltext ist entstellt | Über die Laufzeit-Browserkonsole die tatsächliche Funktionsreferenz finden |
| 6 | Callback-v2 mit Invisible-v2 verwechseln | Manche Invisible-Implementierungen nutzen ebenfalls Callbacks | Prüfen, ob data-size="invisible" gesetzt ist – falls ja, siehe So lösen Sie reCAPTCHA Invisible per API |
Fehlerbehebung
Die meisten Callback-Probleme lassen sich anhand eines einzigen Symptoms eingrenzen. Suchen Sie Ihren Fall in der Tabelle und arbeiten Sie die Behebung ab:
| Symptom | Ursache und Behebung |
|---|---|
| Token gelöst, aber die Seite reagiert nicht | Häufigste Ursache: Sie setzen g-recaptcha-response, statt den Callback aufzurufen. Prüfen Sie, ob das Widget data-callback oder ein callback in grecaptcha.render() hat – und rufen Sie genau diese Funktion auf. |
ReferenceError: SubmitToken is not defined |
Die Funktion ist noch nicht geladen oder der Name stimmt nicht. Namen über data-callback/interne Konfiguration bestätigen, auf vollständiges Laden der Seite warten und auf minifizierten Seiten window.SubmitToken in der Konsole prüfen. |
| Token funktioniert bei Standard-v2, scheitert aber hier | Wahrscheinlich eine Callback-Implementierung. Mit den Erkennungsschritten oben bestätigen und dann auf den Callback-Aufruf wechseln. |
ERROR_BAD_TOKEN_OR_PAGEURL |
Das Paar aus Sitekey und Page-URL ist ungültig. Ein reiner API-Fehler, unabhängig von Callback vs. Standard – beide Werte erneut von der Seite extrahieren. |
| Die Seite hat mehrere reCAPTCHA-Widgets | Jedes Widget kann seinen eigenen Callback haben. Jedes g-recaptcha-div bzw. ___grecaptcha_cfg.clients prüfen und das Widget dem Formular zuordnen, das Sie ansteuern. |
ERROR_CAPTCHA_UNSOLVABLE |
Die Abfrage konnte nicht gelöst werden. Mit einer neuen Anfrage wiederholen – der Fehler ist nicht callback-spezifisch. |
Die vollständige Fehlerreferenz finden Sie unter Häufige Fehler beim Lösen von reCAPTCHA v2.
Warum CaptchaAI hier funktioniert
| Faktor | Detail |
|---|---|
| Gleicher API-Aufruf | Submit- und Abfrage-Ablauf sind identisch mit Standard-reCAPTCHA-v2 – keine zusätzlichen Parameter nötig |
| Erfolgsquote | Hohe Erfolgsquote auf unterstützten Typen; Callback und Standard nutzen denselben Solver |
| Lösungszeit | reCAPTCHA v2 typischerweise unter 60 Sekunden |
| Token-Kompatibilität | Das zurückgegebene Token funktioniert sowohl mit der g-recaptcha-response-Übergabe als auch mit dem Callback-Aufruf |
| Preise | Thread-basierte Pläne ab 15 $/Monat (BASIC, 5 Threads) mit unbegrenzten Lösungen pro Thread |
Fazit: Das von CaptchaAI zurückgegebene Token ist dasselbe, egal wie die Seite reCAPTCHA v2 implementiert. Der Unterschied liegt vollständig in Ihrem clientseitigen Code – darin, wie Sie das Token an die Seite übergeben.
Vollständiges Beispielprojekt
Wenn Sie kein Gerüst zusammensetzen, sondern direkt ein lauffähiges Projekt starten möchten, deckt das Repository den kompletten Ablauf ab:
- Umgebungs-Setup und Abhängigkeiten,
- Polling mit sauberer Wiederholungslogik,
- Fehlerbehandlung für abgelaufene Tokens und API-Fehler.
Das vollständige lauffähige Beispiel auf GitHub ansehen →
FAQ
Warum passiert nichts, obwohl mein Token gültig ist?
Weil die Seite einen Callback erwartet. Ein gültiges Token allein reicht nicht – solange Sie es nur in g-recaptcha-response schreiben, bleibt es wirkungslos. Rufen Sie stattdessen die registrierte Callback-Funktion mit dem Token auf, dann verarbeitet die Seite das Ergebnis.
Wie lange ist ein gelöstes reCAPTCHA-Token gültig?
Etwa 120 Sekunden. reCAPTCHA-Tokens laufen nach rund zwei Minuten ab. Übergeben Sie das Token deshalb unmittelbar nach dem Lösen an den Callback und lagern Sie es nicht zwischen – ein abgelaufenes Token weist die Seite zurück.
Wie unterscheide ich Callback-v2 von Invisible reCAPTCHA v2?
Am Attribut data-size – zwei Fälle sind zu unterscheiden:
data-size="invisible"gesetzt: Invisible-v2, das oft ebenfalls mit einem Callback arbeitet.- Attribut fehlt, aber
data-callbackvorhanden: sichtbares Callback-v2.
Der Weg über die API ist in beiden Fällen gleich; nur der Auslöser unterscheidet sich.
Was tue ich, wenn eine Seite mehrere reCAPTCHA-Widgets hat?
Behandeln Sie jedes Widget einzeln – Schritt für Schritt:
- Prüfen Sie
___grecaptcha_cfg.clientsauf alle registrierten Instanzen. - Ordnen Sie jede Instanz ihrem Formular zu; jede kann einen eigenen Callback und einen eigenen Client-Index haben.
- Rufen Sie nur den Callback auf, der zum anvisierten Formular gehört.
Jetzt mit dem Callback-Solving starten
- API-Schlüssel holen – captchaai.com/api.php
- Callback-Namen ermitteln –
data-callback,grecaptcha.render()oder die interne Konfiguration prüfen - Python- oder Node.js-Code oben kopieren – Platzhalter durch Ihren Schlüssel, Sitekey, Page-URL und Callback-Namen ersetzen
- Ausführen – das Token kommt typischerweise in unter 60 Sekunden, der Callback feuert, die Seite verarbeitet das Ergebnis
- Hängen geblieben? Starten Sie mit Häufige Fehler beim Lösen von reCAPTCHA v2 oder lesen Sie die vollständigen CaptchaAI-API-Dokumente
Verwandte Artikel
- reCAPTCHA Invisible mit Python lösen
- reCAPTCHA v2 und Turnstile auf derselben Seite
- reCAPTCHA Enterprise Assessment API im Detail