Der Solver liefert ein Token, die Zielseite weist es ab, und im Log steht nur invalid-input-response: Bei CAPTCHAs auf Google-Domains steckt dahinter fast immer ein fehlender data-s-Parameter. data-s ist ein Sitzungstoken, das Google zusätzlich zum Sitekey in das reCAPTCHA-Widget schreibt. Wer es beim Lösen weglässt, bekommt ein formal korrektes, für diese Sitzung aber wertloses Token. Kurz gefasst:
data-serscheint fast ausschließlich auf Google-Domains, allen voran auf der/sorry-Seite der Google-Suche.- Ist das Attribut im Widget vorhanden, gehört es in die Solver-Anfrage; fehlt es, bleibt das Feld weg.
- Der Wert gilt nur für einen Seitenaufruf und wird unmittelbar vor der Übermittlung frisch ausgelesen.
Wann reCAPTCHA einen data-s-Parameter mitschickt
Zuerst die Entwarnung: Die meisten reCAPTCHA-Integrationen kennen kein data-s. Der Parameter ist ein Google-Hausmittel und begegnet Ihnen vor allem hier:
| Seite | Häufigkeit | Hinweis |
|---|---|---|
Google-Suche (/sorry, „ungewöhnlicher Datenverkehr“) |
immer | ohne data-s kein gültiges Token |
| YouTube | gelegentlich | bei bestimmten Verifizierungs-Flows |
| Google Play | gelegentlich | Prüfung von App-Einträgen |
| Google Formulare | selten | nur einzelne Implementierungen |
| Fremdseiten mit reCAPTCHA | so gut wie nie | Standardintegrationen kommen ohne aus |
Daraus folgen zwei Praxisregeln:
- Außerhalb der Google-Domains genügen
sitekeyundpageurl. - Kommen ausgerechnet bei einer Google-Suchseite ungültige Token zurück, prüfen Sie zuerst das Widget auf
data-s.
Ein typisches Szenario aus dem DACH-Raum: Ein Rank-Tracking-Dienst betreibt seine Worker auf VPS-Instanzen bei Hetzner, netcup oder IONOS. Rechenzentrums-IPs fallen schneller auf als Büroanschlüsse, entsprechend häufig landet eine Anfrage auf der /sorry-Seite – also bei einem reCAPTCHA mit data-s. Bildet der Client diesen Fall nicht ab, sinkt die Erfolgsquote, obwohl der Sitekey stimmt.
Hinweis: Prüfen Sie vor automatisierten Abrufen die Nutzungsbedingungen der Zielseite. Werden dabei personenbezogene Daten wie IP-Adressen verarbeitet, klären Sie die DSGVO-Grundlage vorab.
Was der Parameter technisch ist
data-s ist ein serverseitig erzeugtes Sitzungstoken, das direkt im HTML des Widgets steht. Es bindet die CAPTCHA-Abfrage an genau eine Server-Sitzung und verhindert die Wiederverwendung eines gelösten Tokens in anderem Kontext.
So sieht das Widget im Quelltext aus
<!-- reCAPTCHA widget with data-s parameter -->
<div class="g-recaptcha"
data-sitekey="6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp"
data-s="AB2grfE8_kyMp3XYRuJo5c..."
data-callback="onCaptchaSolved">
</div>
Das Attribut steht im selben <div> wie data-sitekey.
Eigenschaften auf einen Blick
- Format: Base64-Zeichenkette, 200–500 Zeichen
- Lebensdauer: einmalig, gebunden an den aktuellen Seitenaufruf
- Gültigkeitsbereich: sitzungsspezifisch, nicht über mehrere Aufrufe hinweg nutzbar
- Pflichtfeld: ja, sobald vorhanden – sonst schlägt die Lösung fehl
- Erneuerung: neuer Wert bei jedem Laden oder Neuladen der Seite
Sitzungsbindung: der Ablauf im Detail
User triggers CAPTCHA (e.g., Google flags unusual search traffic)
↓
Google serves a CAPTCHA page with:
- data-sitekey (site key, same for all Google search CAPTCHAs)
- data-s (session token, unique per page load)
↓
reCAPTCHA widget initializes with both parameters
↓
Challenge completion generates a g-recaptcha-response token
↓
Token is submitted alongside the session reference
↓
Google validates token + session binding
↓
If data-s was not used during solving: "invalid-input-response" or silent failure
Funktional ist data-s eine Nonce: Der Solver muss den Wert bereits beim Erzeugen des Tokens kennen. Fehlt er, entsteht ein g-recaptcha-response-Token, das die Validierung verwirft – meist ohne aussagekräftige Fehlermeldung.
data-s aus der Seite auslesen
Mit Python und BeautifulSoup
Liefert der Server das Widget bereits im HTML aus, genügt ein GET-Request: Der Helfer liest Sitekey, data-s und Callback in einem Durchgang aus.
import requests
from bs4 import BeautifulSoup
import re
def extract_recaptcha_params(url):
"""Extract reCAPTCHA parameters including data-s from a page."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
}
response = requests.get(url, headers=headers, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
# Find reCAPTCHA widget div
widget = soup.find("div", class_="g-recaptcha")
if not widget:
# Try finding by data-sitekey attribute
widget = soup.find(attrs={"data-sitekey": True})
if not widget:
return {"error": "No reCAPTCHA widget found"}
params = {
"sitekey": widget.get("data-sitekey"),
"data_s": widget.get("data-s"),
"callback": widget.get("data-callback"),
"size": widget.get("data-size"),
"has_data_s": widget.get("data-s") is not None,
}
return params
# Example: Google "unusual traffic" page
params = extract_recaptcha_params("https://www.google.com/sorry/index")
print(params)
# {
# "sitekey": "6LfwuyUT...",
# "data_s": "AB2grfE8_kyMp3...",
# "has_data_s": True
# }
Mit Node.js und Cheerio
Dieselbe Logik im Node.js-Stack – Cheerio übernimmt hier die Rolle von BeautifulSoup.
const axios = require("axios");
const cheerio = require("cheerio");
async function extractRecaptchaParams(url) {
const { data: html } = await axios.get(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/120.0.0.0 Safari/537.36",
},
timeout: 15000,
});
const $ = cheerio.load(html);
const widget = $(".g-recaptcha, [data-sitekey]").first();
if (widget.length === 0) {
return { error: "No reCAPTCHA widget found" };
}
return {
sitekey: widget.attr("data-sitekey"),
dataS: widget.attr("data-s") || null,
callback: widget.attr("data-callback") || null,
hasDataS: !!widget.attr("data-s"),
};
}
extractRecaptchaParams("https://www.google.com/sorry/index")
.then(console.log);
Mit Selenium bei dynamisch aufgebauten Seiten
Baut die Seite das Widget erst per JavaScript auf, fehlt das Attribut im ausgelieferten HTML. Selenium liest den Wert dann nach dem Rendern aus dem DOM.
from selenium import webdriver
from selenium.webdriver.common.by import By
def extract_data_s_selenium(driver, url):
"""Extract data-s from a dynamically loaded reCAPTCHA page."""
driver.get(url)
# Wait for reCAPTCHA widget to load
import time
time.sleep(3)
try:
widget = driver.find_element(By.CSS_SELECTOR, ".g-recaptcha, [data-sitekey]")
return {
"sitekey": widget.get_attribute("data-sitekey"),
"data_s": widget.get_attribute("data-s"),
}
except Exception:
return {"error": "Widget not found"}
reCAPTCHA mit data-s über CaptchaAI lösen
Der Ablauf bleibt der gewohnte Dreischritt; neu ist allein ein Feld in der Payload:
- Sitekey und
data-saus dem Widget extrahieren. - Aufgabe an
in.phpübermitteln – mitdata-sim Formular. - Ergebnis über
res.phpabfragen, bis das Token vorliegt.
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
# Step 1: Extract parameters from the CAPTCHA page
sitekey = "6LfwuyUTAAAAAOAmoS0fdqijC2PbbdH4kjq62Y1b"
data_s = "AB2grfE8_kyMp3XYRuJo5c..." # Extracted from data-s attribute
page_url = "https://www.google.com/sorry/index?continue=..."
# Step 2: Submit to CaptchaAI WITH data-s
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"data-s": data_s, # Include data-s parameter
"json": 1,
})
task_id = submit.json()["request"]
# Step 3: Poll for result
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:
token = result["request"]
print(f"Token: {token[:60]}...")
# Submit this token to the Google CAPTCHA form
break
Node.js
const axios = require("axios");
async function solveWithDataS(sitekey, dataS, pageUrl) {
const API_KEY = "YOUR_API_KEY";
// Submit with data-s
const { data: submit } = await axios.post(
"https://ocr.captchaai.com/in.php",
new URLSearchParams({
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
"data-s": dataS,
json: 1,
})
);
const taskId = submit.request;
// Poll
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const { data: result } = await axios.get(
"https://ocr.captchaai.com/res.php",
{
params: {
key: API_KEY,
action: "get",
id: taskId,
json: 1,
},
}
);
if (result.status === 1) {
return result.request;
}
}
throw new Error("Timeout");
}
Das zurückgegebene Token gehört danach zügig in das Formularfeld der geladenen Seite – reCAPTCHA-Token sind nur rund 120 Sekunden gültig.
Ein Extractor für beide Fälle
Zwei Codepfade – einen mit, einen ohne Sitzungstoken – pflegt niemand gern. Die folgende Klasse liest die Parameter einmal aus und hängt data-s nur an, wenn es im Widget steht.
import requests
from bs4 import BeautifulSoup
class RecaptchaExtractor:
"""Extract reCAPTCHA parameters from any page."""
def __init__(self, url, session=None):
self.url = url
self.session = session or requests.Session()
self.params = None
def extract(self):
"""Extract sitekey, data-s, and other parameters."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
}
response = self.session.get(self.url, headers=headers, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
widget = soup.find(attrs={"data-sitekey": True})
if not widget:
raise ValueError("No reCAPTCHA widget found on page")
self.params = {
"sitekey": widget["data-sitekey"],
"pageurl": self.url,
}
# Include data-s only if present
data_s = widget.get("data-s")
if data_s:
self.params["data-s"] = data_s
return self.params
def build_solver_payload(self, api_key):
"""Build CaptchaAI submission payload with correct parameters."""
if not self.params:
self.extract()
payload = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": self.params["sitekey"],
"pageurl": self.params["pageurl"],
"json": 1,
}
# Only include data-s when it exists
if "data-s" in self.params:
payload["data-s"] = self.params["data-s"]
return payload
# Usage
extractor = RecaptchaExtractor("https://www.google.com/sorry/index?continue=...")
payload = extractor.build_solver_payload("YOUR_API_KEY")
# payload includes data-s only when present on the page
Fünf Fehler, die immer wieder auftreten
| Fehler | Symptom | Lösung |
|---|---|---|
data-s weggelassen, obwohl vorhanden |
Token wird stillschweigend abgelehnt | vor jedem Absenden prüfen |
data-s mitgeschickt, obwohl nicht vorhanden |
Fehler oder abgewiesene Anfrage | nur setzen, wenn es im Widget steht |
| Denselben Wert mehrfach genutzt | ungültiges Token | pro Seitenaufruf frisch extrahieren |
| Wert zusätzlich URL-codiert | fehlerhafter Parameter | rohen Base64-Wert übergeben |
| Veralteter Wert, Seite vor Minuten geladen | Token passt nicht zur Sitzung | direkt vor der Übermittlung extrahieren |
Häufige Fragen
Wie erkenne ich, ob eine Seite data-s verwendet?
Suchen Sie im gerenderten HTML nach data-s= innerhalb des g-recaptcha-Containers. Zuverlässiger als der Blick in den Browser ist eine Prüfung im Code: Attribut auslesen und pro Aufruf protokollieren – dann ist im Log sofort sichtbar, woran ein Fehlerbild hängt.
Gilt data-s auch für reCAPTCHA v3 oder Enterprise?
In der Regel nein. Das Attribut gehört zum Widget-Markup von reCAPTCHA v2; v3 arbeitet mit action und Score. CaptchaAI löst v2, v2 Invisible, v2 Callback, v2 Enterprise, v3 und v3 Enterprise über dieselbe Methode userrecaptcha – nur die Zusatzfelder unterscheiden sich.
Muss ich den Wert vor dem Senden codieren?
Nein. Übergeben Sie die Base64-Zeichenkette exakt so, wie sie im Attribut steht. Bibliotheken wie requests oder axios kodieren Formularfelder ohnehin selbst; eine zusätzliche Runde URL-Encoding erzeugt einen Wert, den die Gegenseite nicht mehr zuordnen kann.
Kostet eine Lösung mit data-s mehr als ein einfaches reCAPTCHA?
Nein. CaptchaAI rechnet Thread-basiert ab, nicht pro Lösung: Bezahlt werden gleichzeitig laufende Threads, jeder löst im Abrechnungsmonat unbegrenzt viele CAPTCHAs. Von BASIC (15 $/Monat, 5 Threads) bis VIP-3 (7.500 $/Monat, 5.000 Threads) ändert sich allein die Parallelität; Aufschläge nach CAPTCHA-Typ gibt es nicht. (Preise in US-Dollar.)
Fazit
data-s begegnet Ihnen praktisch nur auf Google-eigenen Domains. Ist das Attribut vorhanden, lesen Sie es aus dem Widget-HTML aus und schicken es mit der Anfrage an CaptchaAI; fehlt es, lassen Sie das Feld weg. Diese eine Fallunterscheidung sauber im Client abzubilden, erspart die häufigste Fehlersuche rund um Google-Such-CAPTCHAs.