Fehlerbehebung

Behandlung von reCAPTCHA v2 und v3 auf derselben Seite

Die kurze Antwort zuerst: Lösen Sie reCAPTCHA v3, prüfen Sie den zurückgegebenen Score und lösen Sie v2 nur dann zusätzlich, wenn die Seite den sichtbaren Fallback nachlädt. Zwei reCAPTCHA-Versionen auf einer Seite bedeuten also nicht zwei Lösungen pro Aufruf, sondern eine bedingte Kette: v3 immer, v2 nur bei Bedarf. Verwirrend wird das in der Automatisierung vor allem deshalb, weil beide Versionen eigene Sitekeys und eigene Lösungswege mitbringen. Dieser Leitfaden zeigt, wie Sie die Doppelimplementierung im Quelltext erkennen, welche Strategie zu welchem Muster passt und welche Randfälle auftreten.


Warum Websites v3 und v2 kombinieren

Der Aufbau folgt einer einfachen Logik: v3 bewertet jeden Zugriff unsichtbar im Hintergrund, und erst wenn der Score unter die serverseitige Schwelle fällt, blendet die Seite eine sichtbare v2-Abfrage nach. Ein typisches DACH-Beispiel ist der Login eines Shopware-Shops auf einem Hetzner-Server: v3 prüft jeden Anmeldeversuch, doch sobald der Score bei automatisiertem Traffic einbricht, erscheint die vertraute v2-Checkbox.

User visits page
    ↓
reCAPTCHA v3 runs invisibly in background
    ↓
Score returned to server (e.g., 0.4)
    ↓
Score below threshold (e.g., < 0.7)?
    ├─ YES → Show reCAPTCHA v2 checkbox/image challenge
    └─ NO  → Allow action without visible CAPTCHA
Besuchergruppe v3-Score Was der Nutzer erlebt
Reguläre Besucher hoch kein CAPTCHA, kaum Reibung
Auffälliger Traffic niedrig v2-Abfrage als Sicherheitsnetz
Grenzfälle knapp unter der Schwelle v2 nur situativ, vom Betreiber gesteuert

Die drei gängigen Muster der Doppelimplementierung

In der Praxis begegnen Ihnen drei Varianten. Am häufigsten läuft v3 zuerst und lädt v2 nur bei zu niedrigem Score nach (Muster 1). Daneben gibt es Seiten, die je nach Aktion unterschiedliche Sitekeys ziehen (Muster 2), sowie Aufbauten, die beide Versionen aus einem Skript bedienen (Muster 3).

Muster 1: v3 bewertet vor, v2 fängt ab

<!-- Both scripts loaded -->
<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>

<form id="loginForm">
    <!-- v2 widget (hidden initially) -->
    <div id="recaptcha-v2-container" style="display:none;">
        <div class="g-recaptcha" data-sitekey="V2_SITE_KEY"></div>
    </div>
    <button type="submit">Login</button>
</form>

<script>
// First attempt: v3 invisible
grecaptcha.ready(function() {
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'}).then(function(v3Token) {
        fetch('/api/verify-v3', {
            method: 'POST',
            body: JSON.stringify({token: v3Token})
        })
        .then(r => r.json())
        .then(data => {
            if (data.score < 0.7) {
                // Score too low → show v2 fallback
                document.getElementById('recaptcha-v2-container').style.display = 'block';
                grecaptcha.render('recaptcha-v2-container', {sitekey: 'V2_SITE_KEY'});
            } else {
                // Score OK → submit form directly
                document.getElementById('loginForm').submit();
            }
        });
    });
});
</script>

Muster 2: eigener Sitekey je Aktion

Homepage → v3 only (passive score)
Login page → v3 assessment, v2 fallback
Checkout → v2 always (high security)
Contact form → v3 only

Muster 3: ein Skript, zwei Versionen

<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script>
    // v3 execute
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'});

    // v2 render (uses a different site key)
    grecaptcha.render('v2-container', {sitekey: 'V2_SITE_KEY'});
</script>

Doppelimplementierung im Quelltext erkennen

Bevor Sie eine Strategie wählen, sollten Sie sicher wissen, ob wirklich beide Versionen aktiv sind. v3 verrät sich über den render-Parameter in der Skript-URL oder über grecaptcha.execute(...), v2 über das data-sitekey-Attribut am Widget-Div. Die folgenden Snippets prüfen beides in einem Durchgang.

Erkennung mit Python

import requests
import re

def detect_dual_recaptcha(url):
    """Detect if a page uses both reCAPTCHA v2 and v3."""
    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",
    }
    html = requests.get(url, headers=headers, timeout=15).text

    result = {
        "has_v3": False,
        "has_v2": False,
        "v3_site_key": None,
        "v2_site_key": None,
        "dual": False,
        "pattern": None,
    }

    # Detect v3 (render parameter or enterprise.execute)
    v3_match = re.search(r"api\.js\?render=([A-Za-z0-9_-]+)", html)
    if v3_match and v3_match.group(1) != "explicit":
        result["has_v3"] = True
        result["v3_site_key"] = v3_match.group(1)

    # Detect v3 in execute calls
    v3_execute = re.search(
        r"grecaptcha\.(?:enterprise\.)?execute\s*\(\s*['\"]([^'\"]+)['\"]",
        html,
    )
    if v3_execute:
        result["has_v3"] = True
        if not result["v3_site_key"]:
            result["v3_site_key"] = v3_execute.group(1)

    # Detect v2 (g-recaptcha class or explicit render)
    v2_match = re.search(r'data-sitekey="([^"]+)"', html)
    if v2_match:
        key = v2_match.group(1)
        if key != result.get("v3_site_key"):
            result["has_v2"] = True
            result["v2_site_key"] = key

    # Check for explicit v2 render
    v2_render = re.search(
        r"grecaptcha\.render\s*\([^,]+,\s*\{[^}]*sitekey:\s*['\"]([^'\"]+)",
        html,
    )
    if v2_render:
        result["has_v2"] = True
        if not result["v2_site_key"]:
            result["v2_site_key"] = v2_render.group(1)

    result["dual"] = result["has_v3"] and result["has_v2"]

    if result["dual"]:
        # Determine pattern
        if "display:none" in html or "display: none" in html:
            result["pattern"] = "v3_pre_assessment_v2_fallback"
        else:
            result["pattern"] = "v2_v3_simultaneous"

    return result

detection = detect_dual_recaptcha("https://example.com/login")
print(detection)

Erkennung mit Node.js

const axios = require("axios");

async function detectDualRecaptcha(url) {
    const { data: html } = await axios.get(url, { timeout: 15000 });

    const result = {
        hasV3: false,
        hasV2: false,
        v3SiteKey: null,
        v2SiteKey: null,
        dual: false,
    };

    // v3 detection
    const v3Match = html.match(/api\.js\?render=([A-Za-z0-9_-]+)/);
    if (v3Match && v3Match[1] !== "explicit") {
        result.hasV3 = true;
        result.v3SiteKey = v3Match[1];
    }

    // v2 detection
    const v2Match = html.match(/data-sitekey="([^"]+)"/);
    if (v2Match && v2Match[1] !== result.v3SiteKey) {
        result.hasV2 = true;
        result.v2SiteKey = v2Match[1];
    }

    result.dual = result.hasV3 && result.hasV2;
    return result;
}

detectDualRecaptcha("https://example.com/login").then(console.log);

Lösungsstrategien für kombiniertes reCAPTCHA

Welche Strategie passt, hängt davon ab, wie zuverlässig Ihr Traffic den v3-Schwellenwert erreicht. Das gelöste Token übergeben Sie jeweils als g-recaptcha-response; die Aufgabe nimmt in.php entgegen, das Ergebnis holen Sie per Polling von res.php.

Strategie 1: erst v3, dann v2 bei Bedarf

Die sauberste Variante bildet den Ablauf der Website eins zu eins nach: erst v3, dann v2 nur, wenn der Fallback anspringt.

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_v3(site_key, page_url, action="login"):
    """Solve reCAPTCHA v3 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "version": "v3",
        "action": action,
        "json": 1,
    }).json()

    task_id = submit["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("v3 solve timeout")

def solve_v2(site_key, page_url):
    """Solve reCAPTCHA v2 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1,
    }).json()

    task_id = submit["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("v2 solve timeout")

def solve_dual_recaptcha(v3_key, v2_key, page_url, action="login"):
    """Handle dual reCAPTCHA: try v3, fall back to v2."""
    # Step 1: Try v3
    v3_token = solve_v3(v3_key, page_url, action)

    # Step 2: Submit v3 token to target
    response = requests.post(f"{page_url}/verify", data={
        "g-recaptcha-response": v3_token,
    })

    # Step 3: Check if v2 fallback is needed
    if "recaptcha" in response.text.lower() and v2_key:
        print("v3 score too low — v2 fallback triggered")
        v2_token = solve_v2(v2_key, page_url)
        return {"version": "v2", "token": v2_token}

    return {"version": "v3", "token": v3_token}

result = solve_dual_recaptcha(
    v3_key="6LcExample_v3_key",
    v2_key="6LcExample_v2_key",
    page_url="https://example.com/login",
)
print(f"Solved with {result['version']}")

Strategie 2: v3 überspringen, direkt v2 lösen

Erreicht Ihr automatisierter Traffic den v3-Schwellenwert ohnehin nie und lädt die Seite verlässlich v2 nach, sparen Sie sich die v3-Runde und lösen direkt v2 – das spart Zeit und die Kosten einer Lösung, die den Score ohnehin verfehlt hätte.

# If you consistently fail v3 assessment, just solve v2 directly
token = solve_v2(v2_site_key, page_url)
submit_form(token)

Strategie 3: den Fallback im Browser steuern

Bei verschachtelten oder JavaScript-lastigen Implementierungen ist ein echter Browser oft robuster: Er entscheidet selbst, ob das v2-Widget sichtbar wird.

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://example.com/login")
time.sleep(3)

# Check if v2 widget is visible
v2_visible = driver.execute_script("""
    const container = document.querySelector('.g-recaptcha');
    if (!container) return false;
    const style = window.getComputedStyle(container.parentElement);
    return style.display !== 'none' && style.visibility !== 'hidden';
""")

if v2_visible:
    # v2 is showing — solve v2
    sitekey = driver.find_element(
        By.CSS_SELECTOR, "[data-sitekey]"
    ).get_attribute("data-sitekey")
    token = solve_v2(sitekey, driver.current_url)
    driver.execute_script(
        f'document.getElementById("g-recaptcha-response").value = "{token}";'
    )
else:
    # v3 only — solve v3
    # Extract v3 key from page source
    v3_key = driver.execute_script(
        "return document.querySelector('script[src*=\"render=\"]')"
        ".src.match(/render=([^&]+)/)[1];"
    )
    token = solve_v3(v3_key, driver.current_url)
    # Inject v3 token into the form
    driver.execute_script(f"""
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'g-recaptcha-response';
        input.value = '{token}';
        document.querySelector('form').appendChild(input);
    """)

driver.find_element(By.CSS_SELECTOR, "form").submit()

Randfälle in der Praxis

Zwei Sitekeys auf einer Seite

Seiten mit dualem reCAPTCHA tragen zwei verschiedene Sitekeys – einen für v3, einen für v2. Der v3-Schlüssel steht in der Skript-URL ?render=KEY und in grecaptcha.execute('KEY', ...), der v2-Schlüssel im data-sitekey="KEY" des Widget-Divs. Der falsche Schlüssel für die falsche Version liefert ein ungültiges Token.

reCAPTCHA Enterprise mit v2-Fallback

Manche Enterprise-Aufbauten nutzen v3 Enterprise für die Bewertung und v2 für die eigentliche Abfrage:

# Detect and handle Enterprise + v2 combo
if "recaptcha/enterprise.js" in html:
    # Use enterprise parameter for v3
    v3_params = {"enterprise": 1, "version": "v3"}
else:
    v3_params = {"version": "v3"}

Mehrere Formulare auf einer Seite

Enthält eine Seite mehrere Formulare – etwa Login und Registrierung –, kann jedes seine eigene reCAPTCHA-Instanz besitzen. Lesen Sie den Sitekey gezielt aus dem Zielformular aus:

# Target the login form specifically
login_form = soup.find("form", id="login-form")
widget = login_form.find(attrs={"data-sitekey": True})
sitekey = widget["data-sitekey"]

Häufige Fragen

Wie erkenne ich, ob eine Seite v3 und v2 kombiniert?

Suchen Sie im Quelltext nach zwei Signaturen zugleich: dem render-Parameter beziehungsweise grecaptcha.execute(...) für v3 und einem data-sitekey am g-recaptcha-Widget für v2. Tauchen beide mit unterschiedlichen Schlüsseln auf, liegt eine Doppelimplementierung vor – genau das meldet das Python-Snippet oben als dual: True.

Ab welchem v3-Score wird der v2-Fallback ausgelöst?

Das legt allein der Website-Betreiber fest; ein häufiger Wert liegt zwischen 0,5 und 0,7, verbindlich ist er aber nur serverseitig. Den konkreten Schwellenwert sehen Sie nie direkt – Sie merken ihn daran, dass nach der v3-Übermittlung die v2-Abfrage nachgeladen wird.

Verdoppelt duales reCAPTCHA meine Kosten bei CaptchaAI?

Nein. CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung – jeder Tarif von BASIC (15 $/Monat, 5 Threads) bis VIP-3 (7.500 $/Monat, 5.000 Threads) enthält unbegrenzte Lösungen pro Thread. Ob Sie nur v3 oder v3 plus v2-Fallback lösen, ändert nur, wie viele Aufrufe nacheinander durch einen Thread laufen.


Fazit

  • v3 zuerst, v2 nur bei Bedarf: Lösen Sie zuerst reCAPTCHA v3 mit CaptchaAI, übermitteln Sie das Token und greifen Sie erst zu v2, wenn der Fallback tatsächlich anspringt.
  • Erkennung: v3 am render-Parameter, v2 am Widget-data-sitekey – beide mit ihrem eigenen Sitekey.
  • Ein Aufruf je Version: Jede Version braucht ihren eigenen API-Aufruf, aber nur so viele, wie die Seite im konkreten Fall verlangt.

Verwandte Artikel

Kommentare sind für diesen Artikel deaktiviert.