Khắc Phục Sự Cố

Các lỗi và cách khắc phục reCAPTCHA v2 phổ biến

Request gửi tới CaptchaAI trông đúng, nhưng task vẫn báo lỗi hoặc trang đích vẫn từ chối token? Gần như chắc chắn nguyên nhân nằm ở một trong bốn chỗ: sai googlekey, sai pageurl, thiếu bước gọi callback, hoặc token đã hết hạn trước khi form được submit. Bốn nguyên nhân này chiếm phần lớn các ticket lỗi reCAPTCHA v2 mà đội automation gặp phải.

Bài viết này đi thẳng vào từng triệu chứng, kèm mã lỗi cụ thể ở cả hai giai đoạn — gửi task (in.php) và lấy kết quả (res.php) — cộng thêm các tình huống trang đích âm thầm từ chối token dù API báo thành công. Nếu bạn chưa từng tích hợp reCAPTCHA v2 với CaptchaAI, nên đọc hướng dẫn giải reCAPTCHA v2 bằng API trước để nắm luồng gửi → nhận ID task → polling/callback → dùng token.


Checklist chẩn đoán nhanh

Kiểm tra bảng này trước khi đọc chi tiết từng mã lỗi — hầu hết trường hợp bạn sẽ tìm ra hướng sửa ngay ở đây.

Triệu chứng Điều cần kiểm tra trước tiên
ERROR_GOOGLEKEY hoặc ERROR_WRONG_GOOGLEKEY Sitekey đã được copy đúng từ data-sitekey chưa?
ERROR_PAGEURL Bạn đã gửi đầy đủ URL trang chưa?
ERROR_BAD_TOKEN_OR_PAGEURL Widget có nằm trong iframe không? Dùng URL của iframe.
CAPCHA_NOT_READY kéo dài hơn 3 phút Bình thường với các challenge khó. Tăng timeout lên 180 giây.
ERROR_CAPTCHA_UNSOLVABLE Gửi task mới. Nếu lặp lại nhiều lần, kiểm tra lại sitekey + pageurl.
Token hợp lệ nhưng trang không phản ứng Kiểm tra data-callback. Gọi hàm callback thủ công.
Token trả về nhưng form vẫn fail Token có thể đã hết hạn (>2 phút). Submit nhanh hơn.
Lỗi xảy ra không đều, lúc được lúc không Thêm retry logic với ID task mới mỗi lần.

4 nguyên nhân gây lỗi reCAPTCHA v2 nhiều nhất

Trước khi lần theo từng mã lỗi cụ thể, đây là bốn điểm chiếm khoảng 80% các ca lỗi thực tế đội automation gặp phải:

  1. googlekey sai hoặc bị thiếu — giá trị này lấy từ thuộc tính data-sitekey trên widget reCAPTCHA, hoặc tham số k trong URL anchor. Nếu sai, để trống, hoặc copy nhầm từ trang khác, API từ chối task ngay với ERROR_GOOGLEKEY hoặc ERROR_WRONG_GOOGLEKEY.
  2. pageurl sai — phải là URL chính xác nơi widget thực sự tải. Nếu widget nằm trong iframe host trên domain khác, bạn cần URL của iframe đó chứ không phải URL trang cha. Sai chỗ này gây ERROR_PAGEURL hoặc ERROR_BAD_TOKEN_OR_PAGEURL.
  3. Không gọi callback — một số trang dùng hàm callback JavaScript thay vì field ẩn g-recaptcha-response. Nếu bạn chỉ điền token vào field ẩn trong khi trang đang chờ callback, form sẽ không bao giờ submit. Kiểm tra data-callback trên widget hoặc property callback trong grecaptcha.render().
  4. Token hết hạn hoặc bị dùng lại — token chỉ dùng được một lần và hết hạn sau khoảng 2 phút. Automation mất quá nhiều thời gian giữa lúc nhận token và lúc submit, hoặc cố dùng lại token cũ, sẽ bị trang đích âm thầm từ chối mà không báo lỗi rõ ràng.

Cách lấy đúng sitekey

Đây là nguyên nhân số một, nên đáng để kiểm tra kỹ trước khi gửi task:

# Look for data-sitekey in the page HTML
# <div class="g-recaptcha" data-sitekey="6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-"></div>

# Or find it in the anchor URL
# https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-

Lỗi ở bước gửi task (in.php)

Đây là các lỗi trả về khi bạn gửi task tới https://ocr.captchaai.com/in.php.

Mã lỗi Nguyên nhân Cách xử lý
ERROR_WRONG_USER_KEY Định dạng API key không hợp lệ (không đủ 32 ký tự) Kiểm tra lại API key tại captchaai.com/api.php
ERROR_KEY_DOES_NOT_EXIST API key không tồn tại trong hệ thống Xác nhận bạn copy đủ toàn bộ key, không dính khoảng trắng thừa
ERROR_ZERO_BALANCE Số dư tài khoản bằng 0 Nạp thêm vào tài khoản hoặc kiểm tra số thread đang hoạt động
ERROR_PAGEURL Thiếu tham số pageurl Thêm đầy đủ URL nơi widget reCAPTCHA xuất hiện
ERROR_GOOGLEKEY googlekey sai định dạng hoặc để trống Trích xuất đúng sitekey từ trang
ERROR_WRONG_GOOGLEKEY Thiếu hẳn tham số googlekey Thêm googlekey vào request API
ERROR_BAD_TOKEN_OR_PAGEURL Cặp googlekey + pageurl không khớp Kiểm tra widget có nằm trong iframe không; dùng URL iframe
ERROR_BAD_PARAMETERS Thiếu hoặc sai định dạng tham số bắt buộc Xem lại tài liệu API để đối chiếu field bắt buộc

Ví dụ: gửi request đúng và xử lý lỗi

import requests

def submit_recaptcha_v2(api_key, sitekey, page_url):
    response = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": 1
    })

    data = response.json()

    if data.get("status") == 1:
        return data["request"]  # task ID

    error = data.get("request", "UNKNOWN_ERROR")

    if error == "ERROR_WRONG_USER_KEY":
        raise ValueError("API key format is invalid. Must be 32 characters.")
    elif error == "ERROR_ZERO_BALANCE":
        raise RuntimeError("Account balance is zero. Top up at captchaai.com")
    elif error == "ERROR_PAGEURL":
        raise ValueError("pageurl parameter is missing from request")
    elif error in ("ERROR_GOOGLEKEY", "ERROR_WRONG_GOOGLEKEY"):
        raise ValueError(f"Invalid sitekey. Verify the data-sitekey value on the page.")
    elif error == "ERROR_BAD_TOKEN_OR_PAGEURL":
        raise ValueError("Sitekey/pageurl mismatch. Check if widget is in an iframe.")
    else:
        raise RuntimeError(f"API error: {error}")

# Usage
task_id = submit_recaptcha_v2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://staging.example.com/qa-login")
print(f"Task submitted: {task_id}")
async function submitRecaptchaV2(apiKey, sitekey, pageUrl) {
  const params = new URLSearchParams({
    key: apiKey,
    method: "userrecaptcha",
    googlekey: sitekey,
    pageurl: pageUrl,
    json: 1,
  });

  const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
  const data = await res.json();

  if (data.status === 1) return data.request;

  const error = data.request || "UNKNOWN_ERROR";
  const fixes = {
    ERROR_WRONG_USER_KEY: "API key format is invalid. Must be 32 characters.",
    ERROR_ZERO_BALANCE: "Account balance is zero. Top up at captchaai.com",
    ERROR_PAGEURL: "pageurl parameter is missing from request",
    ERROR_GOOGLEKEY: "Invalid sitekey. Check the data-sitekey attribute.",
    ERROR_BAD_TOKEN_OR_PAGEURL: "Sitekey/pageurl mismatch. Check iframe context.",
  };

  throw new Error(fixes[error] || `API error: ${error}`);
}

// Usage
const taskId = await submitRecaptchaV2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://staging.example.com/qa-login");
console.log(`Task submitted: ${taskId}`);

Lỗi ở bước polling kết quả (res.php)

Đây là các lỗi xuất hiện khi bạn polling https://ocr.captchaai.com/res.php để lấy kết quả.

Mã lỗi Nguyên nhân Cách xử lý
CAPCHA_NOT_READY Task vẫn đang được giải Đợi 5 giây rồi polling lại. Đây là trạng thái bình thường, không phải lỗi.
ERROR_CAPTCHA_UNSOLVABLE Không thể giải được CAPTCHA này Gửi một task mới với tham số mới
ERROR_WRONG_ID_FORMAT Sai định dạng ID task Kiểm tra lại ID trả về từ in.php
ERROR_WRONG_CAPTCHA_ID ID task không tồn tại Xác nhận bạn đã lưu đúng ID task
ERROR_EMPTY_ACTION Thiếu tham số action=get Thêm action=get vào request polling

Ví dụ: polling kèm xử lý lỗi đầy đủ

import time
import requests

def poll_result(api_key, task_id, timeout=120):
    start = time.time()

    while time.time() - start < timeout:
        time.sleep(5)

        response = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key,
            "action": "get",
            "id": task_id,
            "json": 1
        })

        data = response.json()

        if data.get("status") == 1:
            return data["request"]  # solved token

        error = data.get("request", "")

        if error == "CAPCHA_NOT_READY":
            continue  # normal — keep waiting
        elif error == "ERROR_CAPTCHA_UNSOLVABLE":
            raise RuntimeError("CAPTCHA unsolvable. Submit a new task with fresh params.")
        elif error in ("ERROR_WRONG_ID_FORMAT", "ERROR_WRONG_CAPTCHA_ID"):
            raise ValueError(f"Invalid task ID: {task_id}")
        else:
            raise RuntimeError(f"Polling error: {error}")

    raise TimeoutError(f"Solve timed out after {timeout}s")

# Usage
token = poll_result("YOUR_API_KEY", task_id)
print(f"Token: {token[:50]}...")
async function pollResult(apiKey, taskId, timeout = 120000) {
  const start = Date.now();

  while (Date.now() - start < timeout) {
    await new Promise((r) => setTimeout(r, 5000));

    const params = new URLSearchParams({
      key: apiKey,
      action: "get",
      id: taskId,
      json: 1,
    });

    const res = await fetch(`https://ocr.captchaai.com/res.php?${params}`);
    const data = await res.json();

    if (data.status === 1) return data.request;

    if (data.request === "CAPCHA_NOT_READY") continue;
    if (data.request === "ERROR_CAPTCHA_UNSOLVABLE")
      throw new Error("Unsolvable. Submit a new task.");
    throw new Error(`Polling error: ${data.request}`);
  }

  throw new Error(`Solve timed out after ${timeout / 1000}s`);
}

Vì sao trang đích vẫn từ chối token dù API báo thành công

API trả về token hợp lệ nhưng trang đích vẫn không chấp nhận. Đây là nhóm lỗi khó gỡ nhất vì phía CaptchaAI báo mọi thứ đã ổn — vấn đề nằm hoàn toàn ở cách bạn đưa token vào trang.

Token bị đưa vào sai field

Một số trang tìm token trong textarea g-recaptcha-response. Số khác dùng grecaptcha.getResponse(). Số khác nữa lại chờ một callback. Chọn sai cách chèn thì việc submit form sẽ thất bại mà không báo lỗi rõ ràng. Kiểm tra trang để xác định đúng cách trang mong đợi:

# Method 1: Hidden field injection
driver.execute_script(
    'document.getElementById("g-recaptcha-response").innerHTML = arguments[0];',
    token
)

# Method 2: Callback execution (check data-callback attribute)
driver.execute_script(f'onCaptchaSuccess("{token}");')

# Method 3: Direct form field + submit
driver.execute_script(
    'document.querySelector("[name=g-recaptcha-response]").value = arguments[0];',
    token
)
driver.find_element("css selector", "form").submit()

Callback không được kích hoạt

Nếu widget có data-callback="onSuccess" hoặc dùng grecaptcha.render() với property callback, chỉ điền field ẩn sẽ không có tác dụng gì. Bạn phải gọi trực tiếp hàm callback đó — tìm tên hàm rồi gọi thủ công:

// In browser console or Puppeteer/Playwright
// Check for data-callback
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
  window[callbackName](token);
}

Hai lỗi còn lại: token hết hạn và widget trong iframe

  • Token đã hết hạn — nếu quá ~2 phút trôi qua giữa lúc nhận token và lúc submit form, Google sẽ từ chối nó. Tình trạng này rất phổ biến trong pipeline automation chạy chậm hoặc có nhiều bước trung gian. Cách xử lý: submit ngay sau khi nhận token; nếu pipeline chậm, đặt bước gọi solve gần bước submit hơn thay vì gọi ngay từ đầu.
  • Widget nằm trong iframe — nếu reCAPTCHA tải bên trong iframe từ domain khác, bạn phải dùng URL của iframe đó làm pageurl, không phải URL trang cha. ERROR_BAD_TOKEN_OR_PAGEURL thường là dấu hiệu của đúng vấn đề này. Cách xử lý: mở DevTools, tìm iframe chứa reCAPTCHA, lấy URL src của nó làm pageurl.

Ví dụ thực tế: một đội automation làm outsourcing QA cho khách hàng thương mại điện tử tại TP.HCM tự động hóa luồng checkout trên môi trường staging bằng Puppeteer. Task gửi lên CaptchaAI trả về status: 1 và token hợp lệ, nhưng form thanh toán vẫn báo "vui lòng xác nhận bạn không phải robot". Kiểm tra DOM thì phát hiện widget reCAPTCHA được nhúng qua iframe trỏ tới subdomain CDN riêng chứ không phải domain chính của trang checkout — pageurl họ dùng lại là URL trang cha, sai ngữ cảnh thực tế của widget. Đổi pageurl sang đúng src của iframe, token được chấp nhận ngay ở lần submit tiếp theo.


Câu hỏi thường gặp

reCAPTCHA v2 khác reCAPTCHA Enterprise thế nào khi gọi API CaptchaAI?
Về giao diện thì gần như giống nhau, nhưng reCAPTCHA Enterprise dùng tham số API khác (site key thường có định dạng và luồng xác thực riêng). Nếu bạn gửi request theo cách của reCAPTCHA v2 chuẩn cho một trang thực chất đang chạy Enterprise, bạn sẽ gặp lỗi liên tục dù mọi thứ trông đúng. Kiểm tra grecaptcha.enterprise trong console của trang để xác định đúng loại trước khi gửi task.

CAPCHA_NOT_READY có phải là lỗi không?
Không. Nó chỉ có nghĩa là CAPTCHA vẫn đang được giải, không phải sự cố. Đợi 5 giây rồi polling res.php lại. Thời gian giải reCAPTCHA v2 thông thường rơi vào khoảng 15–60 giây, nên nhận CAPCHA_NOT_READY vài lần trong lúc chờ là chuyện bình thường.

Làm sao biết widget reCAPTCHA có đang nằm trong iframe hay không?
Mở DevTools, chọn công cụ "inspect element" rồi bấm vào widget reCAPTCHA. Nếu bạn thấy nó nằm trong một thẻ <iframe>src trỏ tới domain khác với trang bạn đang xem (thường là domain phụ dùng riêng cho CAPTCHA hoặc CDN), thì đó chính là URL bạn phải dùng làm pageurl — không phải URL thanh địa chỉ trình duyệt.

Token báo hợp lệ nhưng form vẫn không submit được, cần kiểm tra gì?
Kiểm tra theo đúng thứ tự: (1) trang có dùng callback không — tìm data-callback trên widget; (2) pageurl có đúng ngữ cảnh không, đặc biệt nếu widget nằm trong iframe; (3) thời gian từ lúc nhận token đến lúc dùng có vượt quá 2 phút không.

Nên đặt timeout polling bao nhiêu cho một challenge reCAPTCHA v2 khó?
Với hầu hết trường hợp, 120 giây là đủ. Nếu bạn thấy CAPCHA_NOT_READY kéo dài hơn 3 phút một cách thường xuyên, tăng timeout lên 180 giây trước khi coi đó là lỗi thật sự — một số challenge phức tạp cần nhiều thời gian giải hơn mức trung bình.


Sửa quy trình reCAPTCHA v2 của bạn theo 4 bước

  1. Kiểm tra lại input — trích xuất đúng googlekey từ data-sitekey và dùng đúng URL trang (nhớ kiểm tra iframe)
  2. Xác định cách chèn token — trang cần field ẩn, callback, hay cả hai
  3. Submit ngay sau khi nhận token — dùng trong vòng 2 phút
  4. Thêm xử lý lỗi đầy đủ — dùng các ví dụ code ở trên để bắt và xử lý từng loại lỗi

Bắt đầu giải reCAPTCHA v2 với CaptchaAI. Lấy API key tại captchaai.com/api.php.


Hướng dẫn liên quan

Os comentários estão desativados para este artigo.