API Tutorials

Rotasi API Key CaptchaAI: Manajemen Multi-Kunci

Satu API key menangani seluruh traffic solve CAPTCHA Anda? Itu single point of failure yang siap meledak kapan saja — begitu key kehabisan saldo, kena rate limit, atau dinonaktifkan, seluruh pipeline scraping atau otomatisasi Anda berhenti total, bukan melambat. Tim otomatisasi dan agency scraping yang menjalankan beberapa akun CaptchaAI sekaligus (lumrah di kerja lepas) baru sadar soal ini justru saat volume sedang tinggi.

Solusinya bukan mencari satu key raksasa yang "cukup untuk semua", tapi merotasi beberapa key sekaligus dengan failover otomatis begitu salah satu bermasalah. Panduan ini membahas tiga strategi rotasi — round-robin, weighted balance-aware, dan failover — plus cara menyimpan key dengan aman dan menjadwalkan refresh saldo, lengkap dengan kode Python dan JavaScript yang bisa langsung dipakai.

Alur singkat memilih strategi yang tepat:

  1. Saldo antar akun selalu Anda top up bersamaan dan jumlahnya sedikit → mulai dari round-robin.
  2. Saldo antar akun mulai timpang, atau jumlah key sudah lebih dari tiga → naik ke weighted balance-aware.
  3. Berapa pun jumlah key-nya → tambahkan failover di atas keduanya, supaya kegagalan satu key tidak menjalar ke aplikasi utama.

Sebelum lanjut: jangan commit API key ke Git, sekalipun ke repo privat. Sekali ter-push, anggap key itu bocor — nonaktifkan dan ganti lewat dashboard CaptchaAI.


Strategi 1: Rotasi Round-Robin

Strategi paling sederhana: telusuri key satu per satu secara merata, tanpa melihat saldo atau beban masing-masing.

Cocok untuk mulai cepat sebelum Anda benar-benar butuh logic yang lebih pintar.

Python

import itertools
import requests

API_KEYS = [
    "KEY_ACCOUNT_1",
    "KEY_ACCOUNT_2",
    "KEY_ACCOUNT_3",
]

key_cycle = itertools.cycle(API_KEYS)


def get_next_key():
    return next(key_cycle)


def solve_captcha(sitekey, page_url):
    api_key = get_next_key()
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": "1",
    })
    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"[{api_key[:8]}...] {data['request']}")

    print(f"Submitted with key {api_key[:8]}...")
    return data["request"], api_key


task_id, used_key = solve_captcha("6Le-SITEKEY", "https://example.com")

Praktis untuk dua sampai tiga key dengan saldo yang selalu Anda top up bersamaan. Masalahnya muncul begitu satu akun kena traffic lebih besar dari yang lain — round-robin tidak tahu, dan tetap membagi rata.


Strategi 2: Rotasi Tertimbang Berbasis Saldo (Balance-Aware)

Round-robin memperlakukan semua key setara, padahal saldo tiap akun jarang sama persis.

Rotasi tertimbang mengarahkan traffic lebih besar ke key dengan saldo lebih tinggi, sekaligus otomatis menyisihkan key yang saldonya nol atau terus-menerus error. Strategi ini mulai masuk akal begitu Anda mengelola lebih dari dua atau tiga akun CaptchaAI sekaligus.

import random
import requests
import threading

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


class KeyRotator:
    def __init__(self, keys):
        self.keys = {k: {"balance": 0, "failures": 0, "disabled": False} for k in keys}
        self._lock = threading.Lock()
        self.refresh_balances()

    def refresh_balances(self):
        for key in self.keys:
            try:
                resp = requests.get(RESULT_URL, params={
                    "key": key, "action": "getbalance", "json": "1"
                }, timeout=10).json()
                if resp["status"] == 1:
                    self.keys[key]["balance"] = float(resp["request"])
                    self.keys[key]["disabled"] = False
                else:
                    self.keys[key]["disabled"] = True
            except Exception:
                self.keys[key]["disabled"] = True

    def get_key(self):
        with self._lock:
            available = {
                k: v for k, v in self.keys.items()
                if not v["disabled"] and v["balance"] > 0.01
            }
            if not available:
                raise Exception("No API keys with balance available")

            # Weighted random by balance
            keys = list(available.keys())
            weights = [available[k]["balance"] for k in keys]
            return random.choices(keys, weights=weights, k=1)[0]

    def report_failure(self, key, error_code):
        with self._lock:
            self.keys[key]["failures"] += 1
            if error_code in ("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST",
                              "ERROR_ZERO_BALANCE", "ERROR_IP_NOT_ALLOWED"):
                self.keys[key]["disabled"] = True
                print(f"[rotator] Disabled key {key[:8]}...: {error_code}")

    def report_success(self, key, cost=0.003):
        with self._lock:
            self.keys[key]["balance"] -= cost
            self.keys[key]["failures"] = 0


rotator = KeyRotator(["KEY_1", "KEY_2", "KEY_3"])

# Usage
api_key = rotator.get_key()
# ... solve captcha ...
rotator.report_success(api_key)

Kelas KeyRotator di atas memakai random.choices dengan bobot saldo — key bersaldo $50 punya peluang terpilih jauh lebih besar dibanding key bersaldo $2, tanpa Anda perlu menghitung manual setiap kali.


Strategi 3: Rotasi dengan Failover Otomatis

Rotasi tertimbang menentukan key mana yang dipakai. Failover menentukan apa yang terjadi kalau key itu gagal di tengah jalan — network timeout, saldo tiba-tiba habis, atau key dinonaktifkan dari sisi CaptchaAI.

Alih-alih meneruskan error itu ke aplikasi utama, sistem otomatis mencoba key berikutnya sampai batas percobaan tercapai.

Python

def solve_with_failover(sitekey, page_url, max_attempts=3):
    for attempt in range(max_attempts):
        api_key = rotator.get_key()
        try:
            resp = requests.post(SUBMIT_URL, data={
                "key": api_key,
                "method": "userrecaptcha",
                "googlekey": sitekey,
                "pageurl": page_url,
                "json": "1",
            }, timeout=15)
            data = resp.json()

            if data["status"] != 1:
                rotator.report_failure(api_key, data["request"])
                continue

            rotator.report_success(api_key)
            return data["request"], api_key

        except requests.RequestException:
            rotator.report_failure(api_key, "NETWORK_ERROR")
            continue

    raise Exception(f"All {max_attempts} keys failed")

JavaScript

const axios = require('axios');

class KeyRotator {
  constructor(keys) {
    this.keys = keys.map(k => ({ key: k, disabled: false, failures: 0 }));
    this.index = 0;
  }

  getKey() {
    const available = this.keys.filter(k => !k.disabled);
    if (available.length === 0) throw new Error('No API keys available');
    const entry = available[this.index % available.length];
    this.index++;
    return entry.key;
  }

  disable(key, reason) {
    const entry = this.keys.find(k => k.key === key);
    if (entry) {
      entry.disabled = true;
      console.log(`[rotator] Disabled ${key.substring(0, 8)}...: ${reason}`);
    }
  }
}

const rotator = new KeyRotator(['KEY_1', 'KEY_2', 'KEY_3']);

async function solveWithFailover(sitekey, pageurl, maxAttempts = 3) {
  for (let i = 0; i < maxAttempts; i++) {
    const apiKey = rotator.getKey();
    try {
      const resp = await axios.post('https://ocr.captchaai.com/in.php', null, {
        params: { key: apiKey, method: 'userrecaptcha', googlekey: sitekey, pageurl, json: 1 }
      });
      if (resp.data.status !== 1) {
        rotator.disable(apiKey, resp.data.request);
        continue;
      }
      return { taskId: resp.data.request, apiKey };
    } catch (err) {
      rotator.disable(apiKey, 'NETWORK_ERROR');
    }
  }
  throw new Error('All keys failed');
}

Masalah Umum Saat Rotasi Key Gagal

Masalah Penyebab Solusi
Semua key dinonaktifkan Saldo nol di semua akun sekaligus Top up akun, cek log ERROR_ZERO_BALANCE
Selalu memakai key yang sama Indeks round-robin tidak aman dipanggil dari banyak thread Bungkus akses indeks dengan lock, seperti pada KeyRotator
Key dinonaktifkan padahal masih valid Error sementara (network, timeout) dianggap permanen Nonaktifkan permanen hanya untuk ERROR_WRONG_USER_KEY, ERROR_ZERO_BALANCE, ERROR_IP_NOT_ALLOWED
Saldo yang tercatat meleset dari saldo asli Race condition saat beberapa thread membaca-tulis saldo bersamaan Gunakan lock yang sama untuk operasi baca dan tulis saldo, jangan hanya salah satunya

Simpan API Key di Environment Variable, Bukan Hardcode

Jangan pernah hardcode API key langsung di kode sumber — terutama kalau repo Anda pernah, atau akan, di-commit ke Git publik atau dibagikan ke tim lepas. Muat key dari environment variable saat aplikasi start:

import os

API_KEYS = os.environ["CAPTCHAAI_KEYS"].split(",")
# Set: CAPTCHAAI_KEYS=key1,key2,key3
rotator = KeyRotator(API_KEYS)

Pola yang sama berlaku untuk stack Node.js — baca daftar key dari process.env, jangan dari file konfigurasi yang ikut ter-commit:

const API_KEYS = process.env.CAPTCHAAI_KEYS.split(',');
const rotator = new KeyRotator(API_KEYS);

Jadwalkan Refresh Saldo untuk Proses Long-Running

Untuk proses yang jalan berhari-hari — worker scraping, cron job, atau service otomatisasi yang selalu aktif — saldo tiap key bisa berubah jauh di antara pengecekan pertama dan sekarang. Refresh saldo secara berkala, bukan cuma sekali di awal, supaya rotator tidak terus-menerus mengarahkan traffic ke key yang sebenarnya sudah habis. Ini makin relevan kalau infrastruktur Anda berjalan di region dengan latensi ke API CaptchaAI yang perlu diperhitungkan — misalnya deployment di AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta), dua region yang umum dipakai tim otomatisasi dan scraping Indonesia.

import threading

def periodic_refresh(rotator, interval=300):
    def refresh():
        while True:
            rotator.refresh_balances()
            for key, info in rotator.keys.items():
                print(f"  {key[:8]}...: ${info['balance']:.2f} "
                      f"{'(disabled)' if info['disabled'] else '(active)'}")
            threading.Event().wait(interval)

    t = threading.Thread(target=refresh, daemon=True)
    t.start()

periodic_refresh(rotator, interval=300)  # every 5 minutes

Interval 300 detik pada contoh di atas cocok untuk kebanyakan kasus. Kalau volume Anda kecil, naikkan ke 600–900 detik supaya panggilan getbalance tidak sia-sia.


Berapa Banyak Key yang Masuk Akal untuk Tim Anda

Jumlah key yang ideal mengikuti volume, bukan angka baku:

  • Proyek freelance atau automation kecil — dua key sudah cukup sebagai failover dasar; begitu satu bermasalah, yang lain langsung menggantikan tanpa aplikasi utama sempat tahu.
  • Agency scraping dengan beberapa klien paralel — tiga sampai lima key mulai masuk akal untuk distribusi beban yang lebih rata antar proyek.
  • Tim price-monitoring yang tembus ribuan solve per hari — kombinasikan weighted rotation dengan failover sejak awal, jangan tunggu satu key kolaps duluan.

Ada juga sisi biaya yang sering luput dari perhitungan. Menjalankan dua akun BASIC ($15/bulan, 5 thread) paralel lewat rotator memberi total 10 thread dengan biaya $30/bulan — throughput-nya di bawah satu akun STANDARD ($30/bulan, 15 thread), tapi Anda dapat redundansi bawaan: kalau satu akun bermasalah, yang lain tetap jalan. Trade-off ini yang membuat rotasi multi-key relevan bukan cuma soal skala, tapi juga keandalan harian — terutama bagi tim freelance dan agency kecil yang sensitif biaya.


Pertanyaan Umum

Berapa banyak API key idealnya untuk mulai rotasi?

Mulai dari dua key untuk failover dasar. Begitu volume solve harian menembus angka ribuan, atau Anda menjalankan lebih dari satu proyek klien sekaligus, tiga sampai lima key membuat distribusi beban jauh lebih merata dibanding mengandalkan satu key besar.

Apakah rotasi key aman dipakai di aplikasi multi-thread atau multi-process?

Aman, selama Anda membungkus operasi baca-tulis saldo dan status key dengan lock — seperti pada contoh KeyRotator di atas. Tanpa lock, dua thread bisa membaca saldo yang sama dan salah menentukan key yang seharusnya dinonaktifkan.

Kapan sebaiknya pakai round-robin, dan kapan pindah ke weighted balance-aware?

Round-robin cukup untuk dua-tiga key dengan saldo yang selalu Anda top up bersamaan. Begitu saldo antar akun mulai timpang — satu akun baru diisi, satu lagi hampir habis — weighted rotation mencegah key yang hampir kosong tetap kebagian traffic penuh.

Bisakah key dari beberapa akun CaptchaAI yang berbeda digabung dalam satu rotator?

Bisa. Setiap key punya saldo dan rate limit sendiri-sendiri, dan rotator memprosesnya secara independen — tidak masalah apakah semua key berasal dari satu akun atau beberapa akun terpisah.

Apa yang terjadi kalau semua key kehabisan saldo secara bersamaan?

Rotator akan melempar error (No API keys with balance available pada contoh Python di atas) alih-alih diam-diam gagal. Tangkap error ini di level aplikasi untuk memicu notifikasi top up, bukan membiarkan job scraping Anda berhenti tanpa keterangan.


Bangun Rotasi Multi-Key yang Tahan Gangguan

Ambil API key Anda di captchaai.com dan mulai distribusikan traffic solve CAPTCHA ke lebih dari satu key sejak hari pertama.

Butuh kurang dari satu jam untuk memasang round-robin sederhana; tambahkan weighted rotation dan failover begitu volume benar-benar menuntutnya.


Panduan Terkait

Komentar dinonaktifkan untuk artikel ini.