Pemecahan Masalah

Kesalahan dan Perbaikan Umum reCAPTCHA Invisible

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

  1. grecaptcha.execute() memicu invisible challenge
  2. Setelah solve, Google memanggil fungsi yang ditentukan di data-callback
  3. 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
  • siteverify sisi server mengembalikan timeout-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
Komentar dinonaktifkan untuk artikel ini.