Beberapa situs web menerapkan reCAPTCHA v2 dan v3 pada halaman yang sama. Pola umumnya adalah: v3 berjalan invisible di background, dan jika skor terlalu rendah, v2 muncul sebagai fallback challenge yang visible. Implementasi ganda ini menimbulkan kebingungan untuk otomasi karena Anda perlu menangani dua tipe CAPTCHA berbeda dengan metode solve yang berbeda. Panduan ini mencakup deteksi, strategi solving, dan kasus edge umum.
Mengapa situs menggunakan v2 dan v3 secara bersamaan
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
Pola ini memberikan yang terbaik dari kedua dunia:
- Sebagian besar pengguna (skor v3 tinggi) tidak melihat CAPTCHA → gesekan rendah
- Pengguna mencurigakan (skor v3 rendah) lihat v2 fallback sebagai security backup
- Operator situs mengontrol threshold antara invisible dan visible
Pola Implementasi Ganda
Pola 1: Pre-assessment v3 + Fallback v2
Pola paling umum. v3 berjalan lebih dulu, dan v2 hanya muncul jika diperlukan.
<!-- 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
Beberapa situs menggunakan v3 untuk monitoring pasif dan v2 untuk aksi berisiko tinggi tertentu:
Homepage → v3 only (passive score)
Login page → v3 assessment, v2 fallback
Checkout → v2 always (high security)
Contact form → v3 only
Pola 3: Single Script, Dual Mode
Google mendukung loading satu script reCAPTCHA yang menangani v2 dan v3:
<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>
Mendeteksi Implementasi Ganda
Deteksi 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 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 Solving untuk reCAPTCHA Ganda
Strategi 1: Solve v3 Lebih Dulu, Lalu v2 Jika Diperlukan
Strategi optimal yang mencerminkan alur situs itu sendiri:
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']}")
Strategi 2: Skip v3, Solve v2 Langsung
Jika Anda tahu situs selalu menampilkan v2 untuk traffic otomasi (skor v3 akan rendah), lewati v3 dan langsung solve v2:
# If you consistently fail v3 assessment, just solve v2 directly
token = solve_v2(v2_site_key, page_url)
submit_form(token)
Ini menghemat waktu dan biaya solve v3 yang mungkin tidak melewati threshold.
Strategi 3: Penanganan Berbasis Browser
Untuk implementasi kompleks, gunakan browser untuk menangani fallback flow:
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()
Kasus Edge
Dua Sitekey Berbeda di Halaman yang Sama
Situs yang menggunakan dual reCAPTCHA akan memiliki DUA sitekey berbeda — satu untuk v3 dan satu untuk v2. Sitekey v3 muncul di URL script ?render=KEY dan di grecaptcha.execute('KEY', ...). Sitekey v2 muncul di data-sitekey="KEY" pada div widget. Menggunakan sitekey yang salah untuk versi yang salah akan menghasilkan token tidak valid.
reCAPTCHA Enterprise dengan Fallback v2
Beberapa implementasi Enterprise menggunakan v3 Enterprise untuk assessment dan v2 untuk challenge:
# 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"}
Beberapa Form dalam Satu Halaman
Jika halaman memiliki beberapa form (login + registrasi), masing-masing form mungkin memiliki instance reCAPTCHA tersendiri. Ekstrak sitekey dari form spesifik yang Anda targetkan:
# 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"]
Pertanyaan Umum
Apakah saya perlu solve v2 dan v3 di halaman yang sama?
Tidak. Biasanya Anda solve v3 lebih dulu (berjalan otomatis). Jika skor v3 melewati threshold situs, tidak ada challenge v2 yang muncul dan Anda selesai. Anda hanya perlu solve v2 jika skor v3 memicu fallback.
Bisakah saya gunakan satu API call CaptchaAI untuk dual reCAPTCHA?
Tidak. v2 dan v3 adalah tipe CAPTCHA terpisah dengan sitekey dan metode solve yang berbeda. Masing-masing memerlukan API call tersendiri ke CaptchaAI. Namun, Anda hanya perlu satu call jika v3 lulus tanpa memicu v2.
Bagaimana saya tahu jika fallback v2 dipicu?
Periksa respons server setelah submit token v3. Jika respons berisi HTML widget v2 atau memicu challenge v2 (redirect atau respons AJAX dengan CAPTCHA HTML), fallback dipicu. Di browser, periksa apakah container v2 visible setelah submit v3.
Sitekey mana yang digunakan untuk setiap versi?
Sitekey v3 ada di URL script: api.js?render=V3_KEY. Sitekey v2 ada di widget HTML: data-sitekey="V2_KEY". Selalu berbeda.
Ringkasan
Implementasi dual reCAPTCHA menggunakan v3 untuk pre-assessment invisible dan v2 sebagai fallback visible saat skor v3 terlalu rendah. Deteksi kedua versi dengan memeriksa parameter render (v3) dan widget data-sitekey (v2). Strategi otomasi optimal: solve v3 lebih dulu dengan CaptchaAI, submit token, dan solve v2 hanya jika fallback dipicu. Setiap versi memerlukan API call terpisah dengan sitekey-nya masing-masing.
Artikel Terkait
- reCAPTCHA Single Page Application yang Dinamis
- Cara Solve reCAPTCHA v2 Callback via API
- Penanganan reCAPTCHA v2 + Turnstile di Situs yang Sama