Token reCAPTCHA valid, solve-nya sukses, tapi server tetap membalas success: false? Kemungkinan besar bukan CAPTCHA-nya yang bermasalah — melainkan domainnya. reCAPTCHA mengikat setiap token ke hostname tempat token itu dibuat; begitu pageurl yang dikirim ke solver tidak persis sama dengan domain tempat token dikirimkan, verifikasi domain menolaknya tanpa pesan error yang jelas.
Ringkasan Cepat: Gejala dan Perbaikannya
Rujukan cepat untuk gejala yang paling sering dilaporkan tim otomatisasi:
| Gejala | Kemungkinan penyebab | Cara mendiagnosis | Perbaikan |
|---|---|---|---|
| Token selalu ditolak | pageurl tidak cocok domain target | Bandingkan pageurl solver dengan domain pengiriman sebenarnya | Perbarui pageurl agar sama persis |
| Berhasil di www, gagal di non-www | Varian domain tidak cocok | Cek perilaku redirect | Pakai varian yang dipakai situs target |
| Kadang berhasil, kadang gagal | CDN/load balancer melayani domain berbeda-beda | Cek apakah domain berubah antar-request | Pakai URL konsisten dari redirect chain |
| Sukses di browser, gagal di skrip | Skrip mengirim dari origin berbeda | Bandingkan address bar browser dengan pageurl skrip | Samakan dengan URL final browser |
| Token Enterprise ditolak | Binding project/domain salah | Cek sitekey Enterprise cocok domain | Periksa pengaturan domain di console Enterprise |
Detail tiap skenario, lengkap dengan kode diagnosis dan perbaikannya, ada di bawah.
Kenapa reCAPTCHA Bisa Menolak Token yang Sebenarnya Valid
Akar masalahnya selalu sama: reCAPTCHA menyimpan hostname widget di dalam token, lalu server pemilik situs memutuskan apakah hostname itu diterima. Alurnya, dari pendaftaran domain sampai keputusan akhir Google:
Site owner registers reCAPTCHA → adds allowed domains (example.com, www.example.com)
↓
reCAPTCHA widget loads on example.com → matches allowed domain ✓
↓
Token generated with embedded hostname
↓
Server validates token via siteverify API
↓
Google checks: Does token hostname match allowed domains?
├─ YES → { "success": true, "hostname": "example.com" }
└─ NO → { "success": false, error or hostname mismatch }
Tiga titik yang ikut menentukan hasilnya:
- Widget di browser — hanya dimuat di domain terdaftar (opsional, bisa dinonaktifkan)
- Saat token dibuat — hostname yang tertanam di token harus sama dengan halaman asal
- Saat server memvalidasi — siteverify mengembalikan hostname, server Anda yang memutuskan apakah cocok
3 Error Verifikasi Domain yang Paling Sering Muncul
1. Hostname di respons siteverify tidak sesuai ekspektasi
{
"success": true,
"hostname": "subdomain.example.com",
"challenge_ts": "2025-01-15T10:30:00Z"
}
Token-nya sah, tapi field hostname menunjukkan domain berbeda dari yang diharapkan. Banyak implementasi server menolak kondisi ini:
# Server-side validation that checks hostname
def validate_token(token, secret_key, expected_hostname):
result = requests.post(
"https://www.google.com/recaptcha/api/siteverify",
data={"secret": secret_key, "response": token},
).json()
if not result.get("success"):
return False
# This check causes failures when hostnames don't match
if result.get("hostname") != expected_hostname:
return False # Domain mismatch!
return True
Tiga penyebab tersering:
- Token di-solve untuk
www.example.com, divalidasi diexample.com - Token di-solve untuk
staging.example.com, divalidasi diexample.com - Proxy atau CDN mengubah hostname yang terlihat server
Perbaikan: pastikan pageurl di request solver Anda sama persis dengan domain tempat token itu nanti dikirimkan.
2. Widget reCAPTCHA menolak dimuat
Widget menampilkan error atau bahkan tidak render sama sekali:
ERROR: Invalid domain for site key
Penyebab yang biasa ditemukan:
- Domain yang diizinkan di sitekey tidak mencakup domain halaman saat ini
- Widget dimuat dari
localhostatau protokolfile:// - Memakai alamat IP, bukan nama domain
Untuk otomatisasi: ini murni masalah konfigurasi pemilik situs. Yang bisa Anda kendalikan hanya memastikan pageurl yang dikirim ke solver cocok dengan domain yang diizinkan.
3. Token ditolak walau solve-nya sukses
{
"success": false,
"error-codes": ["invalid-input-response"]
}
Token dibuat untuk domain yang berbeda dari domain tempat ia divalidasi. Penyebab paling umum di skrip otomatisasi: pageurl yang dikirim ke solver tidak cocok dengan domain target sebenarnya.
# WRONG: pageurl doesn't match actual target
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": "https://staging.example.com/qa-login", # ← Must match actual domain
"json": 1,
})
# But submitting token to:
requests.post("https://app.staging.example.com/qa-login", ...) # Different subdomain!
Aturan Pencocokan Domain: Exact Match vs Wildcard
Konfigurasi domain ada di tangan pemilik situs, bukan solver — tugas Anda hanya memastikan
pageurlkonsisten dengan domain yang sudah mereka daftarkan.
Verifikasi domain reCAPTCHA bukan pencocokan subdomain ketat secara default:
example.combiasanya menerimaexample.com,www.example.com, dansub.example.combila wildcard aktifwww.example.comsaja hanya menerimawww.example.combila konfigurasinya ketat*.example.commenerima subdomain apa pun dari example.comlocalhosthanya menerimalocalhost, dipakai untuk development
Perilaku hostname di sisi server
Saat validasi lewat siteverify, field hostname di respons mencerminkan halaman tempat token dibuat — server pemilik situs yang menentukan apakah nilai itu diterima:
# Permissive validation (accepts any subdomain)
def validate_permissive(token, secret, base_domain):
result = requests.post(
"https://www.google.com/recaptcha/api/siteverify",
data={"secret": secret, "response": token},
).json()
if not result.get("success"):
return False
hostname = result.get("hostname", "")
return hostname == base_domain or hostname.endswith(f".{base_domain}")
# Strict validation (exact match only)
def validate_strict(token, secret, expected_hostname):
result = requests.post(
"https://www.google.com/recaptcha/api/siteverify",
data={"secret": secret, "response": token},
).json()
return result.get("success") and result.get("hostname") == expected_hostname
4 Cara Memperbaiki Error Domain di Skrip Otomatisasi
Skenario yang sering dialami tim scraping dan monitoring harga di Indonesia: worker jalan dari AWS ap-southeast-1 (Singapura) saat mengetes endpoint staging, token diterima tanpa masalah. Begitu dipindah ke production di belakang CDN, hostname yang terlihat oleh reCAPTCHA berubah dan token yang tadinya valid langsung ditolak. Empat langkah berikut urutan diagnosis yang efektif untuk kasus seperti ini.
Langkah 1: samakan pageurl dengan domain sebenarnya
Perbaikan paling sering dibutuhkan — pastikan pageurl sama persis dengan target aktual:
# Correct: pageurl matches where you'll submit the token
target_url = "https://www.staging.example.com/qa-login"
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": "6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
"pageurl": target_url, # Must match the actual domain
"json": 1,
})
Langkah 2: tangani varian www vs non-www
Situs sering punya dua versi domain yang saling redirect — kode berikut mendeteksi versi mana yang sebenarnya dipakai:
from urllib.parse import urlparse
def normalize_url(url):
"""Normalize URL for consistent domain matching."""
parsed = urlparse(url)
# Use exactly what the target site uses
# Check if the site redirects www → non-www or vice versa
return f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
# Test which variant the site uses
response = requests.get("https://staging.example.com/qa-login", allow_redirects=True)
actual_url = response.url # May be https://www.staging.example.com/qa-login after redirect
Langkah 3: ikuti redirect untuk menemukan domain asli
Beberapa situs mengalihkan lewat beberapa domain sebelum sampai ke halaman final:
def get_final_url(url):
"""Follow redirects to find the actual CAPTCHA page domain."""
response = requests.get(url, allow_redirects=True, timeout=15)
return response.url
# Login URL might redirect:
# https://staging.example.com/qa-login → https://auth.staging.example.com/qa-login
final_url = get_final_url("https://staging.example.com/qa-login")
# Use final_url as pageurl for solver
Langkah 4: ekstrak domain dari iframe reCAPTCHA
Kalau tiga langkah di atas belum cukup, ambil domain langsung dari markup iframe reCAPTCHA di halaman:
from bs4 import BeautifulSoup
from urllib.parse import urlparse
def extract_recaptcha_domain(html, page_url):
"""Extract the domain reCAPTCHA uses for token binding."""
soup = BeautifulSoup(html, "html.parser")
# Check for reCAPTCHA iframe
iframe = soup.find("iframe", src=lambda s: s and "recaptcha" in s)
if iframe:
src = iframe.get("src", "")
# The iframe URL may contain the domain parameter
if "domain=" in src:
# Extract domain from iframe URL
pass
# Default: use the page URL's domain
return urlparse(page_url).netloc
Tool Diagnostik: Cek Domain Sebelum Solve
Daripada menebak, jalankan diagnostik kecil ini sebelum mengirim task ke solver — ia mengikuti redirect, mengecek varian www, dan langsung melaporkan pageurl yang seharusnya dipakai:
import requests
from urllib.parse import urlparse
class DomainDiagnostic:
"""Diagnose domain verification issues for reCAPTCHA solving."""
def __init__(self, target_url):
self.target_url = target_url
self.issues = []
def check_redirects(self):
"""Check if the URL redirects to a different domain."""
try:
response = requests.get(
self.target_url, allow_redirects=True, timeout=15,
headers={"User-Agent": "Mozilla/5.0 Chrome/120.0.0.0"},
)
final_url = response.url
original_domain = urlparse(self.target_url).netloc
final_domain = urlparse(final_url).netloc
if original_domain != final_domain:
self.issues.append({
"type": "redirect",
"message": f"Redirects from {original_domain} to {final_domain}",
"fix": f"Use pageurl: {final_url}",
})
return final_url
except Exception as e:
self.issues.append({"type": "error", "message": str(e)})
return self.target_url
def check_www_variant(self):
"""Check if www and non-www point to the same content."""
parsed = urlparse(self.target_url)
domain = parsed.netloc
if domain.startswith("www."):
alt_domain = domain[4:]
else:
alt_domain = f"www.{domain}"
alt_url = self.target_url.replace(domain, alt_domain)
try:
alt_response = requests.get(alt_url, allow_redirects=True, timeout=10)
alt_final = urlparse(alt_response.url).netloc
if alt_final != domain and alt_final != alt_domain:
self.issues.append({
"type": "www_redirect",
"message": f"{alt_domain} redirects to {alt_final}",
})
except Exception:
pass
def report(self):
"""Generate diagnostic report."""
final_url = self.check_redirects()
self.check_www_variant()
print(f"Target URL: {self.target_url}")
print(f"Final URL: {final_url}")
print(f"Use as pageurl: {final_url}")
if self.issues:
print("\nIssues found:")
for issue in self.issues:
print(f" [{issue['type']}] {issue['message']}")
if "fix" in issue:
print(f" Fix: {issue['fix']}")
else:
print("\nNo domain issues detected.")
# Usage
diag = DomainDiagnostic("https://staging.example.com/qa-login")
diag.report()
Pertanyaan yang Sering Diajukan
Kenapa token reCAPTCHA saya lolos saat testing di localhost tapi ditolak begitu masuk production?
Empat penyebab tersering: localhost punya aturan domain sendiri, production dilayani CDN dengan hostname berbeda dari perkiraan, validasi hostname di production biasanya lebih ketat, dan redirect chain-nya sering berubah.
Apakah http dan https dianggap domain yang berbeda oleh reCAPTCHA?
Tidak. Verifikasinya berbasis hostname, bukan skema URL — http://example.com dan https://example.com dianggap sama selama hostname-nya identik. Token biasanya ditolak karena subdomain atau redirect, bukan skemanya.
Bagaimana cara memastikan pageurl yang saya kirim ke CaptchaAI sudah sesuai domain target sebenarnya?
Jalankan tool diagnostik di atas sebelum mengirim task solve — ia mengikuti redirect dan melaporkan URL final yang sebaiknya dipakai sebagai pageurl, jauh lebih cepat daripada menebak.
Token yang sudah di-solve untuk satu subdomain, bisakah dipakai di subdomain lain?
Tidak. Token reCAPTCHA terikat ke hostname tempat ia dibuat. Token untuk app.example.com tidak otomatis berlaku di checkout.example.com — subdomain yang mirip pun bisa gagal jika situs memvalidasi hostname secara ketat.
Apa yang harus dilakukan kalau CDN mengubah domain yang terlihat oleh reCAPTCHA?
Cari tahu hostname yang sebenarnya sampai ke browser pengguna akhir — bukan hostname origin di belakang CDN — lalu pakai itu sebagai pageurl. Tool diagnostik di atas dan langkah 3 cara paling praktis menemukannya.
Ringkasan
Verifikasi domain reCAPTCHA mengikat setiap token ke hostname tempat ia dibuat. Kegagalan otomatisasi paling sering adalah ketidakcocokan pageurl — URL yang dikirim ke CaptchaAI harus sama persis dengan domain tempat token nanti dikirimkan. Ikuti redirect untuk menemukan domain sebenarnya, tangani varian www vs non-www, dan jalankan tool diagnostik sebelum solve — bukan sesudah token ditolak.
Artikel Terkait
- cara mengatasi reCAPTCHA v2 callback lewat API
- menangani Turnstile dan reCAPTCHA v2 di situs yang sama
- error umum grid image CAPTCHA dan perbaikannya