Use Cases

Masalah CAPTCHA pada Headless Browser dan Cara Mengatasinya

Skrip scraping atau QA yang mendadak kena reCAPTCHA di headless Chrome, padahal browser biasa lolos mulus di halaman yang sama, biasanya kena satu penyebab: sinyal browser otomatis yang bocor ke halaman lewat JavaScript.

Ada dua cara menghadapinya — kurangi sinyal yang bocor supaya CAPTCHA lebih jarang muncul, atau selesaikan CAPTCHA-nya lewat API begitu terlanjur muncul. Panduan ini membahas keduanya secara langsung, plus penanganan khusus untuk Cloudflare Challenge yang butuh proxy dan cookie tambahan.

Ini relevan buat tim automation dan price-monitoring di Indonesia yang menjalankan crawler headless dari AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta).

Makin banyak instance headless yang jalan paralel, makin sering CAPTCHA muncul, dan menyelesaikannya manual satu per satu jelas tidak realistis di volume ratusan request per menit.

Tiga pendekatan yang dibahas di panduan ini:

  • Solve via API — serahkan CAPTCHA ke CaptchaAI begitu muncul; jalan sama baiknya di headless maupun headed karena solve terjadi di sisi server.
  • Kurangi sinyal deteksi — patch sinyal browser otomatis, samakan ukuran window, pakai konfigurasi standar untuk Puppeteer dan Selenium.
  • Tangani Cloudflare Challenge — kombinasikan proxy yang konsisten dengan cookie qa_validation_cookie supaya request berikutnya tetap tervalidasi.

Kenapa Headless Browser Lebih Sering Kena CAPTCHA

Metode Deteksi Apa yang Diperiksa Situs
sinyal browser otomatis Bernilai true saat browser jalan dalam mode headless
Ukuran window Headless sering pakai default 800x600
Renderer WebGL Headless mengembalikan "SwiftShader"
Chrome DevTools Protocol Port CDP terbuka
Plugin browser Tidak ada PDF viewer, Flash, dll.
Permission API Respons berbeda dibanding mode biasa
String User-Agent Ada substring "HeadlessChrome"

Begitu beberapa sinyal ini muncul bersamaan, sistem anti-bot seperti reCAPTCHA, Cloudflare, dan DataDome menurunkan trust score Anda dan langsung menyajikan CAPTCHA. Ini hasil scoring yang bisa diprediksi, bukan hukuman acak — dan itu artinya juga bisa ditekan.

Prioritaskan yang paling murah diperbaiki dulu: ukuran window dan viewport cuma butuh satu baris kode, tapi dampaknya ke trust score langsung terasa dibanding sinyal lain yang lebih dalam.

Masalah Umum per Browser dan Solusinya

Sebelum masuk ke solusi lengkap, ini referensi cepat kalau Anda cuma butuh satu baris perbaikan untuk browser tertentu:

Browser Masalah Solusi
Chrome headless sinyal browser otomatis = true Gunakan flag --disable-blink-features
Puppeteer Plugin browser tidak ada Gunakan puppeteer-extra dengan konfigurasi standar
Selenium Switch enable-automation aktif excludeSwitches: ["enable-automation"]
Playwright Sinyal browser pada WebKit Pakai channel Chromium dengan konfigurasi standar
Semua browser Ukuran viewport tidak konsisten Set ke 1920x1080 atau acak dalam rentang wajar

Tabel di atas untuk perbaikan cepat satu baris. Untuk penjelasan lengkap dan contoh kode tiap pendekatan, lanjut ke tiga bagian berikut.

Cara 1: Solve CAPTCHA Lewat API CaptchaAI

Daripada mengejar konfigurasi standar yang sempurna — yang pada akhirnya tetap bisa ditembus sistem anti-bot yang cukup canggih — cara paling stabil justru menerima kenyataan bahwa CAPTCHA akan tetap muncul, lalu menyelesaikannya lewat API saat itu terjadi. CaptchaAI solve CAPTCHA di sisi server, jadi pendekatan ini bekerja sama baiknya di headless maupun headed, apa pun sinyal browser yang bocor.

Karena solve terjadi di server CaptchaAI, tidak ada patch browser tambahan yang wajib dipasang di sisi Anda untuk pendekatan ini — cukup panggil API-nya.

Selenium (Python)

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import requests
import time

API_KEY = "YOUR_API_KEY"

options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

driver.get("https://staging.example.com/qa-login")

# Check for CAPTCHA
recaptcha = driver.find_elements("class name", "g-recaptcha")
if recaptcha:
    site_key = recaptcha[0].get_attribute("data-sitekey")

    # Solve via CaptchaAI
    resp = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": API_KEY, "method": "userrecaptcha",
        "googlekey": site_key, "pageurl": driver.current_url
    })
    task_id = resp.text.split("|")[1]

    while True:
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id
        })
        if result.text == "CAPCHA_NOT_READY": continue
        token = result.text.split("|")[1]
        break

    # Inject token
    driver.execute_script(
        f"document.getElementById('g-recaptcha-response').innerHTML = '{token}';"
    )
    driver.find_element("css selector", "form").submit()

Puppeteer (Node.js)

const puppeteer = require("puppeteer");
const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

const browser = await puppeteer.launch({ headless: "new" });
const page = await browser.newPage();
await page.goto("https://staging.example.com/qa-login");

// Check for CAPTCHA
const siteKey = await page
  .$eval(".g-recaptcha", (el) => el.getAttribute("data-sitekey"))
  .catch(() => null);

if (siteKey) {
  const submit = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: API_KEY,
      method: "userrecaptcha",
      googlekey: siteKey,
      pageurl: page.url(),
    },
  });
  const taskId = submit.data.split("|")[1];

  let token;
  while (true) {
    await new Promise((r) => setTimeout(r, 5000));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId },
    });
    if (result.data === "CAPCHA_NOT_READY") continue;
    token = result.data.split("|")[1];
    break;
  }

  await page.evaluate((t) => {
    document.getElementById("g-recaptcha-response").innerHTML = t;
  }, token);
  await page.click('button[type="submit"]');
}

Cara 2: Kurangi Frekuensi CAPTCHA Muncul

Solve via API tetap jalan di skenario apa pun, tapi kalau CAPTCHA muncul di sebagian besar request, biaya thread dan waktu tunggu ikut membengkak.

Mengurangi sinyal yang bocor menekan frekuensi itu — bukan menghilangkannya sama sekali, jadi anggap tiga langkah berikut sebagai pelengkap solve via API, bukan pengganti.

Konfigurasi Browser Standar

# Selenium
options.add_experimental_option("excludeSwitches", ["enable-automation"])
// Puppeteer
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, "webdriver", { get: () => false });
});

Set Ukuran Jendela yang Realistis

Ukuran window default headless (800x600) itu sendiri sudah jadi sinyal. Samakan dengan resolusi desktop yang umum dipakai:

# Selenium
driver.set_window_size(1920, 1080)
// Puppeteer
await page.setViewport({ width: 1920, height: 1080 });

Pakai Konfigurasi Standar untuk Puppeteer dan Selenium

# Puppeteer
npm install puppeteer-extra puppeteer-extra (mode standar)
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra (mode standar)");
puppeteer.use(StealthPlugin());
# Selenium
pip install undetected-chromedriver
import undetected_chromedriver as uc
driver = uc.Chrome(headless=True)

Kombinasi ketiganya — patch sinyal, ukuran window realistis, dan konfigurasi standar — biasanya cukup menurunkan frekuensi CAPTCHA tanpa mengubah alur scraping atau alur QA Anda sama sekali.

Cara 3: Tangani Cloudflare Challenge

Halaman tantangan Cloudflare memerlukan lebih dari sekadar token. Sebelum kirim request cloudflare_challenge, siapkan dulu:

  1. Proxy yang konsisten untuk request solve maupun request lanjutan.
  2. Tempat menyimpan cookie qa_validation_cookie hasil respons.
  3. User agent yang sama persis dipakai ulang di request berikutnya.
# CaptchaAI handles full Cloudflare challenges
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "cloudflare_challenge",
    "pageurl": "https://example.com",
    "proxy": "http://user:pass@proxy:port",
    "proxytype": "HTTP"
})
task_id = resp.text.split("|")[1]

# Result includes qa_validation_cookie cookie and user_agent
# Use both to make subsequent requests

Parameter proxy dan proxytype di atas wajib diisi untuk method cloudflare_challenge — cookie hasil validasi terikat pada IP dan user agent tempat validasi berlangsung, jadi kalau request berikutnya lewat proxy atau user agent yang berbeda, Cloudflare bisa langsung menganggapnya tidak valid.

Headless vs Headed: Kapan Masih Layak Dipakai

Headless tetap pilihan default karena lebih ringan dan tidak butuh server display seperti Xvfb di Linux. Mode headed memang menekan sebagian sinyal deteksi, tapi bukan solusi ajaib — sistem anti-bot yang canggih macam Cloudflare dan PerimeterX tetap bisa mengenali otomasi lewat sinyal lain. Karena pendekatan API CaptchaAI solve di sisi server, hasilnya sama saja dipakai di headless maupun headed, jadi keputusan headless-atau-headed lebih soal kebutuhan infrastruktur ketimbang soal CAPTCHA.

Pertanyaan Seputar CAPTCHA di Headless Browser

Apakah CaptchaAI juga bisa dipakai dengan Playwright, bukan cuma Selenium dan Puppeteer?

Bisa. Playwright memakai pendekatan yang sama karena CaptchaAI solve CAPTCHA di sisi server: ambil site key dari halaman, kirim ke in.php, polling res.php, lalu inject token lewat page.evaluate() — persis pola pada contoh Puppeteer di atas, tinggal disesuaikan API Playwright-nya.

Pola yang sama ini juga berlaku untuk framework headless lain di luar tiga yang dibahas di panduan ini, selama Anda bisa membaca data-sitekey dari DOM dan menyuntikkan token balik ke halaman.

Berapa lama waktu penyelesaian CAPTCHA saat scraping pakai headless browser?

Tergantung tipenya: reCAPTCHA v2 biasanya clear dalam waktu di bawah 60 detik, Cloudflare Challenge di bawah 15 detik, dan Cloudflare Turnstile di bawah 10 detik, dengan tingkat keberhasilan tinggi pada tipe yang didukung. Headless atau headed tidak mengubah angka ini karena solve terjadi di server CaptchaAI, bukan di browser Anda.

Apakah proxy wajib dipakai untuk menangani Cloudflare Challenge di headless browser?

Untuk method cloudflare_challenge, ya — parameter proxy dan proxytype pada contoh di atas harus diisi dengan proxy yang konsisten, karena cookie qa_validation_cookie yang dihasilkan terikat pada IP dan user agent tempat validasi berlangsung.

Bisakah konfigurasi browser saja membuat headless browser sama sekali tidak pernah kena CAPTCHA?

Tidak bisa diandalkan. Sinyal browser otomatis, ukuran window, sampai renderer WebGL bisa disamarkan satu per satu, tapi begitu volume request naik, sistem anti-bot tetap punya pola lain untuk dicurigai. Menjadikan CaptchaAI sebagai lapisan penyelesaian CAPTCHA memastikan automation Anda tetap jalan saat challenge muncul, alih-alih berharap itu tidak pernah terjadi.

Ringkasan singkat: solve via API untuk kepastian, kurangi sinyal untuk efisiensi biaya, dan tangani Cloudflare Challenge dengan proxy plus cookie yang konsisten.

Panduan Terkait

Komentar dinonaktifkan untuk artikel ini.