API Tutorials

Cara Solve reCAPTCHA v2 Enterprise dengan Node.js dan CaptchaAI

Dari sisi kode Node.js, jarak antara reCAPTCHA v2 biasa dan v2 Enterprise hanya satu parameter: enterprise=1. Endpoint sama, alur sama, field token sama. Yang menjebak bukan kodenya, melainkan salah menebak jenis widget — keduanya tampak identik, tapi token tanpa flag Enterprise ditolak diam-diam oleh server target.

Apa pun halamannya, alurnya selalu empat langkah yang sama:

  1. Kirim task ke in.php dengan enterprise=1.
  2. Simpan task ID yang dikembalikan.
  3. Polling res.php sampai token siap.
  4. Pasang token sebagai g-recaptcha-response bersama form.

Sisa artikel ini membedah tiap langkah dengan kode Node.js yang bisa langsung dijalankan, lalu menutupnya dengan perhitungan kapasitas thread dan daftar kode error yang paling sering muncul.


Enterprise vs v2 standard: apa yang berbeda

  • Sumber skrip. Enterprise dari /recaptcha/enterprise.js; v2 standard dari /recaptcha/api.js.
  • Validasi backend. Token Enterprise diverifikasi lewat Google Cloud reCAPTCHA Enterprise dan sering terikat pada sebuah action.
  • Request ke CaptchaAI. Enterprise butuh enterprise=1; kirim flag itu untuk v2 standard, hasilnya gagal.

Ringkasnya:

Aspek v2 standard v2 Enterprise
Anchor /recaptcha/api2/anchor /recaptcha/enterprise/anchor
Parameter CaptchaAI tanpa flag enterprise=1
action tidak ada ikut dikirim bila ada sa=

Field yang dibaca form tetap g-recaptcha-response.


Yang perlu disiapkan

Kebutuhan Detail
API key CaptchaAI captchaai.com
Node.js 14+ fetch bawaan atau paket node-fetch
Sitekey Parameter k= di URL anchor Enterprise
URL halaman Alamat lengkap tempat CAPTCHA muncul
Action (opsional) Parameter sa= di URL anchor

Langkah 1: Pastikan halaman memakai reCAPTCHA v2 Enterprise

Buka DevTools, masuk ke tab Network, cari request anchor-nya:

https://www.google.com/recaptcha/enterprise/anchor?ar=1&k=6LdxxXXxAAAAAAcX...&sa=LOGIN&...

Penanda yang perlu dicatat:

  • /recaptcha/enterprise.js atau /enterprise/anchor — konfirmasi Enterprise.
  • Nilai k= adalah sitekey.
  • Nilai sa= (kalau ada) adalah action, misalnya LOGIN.

Kalau yang muncul /recaptcha/api2/anchor, itu v2 standard — jangan tambahkan enterprise=1.


Langkah 2: Kirim task ke endpoint in.php

Request ini mengembalikan task ID. action hanya ikut dikirim bila ada di URL anchor:

const API_KEY = "YOUR_API_KEY";

async function submitTask(sitekey, pageurl, action) {
  const params = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: sitekey,
    pageurl: pageurl,
    enterprise: "1",
    json: "1",
  });

  if (action) {
    params.set("action", action);
  }

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

  if (data.status !== 1) {
    throw new Error(`Submit failed: ${data.request}`);
  }

  console.log(`Task submitted. ID: ${data.request}`);
  return data.request;
}

Simpan task ID-nya untuk langkah berikutnya.


Langkah 3: Polling hasil lewat res.php

Beri jeda 20 detik sebelum polling pertama — lebih cepat dari itu hampir selalu mengembalikan CAPCHA_NOT_READY. Setelah itu periksa tiap 5 detik:

function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function pollResult(taskId) {
  await delay(20000);

  for (let attempt = 0; attempt < 30; attempt++) {
    const params = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

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

    if (data.status === 1) {
      console.log(`Solved. Token: ${data.request.substring(0, 60)}...`);
      return {
        token: data.request,
        userAgent: data.user_agent || "",
      };
    }

    if (data.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve failed: ${data.request}`);
    }

    console.log(`Attempt ${attempt + 1}: not ready, waiting 5s...`);
    await delay(5000);
  }

  throw new Error("Solve timed out");
}

Fungsi ini mengembalikan token dan user_agent; keduanya dipakai.

  • Jeda 20 detik di awal menghemat panggilan res.php yang pasti belum siap.
  • Interval 5 detik cukup rapat; memperkecilnya tidak mempercepat penyelesaian.
  • Batas 30 percobaan menutup alur pada sekitar 170 detik, cukup aman sebagai batas waktu worker.

Langkah 4: Pasang token ke form

Token dikirim sebagai g-recaptcha-response. Kalau respons solve menyertakan user_agent, pakai di header request agar konteks token cocok:

async function submitForm(token, userAgent) {
  const headers = { "Content-Type": "application/x-www-form-urlencoded" };

  if (userAgent) {
    headers["User-Agent"] = userAgent;
  }

  const response = await fetch("https://example.com/api/login", {
    method: "POST",
    headers,
    body: new URLSearchParams({
      username: "user",
      password: "pass",
      "g-recaptcha-response": token,
    }),
  });

  console.log(`Response status: ${response.status}`);
  return response;
}

Kalau situs memakai form HTML biasa dan bukan endpoint JSON, isi nilai token ke elemen textarea bernama g-recaptcha-response sebelum form disubmit — namanya sama, hanya cara pengirimannya yang berbeda.


Skrip lengkap yang siap dijalankan

Semua langkah dalam satu file. Ganti SITE_KEY dan PAGE_URL dengan nilai halaman Anda:

const API_KEY = "YOUR_API_KEY";
const SITE_KEY = "6LdxxXXxAAAAAAcXxxXxxX91xxxxxxxx8xxOx7A";
const PAGE_URL = "https://staging.example.com/qa-login";
const ACTION = "LOGIN"; // optional — omit if not in anchor URL

function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveRecaptchaV2Enterprise() {
  // Submit task
  const submitParams = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: SITE_KEY,
    pageurl: PAGE_URL,
    enterprise: "1",
    action: ACTION,
    json: "1",
  });

  const submitRes = await fetch(
    `https://ocr.captchaai.com/in.php?${submitParams}`
  );
  const submitData = await submitRes.json();

  if (submitData.status !== 1) {
    throw new Error(`Submit error: ${submitData.request}`);
  }

  const taskId = submitData.request;
  console.log(`Task ID: ${taskId}`);

  // Poll for result
  await delay(20000);

  for (let i = 0; i < 30; i++) {
    const pollParams = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

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

    if (pollData.status === 1) {
      return {
        token: pollData.request,
        userAgent: pollData.user_agent || "",
      };
    }

    if (pollData.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve error: ${pollData.request}`);
    }

    await delay(5000);
  }

  throw new Error("Solve timed out");
}

(async () => {
  const { token, userAgent } = await solveRecaptchaV2Enterprise();
  console.log(`Token: ${token.substring(0, 60)}...`);
  if (userAgent) console.log(`User-Agent: ${userAgent}`);
})();

Output yang diharapkan:

Task ID: 73849562810
Token: 03AGdBq24PBCqLmOx2V4pGHJjkR2xZ1r...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...

Menghitung kapasitas: thread, bukan jumlah solve

Freelancer dan agensi price-monitoring di Indonesia umumnya terbiasa dengan model bayar per solve. CaptchaAI menagih per thread bersamaan, solve tanpa batas selama bulan berjalan. Dengan penyelesaian 15–30 detik, satu thread menuntaskan sekitar 120–240 task per jam:

  • BASIC ($15/bulan, 5 thread) — sekitar 600–1200 task per jam.
  • STANDARD ($30/bulan, 15 thread) — untuk beberapa job paralel.
  • ADVANCE ($90/bulan, 50 thread) — untuk pipeline sepanjang hari.

Kalau Anda deploy di ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta), latency ke API hanya puluhan milidetik — jangan memperpendek interval polling demi mengejarnya.


Kode error dan cara menanganinya

Kode Penyebab Solusi
ERROR_WRONG_USER_KEY Format API key salah Key harus 32 karakter
ERROR_KEY_DOES_NOT_EXIST Key tidak dikenali Cek di captchaai.com
ERROR_ZERO_BALANCE Saldo habis Isi ulang akun
ERROR_BAD_TOKEN_OR_PAGEURL Sitekey atau URL salah Ambil ulang k= dari anchor
ERROR_CAPTCHA_UNSOLVABLE Task gagal Pastikan sitekey Enterprise v2
Token ditolak situs User-Agent tidak cocok Pakai user_agent dari respons solve

ERROR_ZERO_BALANCE tidak membaik dengan percobaan ulang — pisahkan penanganannya.

Aturan sederhana yang dipakai di produksi: hanya coba ulang error yang sifatnya sementara, dan hentikan sisanya sejak percobaan pertama.

  1. ERROR_CAPTCHA_UNSOLVABLE — coba ulang maksimal dua kali dengan jeda yang meningkat eksponensial, lalu catat halamannya untuk diperiksa manual.
  2. ERROR_ZERO_BALANCE dan ERROR_KEY_DOES_NOT_EXIST — hentikan worker dan kirim notifikasi; percobaan ulang hanya membuang waktu.
  3. ERROR_BAD_TOKEN_OR_PAGEURL — ambil ulang nilai k= dari URL anchor, karena sitekey bisa berubah setelah situs melakukan deploy.

Catat juga selisih waktu antara pengiriman task dan token yang diterima. Angka itu yang nanti Anda pakai untuk menghitung kebutuhan thread, bukan tebakan.


Sebelum dipakai di job produksi

  • Simpan API key di environment variable, jangan hardcode di file skrip yang ikut masuk ke repository.
  • Selesaikan CAPTCHA tepat sebelum form dikirim, bukan di awal alur — token hanya berlaku sekitar dua menit.
  • Pastikan action yang dikirim sama persis dengan nilai sa= di URL anchor, termasuk hurufnya besar-kecil.
  • Batasi jumlah task bersamaan sesuai thread paket Anda supaya antrean tidak menumpuk di sisi klien.
  • Jalankan scraping hanya pada data yang memang boleh Anda proses; UU Pelindungan Data Pribadi (UU 27/2022) membuat kebiasaan ini penting sejak tahap perancangan.

Pertanyaan yang sering muncul

Apakah token Enterprise bisa dipakai ulang?

Tidak. Token reCAPTCHA sekali pakai dan hanya berlaku sekitar dua menit. Selesaikan tepat sebelum mengirim form.

Kenapa situs menolak token yang sudah diselesaikan?

Paling umum: User-Agent tidak cocok. Token terikat pada User-Agent saat penyelesaian, jadi pakai user_agent dari respons polling. Kemungkinan kedua: token kedaluwarsa.

Bisakah skrip ini jalan di serverless seperti AWS Lambda?

Bisa, alurnya murni HTTP. Setel batas waktu function minimal 60 detik agar jeda polling 20 detik tetap muat.

Berapa thread untuk 1.000 login QA per hari?

Kalau merata, BASIC ($15/bulan, 5 thread) cukup. Kalau menumpuk, naikkan ke STANDARD ($30/bulan, 15 thread).

Bagaimana dengan hCaptcha dan FunCaptcha?

Keduanya belum didukung, jadi jangan rencanakan alur ini untuk tipe tersebut. Yang tersedia lewat endpoint yang sama: reCAPTCHA v2 dan v3 (termasuk Enterprise), Cloudflare Turnstile, dan GeeTest v3. GeeTest v4 masih segera hadir, sementara CaptchaFox, Friendly Captcha, dan Lemin tersedia dalam status beta.


Mulai jalankan alur Enterprise Anda

Ambil API key di captchaai.com, tambahkan enterprise=1 ke request v2 Anda, lalu uji lebih dulu di halaman staging milik sendiri sebelum dipakai pada job produksi.


Panduan terkait

Komentar dinonaktifkan untuk artikel ini.