Troubleshooting

Menangani reCAPTCHA v2 dan v3 di Halaman yang Sama

Ketika satu halaman memuat reCAPTCHA v2 dan v3 sekaligus, urutan penanganannya sederhana: selesaikan v3 lebih dulu, lalu tangani v2 hanya jika skor v3 rendah dan situs memunculkan challenge fallback. Bagian yang sulit bukan solving-nya, melainkan mendeteksi versi mana yang aktif dan sitekey mana untuk masing-masing versi. Salah pasang sitekey, dan token langsung ditolak.

Secara ringkas, alur penanganannya terdiri dari tiga langkah:

  1. Deteksi apakah halaman benar-benar memuat dua versi dan ambil kedua sitekey.
  2. Selesaikan v3 lebih dulu, karena berjalan otomatis di background.
  3. Tangani v2 hanya jika respons server menunjukkan fallback terpicu.

Artikel ini membahas tiap langkah tersebut, lengkap dengan strategi solving dan kasus edge yang sering bikin skrip otomasi gagal diam-diam.


Kenapa satu halaman memakai v2 dan v3 sekaligus

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

Kombinasi ini memberi operator situs dua lapisan sekaligus:

  • Mayoritas pengunjung dengan skor v3 tinggi tidak pernah melihat CAPTCHA, sehingga gesekan tetap rendah.
  • Traffic mencurigakan dengan skor v3 rendah baru dihadapkan ke challenge v2 sebagai lapisan keamanan cadangan.
  • Operator situs memegang kendali penuh atas threshold yang memisahkan mode invisible dan mode visible.

Untuk otomasi, konsekuensinya jelas: Anda tidak bisa mengasumsikan satu versi saja. Skrip harus siap menghadapi keduanya. Perbedaan mendasar antara kedua versi merangkum kenapa keduanya butuh perlakuan berbeda:

Aspek reCAPTCHA v3 reCAPTCHA v2
Mode Invisible, skor di background Visible, checkbox atau image
Lokasi sitekey Parameter render= di URL script Atribut data-sitekey pada widget
Kapan muncul Selalu berjalan lebih dulu Hanya saat skor v3 di bawah threshold
Field token g-recaptcha-response g-recaptcha-response

Tiga pola implementasi ganda yang umum

Pola 1: pre-assessment v3 dengan fallback v2

Pola paling sering ditemui, dengan dua karakteristik utama:

  • v3 dieksekusi lebih dulu secara otomatis.
  • v2 baru dirender kalau skor v3 berada di bawah ambang.
<!-- 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>

Pola 2: sitekey berbeda untuk aksi berbeda

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

Peta di atas menggambarkan situs yang memakai v3 untuk pemantauan pasif dan menyimpan v2 khusus untuk aksi berisiko tinggi seperti checkout. Versi CAPTCHA yang Anda hadapi bisa berubah tergantung halaman.

Pola 3: satu script untuk dua mode

<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>

Satu script reCAPTCHA bisa menangani v2 dan v3 sekaligus, tetapi render dan execute tetap memakai dua sitekey berbeda.


Mendeteksi halaman reCAPTCHA ganda

Sebelum memilih strategi, pastikan dulu halaman memang memuat dua versi. Ada tiga penanda yang perlu Anda cek pada HTML halaman:

  • Sitekey v3 pada parameter render= di URL script atau di panggilan grecaptcha.execute().
  • Sitekey v2 pada atribut data-sitekey di widget, atau pada panggilan grecaptcha.render().
  • Status ganda: kedua sitekey ada dan nilainya berbeda.

Deteksi dengan 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://staging.example.com/qa-login")
print(detection)

Deteksi dengan 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://staging.example.com/qa-login").then(console.log);

Strategi menyelesaikan reCAPTCHA ganda

Ada tiga pendekatan yang lazim dipakai, tergantung seberapa sering situs menurunkan fallback v2 ke traffic Anda:

  1. Selesaikan v3 dulu, tangani v2 hanya saat fallback muncul — paling efisien untuk mayoritas kasus.
  2. Lewati v3, langsung selesaikan v2 — untuk situs yang selalu menantang traffic otomasi.
  3. Serahkan keputusan ke browser — untuk implementasi yang sulit diprediksi dari HTML mentah.

Strategi 1: selesaikan v3 dulu, v2 hanya jika perlu

Strategi paling efisien meniru alur situs itu sendiri: coba v3, dan panggil v2 hanya saat fallback benar-benar terpicu.

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://staging.example.com/qa-login",
)
print(f"Solved with {result['version']}")

Beberapa hal penting dari kode di atas:

  • Kedua fungsi memakai method yang sama, yaitu userrecaptcha.
  • Yang membedakan hanyalah parameter version dan sitekey.
  • Token hasilnya sama-sama masuk ke field g-recaptcha-response.

Strategi 2: lewati v3, langsung selesaikan v2

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

Jika Anda tahu situs selalu menampilkan v2 untuk traffic otomasi (skor v3-nya pasti rendah), tidak ada gunanya membayar solve v3. Langsung selesaikan v2 seperti di atas — ini menghemat satu langkah yang kemungkinan besar sia-sia.

Strategi 3: penanganan lewat browser

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

driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-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()

Untuk implementasi rumit, biarkan browser yang memutuskan versi mana yang aktif, lalu inject token sesuai kondisi.


Contoh skenario untuk tim otomasi di Indonesia

Bayangkan tim data di sebuah startup Jakarta yang menjalankan pipeline pemantauan harga dengan worker di region AWS ap-southeast-3 (Jakarta). Halaman login yang dihadapi memakai v3 di background dan menurunkan challenge v2 saat request datang dari IP pusat data. Pola paling hemat di sini adalah Strategi 1: coba v3 dulu, dan hanya bayar solve v2 saat fallback muncul. Dengan model harga CaptchaAI berbasis thread — misalnya BASIC ($15/bulan, 5 threads) dengan solve tak terbatas per thread — percobaan v3 yang kadang gagal threshold tidak menambah tagihan. Catatan kepatuhan lokal: sesuai UU Pelindungan Data Pribadi (UU 27/2022), proses hanya data yang berhak Anda akses dan hindari data pribadi tanpa dasar yang sah.


Kasus edge yang sering muncul

Dua sitekey berbeda dalam satu halaman

Situs dengan reCAPTCHA ganda selalu punya DUA sitekey berbeda — satu untuk v3, satu untuk v2:

  • Sitekey v3 muncul di URL script ?render=KEY dan di grecaptcha.execute('KEY', ...).
  • Sitekey v2 ada di data-sitekey="KEY" pada div widget.
  • Memakai sitekey yang salah untuk versi yang salah menghasilkan token tidak valid, dan situs menolaknya tanpa pesan error yang jelas.

reCAPTCHA Enterprise dengan fallback v2

# 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"}

Sebagian implementasi Enterprise memakai v3 Enterprise untuk scoring dan v2 biasa untuk challenge, dideteksi lewat keberadaan recaptcha/enterprise.js.

Beberapa form dalam satu halaman

# 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"]

Jika satu halaman memuat beberapa form (misalnya login dan registrasi), tiap form bisa punya instance reCAPTCHA sendiri. Ambil sitekey dari form spesifik yang Anda targetkan seperti di atas, jangan yang pertama ditemukan.


Pertanyaan umum

Berapa biaya menyelesaikan reCAPTCHA ganda dengan CaptchaAI?

CaptchaAI menagih per thread, bukan per solve, dengan solve tak terbatas per thread setiap bulan. Paket BASIC ($15/bulan, 5 threads) sudah cukup untuk banyak alur otomasi, dan karena tidak ada biaya per CAPTCHA, percobaan v3 yang gagal threshold sebelum fallback v2 tidak menambah tagihan.

Bagaimana urutan solve yang benar untuk v2 dan v3?

Selesaikan v3 lebih dulu karena berjalan otomatis. Jika skornya lolos threshold situs, tidak ada v2 yang muncul dan pekerjaan selesai. Anda baru menyelesaikan v2 saat respons server menunjukkan fallback terpicu.

Apakah satu API call bisa menangani v2 dan v3 sekaligus?

Tidak. v2 dan v3 adalah tipe terpisah dengan sitekey dan parameter berbeda, jadi masing-masing butuh call tersendiri. Namun dalam praktik Anda sering hanya butuh satu call bila v3 lolos tanpa memicu v2.

Bagaimana cara tahu fallback v2 sudah terpicu?

Periksa respons server setelah token v3 dikirim. Jika respons memuat HTML widget v2 atau memicu challenge (redirect maupun respons AJAX berisi HTML CAPTCHA), fallback aktif. Di browser, cek apakah container v2 berubah menjadi visible setelah submit v3.

Apakah CaptchaAI mendukung reCAPTCHA Enterprise pada halaman ganda?

Ya. reCAPTCHA v2 Enterprise dan v3 Enterprise sama-sama didukung. Tambahkan parameter enterprise saat men-submit, dan tangani fallback v2 dengan cara yang sama seperti implementasi non-Enterprise.


Ringkasan

Implementasi reCAPTCHA ganda memakai v3 untuk pre-assessment invisible dan v2 sebagai fallback visible saat skor v3 terlalu rendah. Deteksi kedua versi dengan memeriksa parameter render (v3) dan atribut data-sitekey pada widget (v2). Strategi otomasi paling efisien: selesaikan v3 lebih dulu dengan CaptchaAI, kirim token, dan tangani v2 hanya jika fallback terpicu. Ingat, tiap versi butuh API call terpisah dengan sitekey masing-masing.

Artikel terkait

Komentar dinonaktifkan untuk artikel ini.