reCAPTCHA Invisible menghilangkan checkbox — tetapi menambahkan mode kegagalan baru untuk otomatisasi. Masalah terbesar adalah tidak mendeteksi widget invisible sama sekali, callback tidak dijalankan, mengirimkan token yang kedaluwarsa, dan menggunakan parameter v2 standar saat parameter invisible diperlukan.
Panduan ini mencakup setiap pola error umum dengan perbaikan yang tepat. Jika Anda butuh latar belakang tentang cara kerja reCAPTCHA Invisible, baca Cara Kerja reCAPTCHA Invisible dan Cara Solve-nya terlebih dahulu.
Referensi Error Cepat
| Error | Penyebab | Perbaikan |
|---|---|---|
ERROR_WRONG_GOOGLEKEY |
Sitekey salah atau dari domain lain | Ekstrak sitekey dari div widget invisible atau panggilan grecaptcha.render() |
ERROR_PAGEURL |
URL tidak cocok — mengirim URL parent, bukan URL iframe | Gunakan URL persis tempat widget invisible dimuat |
ERROR_CAPTCHA_UNSOLVABLE |
Google menandai task sebagai tidak mungkin | Coba lagi dengan proxy dan cookie baru; periksa apakah situs beralih ke v3 |
ERROR_BAD_TOKEN_OR_PAGEURL |
Token ditolak situs target | Verifikasi pageurl sama persis; inject via callback, bukan hidden field |
CAPCHA_NOT_READY |
Task masih diproses | Terus polling setiap 5 detik; solve invisible membutuhkan 10–30 detik |
ERROR_KEY_DOES_NOT_EXIST |
API key CaptchaAI tidak valid | Periksa key di captchaai.com/account |
| Token diterima tapi form gagal | Callback tidak dijalankan setelah inject token | Temukan dan panggil fungsi data-callback dengan token |
Error 1: Tidak Mendeteksi reCAPTCHA Invisible di Halaman
reCAPTCHA Invisible tidak memiliki checkbox yang terlihat. Jika scraper Anda tidak mendeteksinya, request yang dilindungi captcha akan gagal secara diam-diam dengan error submit form atau redirect.
Cara Mendeteksi reCAPTCHA Invisible
Cari pola berikut di halaman HTML:
<!-- Pattern 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..."
data-size="invisible"
data-callback="onSubmit"></div>
<!-- Pattern 2: button with data-sitekey and invisible size -->
<button class="g-recaptcha"
data-sitekey="6LdKlZEU..."
data-callback="onSubmit"
data-action="submit">Submit</button>
<!-- Pattern 3: programmatic render with size: invisible -->
<script>
grecaptcha.render('submit-btn', {
sitekey: '6LdKlZEU...',
callback: onSubmit,
size: 'invisible'
});
</script>
Skrip deteksi (Python):
import requests
from bs4 import BeautifulSoup
import re
def detect_invisible_recaptcha(url):
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")
# Check for data-size="invisible"
widget = soup.find("div", {"data-size": "invisible", "class": "g-recaptcha"})
if widget:
return {
"type": "invisible",
"sitekey": widget.get("data-sitekey"),
"callback": widget.get("data-callback")
}
# Check for programmatic render with invisible
scripts = soup.find_all("script")
for script in scripts:
if script.string and "size" in str(script.string) and "invisible" in str(script.string):
key_match = re.search(r"sitekey['"\"']?\s*[:=]\s*['"\"']([^'"\"']+)", script.string)
if key_match:
return {
"type": "invisible-programmatic",
"sitekey": key_match.group(1),
"callback": "check grecaptcha.render() call"
}
return None
Skrip deteksi (Node.js):
const axios = require("axios");
const cheerio = require("cheerio");
async function detectInvisibleRecaptcha(url) {
const { data } = await axios.get(url);
const $ = cheerio.load(data);
// Check for data-size="invisible"
const widget = $(".g-recaptcha[data-size='invisible']");
if (widget.length) {
return {
type: "invisible",
sitekey: widget.attr("data-sitekey"),
callback: widget.attr("data-callback"),
};
}
// Check script tags for programmatic invisible render
const scriptContent = $("script")
.map((_, el) => $(el).html())
.get()
.join("\n");
if (scriptContent.includes("invisible")) {
const keyMatch = scriptContent.match(/sitekey['"]?\s*[:=]\s*['"]([^'"]+)/);
if (keyMatch) {
return {
type: "invisible-programmatic",
sitekey: keyMatch[1],
callback: "check grecaptcha.render() call",
};
}
}
return null;
}
Error 2: Sitekey Salah — ERROR_WRONG_GOOGLEKEY
Ini terjadi saat Anda mengirim sitekey yang tidak cocok dengan widget reCAPTCHA Invisible di halaman target. Penyebab umum:
- Menyalin sitekey dari checkbox v2 di halaman lain
- Menggunakan sitekey dari anchor URL versi reCAPTCHA yang berbeda
- Halaman memiliki beberapa widget reCAPTCHA dan Anda mengambil yang salah
Perbaiki: Ekstrak Sitekey Invisible yang Benar
import requests
from bs4 import BeautifulSoup
def get_invisible_sitekey(url):
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")
# Priority 1: invisible widget
widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
if widget:
return widget["data-sitekey"]
# Priority 2: any g-recaptcha div (may be invisible without data-size)
widget = soup.find(class_="g-recaptcha")
if widget and widget.get("data-sitekey"):
return widget["data-sitekey"]
return None
sitekey = get_invisible_sitekey("https://staging.example.com/qa-login")
print(f"Sitekey: {sitekey}")
Error 3: Callback Tidak Dijalankan — Form Disubmit Tapi Tidak Ada Yang Terjadi
Ini adalah kegagalan reCAPTCHA Invisible nomor satu yang dilewatkan developer. Tidak seperti checkbox v2 yang cukup memasukkan token ke g-recaptcha-response, reCAPTCHA Invisible hampir selalu menggunakan fungsi callback JavaScript. Jika Anda memasukkan token tapi tidak memanggil callback, form tidak akan pernah diproses.
Cara Kerja Alur Callback
grecaptcha.execute()memicu invisible challenge- Setelah solve, Google memanggil fungsi yang ditentukan di
data-callback - Fungsi callback tersebut mengirimkan form atau membuat API call
Perbaiki: Temukan dan Jalankan Callback
Langkah 1 — Identifikasi nama callback:
# From HTML: data-callback="onSubmit"
# From JS: callback: onSubmit
# From grecaptcha.render: second argument with callback property
Langkah 2 — Inject token DAN panggil callback (Selenium):
from selenium import webdriver
import requests
import time
driver = webdriver.Chrome()
driver.get("https://example.com/form")
# Get sitekey
sitekey = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-sitekey")
callback_name = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
# Solve with CaptchaAI
task_id = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": driver.current_url,
"invisible": 1
}).text.split("|")[1]
# Poll for result
token = None
for _ in range(60):
time.sleep(5)
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id
}).text
if resp.startswith("OK|"):
token = resp.split("|")[1]
break
# Inject token into the response field
driver.execute_script(
f'document.getElementById("g-recaptcha-response").value = "{token}";'
)
# CRITICAL: Call the callback function
driver.execute_script(f'{callback_name}("{token}");')
Langkah 2 — Inject token DAN panggil callback (Puppeteer):
const puppeteer = require("puppeteer");
const axios = require("axios");
(async () => {
const browser = await puppeteer.launch({ headless: "new" });
const page = await browser.newPage();
await page.goto("https://example.com/form");
// Get sitekey and callback
const { sitekey, callback } = await page.evaluate(() => {
const el = document.querySelector(".g-recaptcha[data-size='invisible']");
return {
sitekey: el?.getAttribute("data-sitekey"),
callback: el?.getAttribute("data-callback"),
};
});
// Submit to CaptchaAI
const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: "YOUR_API_KEY",
method: "userrecaptcha",
googlekey: sitekey,
pageurl: page.url(),
invisible: 1,
},
});
const taskId = submitResp.data.split("|")[1];
// Poll for result
let token;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: "YOUR_API_KEY", action: "get", id: taskId },
});
if (result.data.startsWith("OK|")) {
token = result.data.split("|")[1];
break;
}
}
// Inject token and fire callback
await page.evaluate(
(tok, cb) => {
document.getElementById("g-recaptcha-response").value = tok;
if (cb && typeof window[cb] === "function") {
window[cb](tok);
}
},
token,
callback,
);
await browser.close();
})();
Error 4: Parameter invisible=1 Tidak Ada
Saat solve reCAPTCHA Invisible via CaptchaAI, Anda harus menyertakan invisible=1 dalam request. Tanpanya, solver akan memperlakukan task sebagai checkbox v2 standar, yang dapat menyebabkan ERROR_CAPTCHA_UNSOLVABLE atau token yang ditolak situs target.
Request Salah vs Benar
# WRONG — missing invisible=1
params = {
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url
}
# CORRECT — includes invisible=1
params = {
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1 # Required for invisible reCAPTCHA
}
response = requests.get("https://ocr.captchaai.com/in.php", params=params)
Error 5: Token Kedaluwarsa Sebelum Disubmit
Token reCAPTCHA Invisible kedaluwarsa dalam 120 detik — sama seperti v2 standar. Namun alur invisible sering memiliki langkah pemrosesan tambahan antara solve dan submit, membuat kedaluwarsa lebih sering terjadi.
Gejala
- Form mengembalikan error generik setelah inject token
siteverifysisi server mengembalikantimeout-or-duplicate- Token valid tapi butuh terlalu lama mencapai langkah submit
Perbaiki: Solve Tepat Waktu
Hanya minta solve saat Anda siap langsung mengirimkan:
import requests
import time
def solve_invisible_recaptcha(api_key, sitekey, page_url):
# Submit task
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit failed: {resp.text}")
task_id = resp.text.split("|")[1]
# 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
})
if result.text.startswith("OK|"):
return result.text.split("|")[1]
if result.text != "CAPCHA_NOT_READY":
raise Exception(f"Solve failed: {result.text}")
raise Exception("Solve timed out after 5 minutes")
# Usage: solve JUST before you need to submit
# 1. Navigate to page and prepare form data first
# 2. THEN solve the captcha
# 3. Inject token and submit immediately
token = solve_invisible_recaptcha("YOUR_API_KEY", sitekey, page_url)
# Submit within 120 seconds of receiving the token
Error 6: Token Ditolak — ERROR_BAD_TOKEN_OR_PAGEURL
Situs target memverifikasi token ke Google dan gagal. Penyebab umum:
| Penyebab | Cara mengidentifikasi | Perbaikan |
|---|---|---|
pageurl salah |
URL tidak cocok dengan domain registrasi sitekey | Gunakan URL persis tempat widget dimuat |
| Token digunakan di domain berbeda | Reuse token lintas domain | Solve dengan pageurl domain yang benar |
| Token sudah digunakan | Mengirim token yang sama dua kali | Minta solve baru untuk setiap submit |
| IP tidak cocok | IP Anda berbeda dengan IP solver | Tambahkan parameter proxy agar cocok dengan IP sesi |
| Flag invisible hilang | Di-solve sebagai v2 standar, digunakan di halaman invisible | Tambahkan invisible=1 ke request solve |
Checklist Debug
def debug_invisible_solve(api_key, sitekey, page_url, proxy=None):
"""Run a diagnostic solve with detailed logging."""
print(f"Sitekey: {sitekey}")
print(f"Page URL: {page_url}")
print(f"Proxy: {proxy or 'none'}")
params = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
}
if proxy:
params["proxy"] = proxy
params["proxytype"] = "HTTP"
# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
print(f"Submit response: {resp.text}")
if not resp.text.startswith("OK|"):
return None
task_id = resp.text.split("|")[1]
print(f"Task ID: {task_id}")
# Poll with timing
start = time.time()
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
})
elapsed = time.time() - start
print(f" [{elapsed:.0f}s] {result.text[:50]}")
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
print(f"Token received after {elapsed:.0f}s")
print(f"Token length: {len(token)} characters")
print(f"Token starts with: {token[:30]}...")
return token
if result.text != "CAPCHA_NOT_READY":
print(f"FAILED: {result.text}")
return None
print("TIMEOUT after 5 minutes")
return None
Error 7: Beberapa Widget reCAPTCHA dalam Satu Halaman
Beberapa halaman memiliki checkbox v2 yang terlihat DAN reCAPTCHA Invisible. Jika Anda menyelesaikan yang salah, token tersebut valid tapi tidak cocok dengan widget yang menjaga aksi yang Anda butuhkan.
Perbaiki: Targetkan Widget yang Benar
from bs4 import BeautifulSoup
def find_all_recaptcha_widgets(html):
soup = BeautifulSoup(html, "html.parser")
widgets = []
for el in soup.find_all(class_="g-recaptcha"):
widgets.append({
"sitekey": el.get("data-sitekey"),
"size": el.get("data-size", "normal"),
"callback": el.get("data-callback"),
"tag": el.name,
"id": el.get("id")
})
return widgets
# Example output:
# [
# {"sitekey": "6LdA...", "size": "normal", "callback": None, "tag": "div", "id": "recaptcha-login"},
# {"sitekey": "6LdB...", "size": "invisible", "callback": "onRegister", "tag": "div", "id": "recaptcha-register"}
# ]
# Use the widget with size="invisible" for the invisible solve
Solve reCAPTCHA Invisible dengan Error Handling
Pembungkus siap produksi ini menangani semua kesalahan di atas:
import requests
import time
import logging
logger = logging.getLogger(__name__)
class InvisibleRecaptchaSolver:
def __init__(self, api_key, max_retries=3):
self.api_key = api_key
self.max_retries = max_retries
self.base_url = "https://ocr.captchaai.com"
def solve(self, sitekey, page_url, proxy=None):
"""Solve invisible reCAPTCHA with automatic retry on transient errors."""
for attempt in range(1, self.max_retries + 1):
try:
token = self._attempt_solve(sitekey, page_url, proxy)
if token:
return token
except Exception as e:
logger.warning(f"Attempt {attempt} failed: {e}")
if attempt < self.max_retries:
time.sleep(2 ** attempt)
raise Exception(f"Failed to solve after {self.max_retries} attempts")
def _attempt_solve(self, sitekey, page_url, proxy):
params = {
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
}
if proxy:
params["proxy"] = proxy
params["proxytype"] = "HTTP"
# Submit task
resp = requests.get(f"{self.base_url}/in.php", params=params)
if "ERROR" in resp.text:
error = resp.text.strip()
if error in ("ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"):
raise Exception(f"Configuration error (do not retry): {error}")
if error == "ERROR_ZERO_BALANCE":
raise Exception("Account balance is zero — add funds")
raise Exception(f"Submit error: {error}")
if not resp.text.startswith("OK|"):
raise Exception(f"Unexpected submit response: {resp.text}")
task_id = resp.text.split("|")[1]
# Poll for result
for _ in range(60):
time.sleep(5)
result = requests.get(f"{self.base_url}/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id
})
if result.text.startswith("OK|"):
return result.text.split("|")[1]
if result.text == "CAPCHA_NOT_READY":
continue
if result.text == "ERROR_CAPTCHA_UNSOLVABLE":
logger.warning("Captcha unsolvable — will retry with new task")
return None
raise Exception(f"Poll error: {result.text}")
raise Exception("Solve timed out after 5 minutes")
# Usage
solver = InvisibleRecaptchaSolver("YOUR_API_KEY")
token = solver.solve(
sitekey="6LdKlZEU...",
page_url="https://staging.example.com/qa-login"
)
print(f"Token: {token[:50]}...")
const axios = require("axios");
class InvisibleRecaptchaSolver {
constructor(apiKey, maxRetries = 3) {
this.apiKey = apiKey;
this.maxRetries = maxRetries;
this.baseUrl = "https://ocr.captchaai.com";
}
async solve(sitekey, pageUrl, proxy) {
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
try {
const token = await this._attemptSolve(sitekey, pageUrl, proxy);
if (token) return token;
} catch (err) {
console.warn(`Attempt ${attempt} failed: ${err.message}`);
if (attempt < this.maxRetries) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
}
}
}
throw new Error(`Failed to solve after ${this.maxRetries} attempts`);
}
async _attemptSolve(sitekey, pageUrl, proxy) {
const params = {
key: this.apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
invisible: 1,
};
if (proxy) {
params.proxy = proxy;
params.proxytype = "HTTP";
}
// Submit task
const submitResp = await axios.get(`${this.baseUrl}/in.php`, { params });
if (submitResp.data.includes("ERROR")) {
const error = submitResp.data.trim();
if (["ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"].includes(error)) {
throw new Error(`Configuration error (do not retry): ${error}`);
}
throw new Error(`Submit error: ${error}`);
}
const taskId = submitResp.data.split("|")[1];
// Poll for result
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get(`${this.baseUrl}/res.php`, {
params: { key: this.apiKey, action: "get", id: taskId },
});
if (result.data.startsWith("OK|")) {
return result.data.split("|")[1];
}
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data === "ERROR_CAPTCHA_UNSOLVABLE") return null;
throw new Error(`Poll error: ${result.data}`);
}
throw new Error("Solve timed out after 5 minutes");
}
}
// Usage
const solver = new InvisibleRecaptchaSolver("YOUR_API_KEY");
solver.solve("6LdKlZEU...", "https://staging.example.com/qa-login").then((token) => {
console.log(`Token: ${token.substring(0, 50)}...`);
});
Checklist Pemecahan Masalah
Jalankan checklist ini saat solve reCAPTCHA Invisible gagal:
| Langkah | Periksa | Tindakan |
|---|---|---|
| 1 | Konfirmasi ini invisible, bukan v2 standar | Cari data-size="invisible" atau size: 'invisible' di render call |
| 2 | Verifikasi sitekey sudah benar | Bandingkan dengan data-sitekey pada widget invisible secara spesifik |
| 3 | Konfirmasi invisible=1 dalam request API |
Periksa parameter in.php Anda |
| 4 | Periksa pageurl sama persis |
Gunakan URL DevTools browser, bukan URL redirect |
| 5 | Temukan nama fungsi callback | Cari atribut data-callback atau callback di grecaptcha.render() |
| 6 | Verifikasi inject token + panggil callback | Keduanya diperlukan — token saja tidak cukup |
| 7 | Periksa kesegaran token | Token harus digunakan dalam 120 detik |
| 8 | Test dengan proxy jika IP penting | Tambahkan parameter proxy dan proxytype |
Pertanyaan Umum
Apa perbedaan solve reCAPTCHA Invisible dengan v2 standar?
Metode API-nya sama (method=userrecaptcha), tapi Anda harus menambahkan invisible=1 ke request. Perbedaan kritis ada di sisi inject: reCAPTCHA Invisible hampir selalu memerlukan pemanggilan fungsi callback JavaScript setelah inject token, sedangkan v2 standar biasanya cukup dengan hidden field.
Mengapa token saya berfungsi saat testing tapi gagal di produksi?
Kemungkinan besar ketidakcocokan IP. Saat testing, IP solver dan browser Anda mungkin serupa. Di produksi, IP solver dan IP server Anda berbeda. Tambahkan parameter proxy yang cocok dengan IP sesi Anda untuk memperbaikinya.
Berapa lama waktu yang dibutuhkan untuk solve reCAPTCHA Invisible?
Waktu solve umumnya 10–30 detik via CaptchaAI. Invisible challenge umumnya lebih cepat dari checkbox v2 karena tidak memerlukan image recognition — mengandalkan risk analysis.
Bisakah saya solve reCAPTCHA Invisible tanpa browser?
Ya. Karena solve terjadi di sisi server via API, Anda hanya butuh sitekey dan pageurl. Browser hanya diperlukan jika Anda harus menjalankan fungsi callback di halaman nyata. Untuk alur kerja API murni, ekstrak sitekey, solve via CaptchaAI, dan kirimkan token dengan HTTP request Anda.
Langkah Selanjutnya
- CaptchaAI Quickstart: Solve CAPTCHA Pertama dalam 5 Menit
- Cara Solve Cloudflare Turnstile dengan API
- Cara Solve GeeTest v3 dengan API