DevOps & Scaling

Azure Functions + CaptchaAI: Integrasi Cloud

Kalau infrastruktur tim Anda sudah berjalan di Azure, menjalankan penyelesaian CAPTCHA CaptchaAI lewat Azure Functions adalah pilihan paling masuk akal — tidak perlu server terpisah yang harus dijaga 24 jam, cukup function yang aktif saat dipanggil.

Model ini cocok untuk tim automation dan scraping di Indonesia yang beban kerjanya naik-turun: Anda hanya membayar saat function berjalan, bukan untuk instance yang menganggur.

Empat hal yang Anda kerjakan di panduan ini:

  • Kirim task lewat HTTP trigger atau queue trigger
  • Simpan API key CaptchaAI di Key Vault, bukan di kode
  • Polling hasil dari res.php sampai token siap
  • Pakai token itu, lalu pilih paket thread CaptchaAI yang sesuai volume

Trigger HTTP: Endpoint Solve CaptchaAI di Azure Functions

Function ini menerima POST berisi method CAPTCHA (misalnya userrecaptcha untuk reCAPTCHA v2/v3) beserta site key dan page URL, lalu meneruskannya ke in.php milik CaptchaAI. Setelah task diterima, function polling ke res.php setiap 5 detik sampai token siap atau timeout 90 detik tercapai. Logika solve dan polling ada di satu fungsi solve() yang dipakai ulang oleh queue trigger berikutnya.

# function_app.py
import json
import time
import os
import logging
import urllib.request
import urllib.parse
import azure.functions as func

app = func.FunctionApp()


@app.route(route="solve", methods=["POST"])
def solve_captcha(req: func.HttpRequest) -> func.HttpResponse:
    """HTTP trigger for CAPTCHA solving."""
    try:
        body = req.get_json()
    except ValueError:
        return func.HttpResponse(
            json.dumps({"error": "JSON body required"}),
            status_code=400,
            mimetype="application/json",
        )

    method = body.get("method", "userrecaptcha")
    params = body.get("params", {})
    api_key = os.environ["CAPTCHAAI_KEY"]

    try:
        token = solve(api_key, method, params)
        return func.HttpResponse(
            json.dumps({"token": token}),
            mimetype="application/json",
        )
    except Exception as e:
        logging.error(f"Solve failed: {e}")
        return func.HttpResponse(
            json.dumps({"error": str(e)}),
            status_code=500,
            mimetype="application/json",
        )


def solve(api_key, method, params, timeout=90):
    """Solve CAPTCHA via CaptchaAI API."""
    submit_data = urllib.parse.urlencode({
        "key": api_key,
        "method": method,
        "json": 1,
        **params,
    }).encode()

    req = urllib.request.Request(
        "https://ocr.captchaai.com/in.php",
        data=submit_data,
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        result = json.loads(resp.read())

    if result.get("status") != 1:
        raise RuntimeError(f"Submit error: {result.get('request')}")

    task_id = result["request"]

    start = time.time()
    while time.time() - start < timeout:
        time.sleep(5)
        poll_url = (
            f"https://ocr.captchaai.com/res.php"
            f"?key={api_key}&action=get&id={task_id}&json=1"
        )
        with urllib.request.urlopen(poll_url, timeout=15) as resp:
            data = json.loads(resp.read())

        if data["request"] != "CAPCHA_NOT_READY":
            if data.get("status") == 1:
                return data["request"]
            raise RuntimeError(f"Solve error: {data['request']}")

    raise TimeoutError("Solve timeout")

Timeout 90 detik di atas adalah margin aman, bukan waktu rata-rata — sebagian besar tipe CAPTCHA selesai jauh lebih cepat (lihat FAQ waktu penyelesaian di bagian bawah).


Simpan API Key CaptchaAI di Azure Key Vault

Menaruh API key langsung di kode gampang bocor lewat log atau commit yang salah. Key Vault menyimpan secret terenkripsi, hanya bisa diakses identity yang diberi izin eksplisit.

Buat Vault dan Simpan Secret

Tiga perintah az berikut membuat vault, menyimpan API key CaptchaAI sebagai secret, lalu memberi izin get ke managed identity function app:

# Create Key Vault
az keyvault create \
  --name captchaai-vault \
  --resource-group myResourceGroup

# Store secret
az keyvault secret set \
  --vault-name captchaai-vault \
  --name CaptchaAIKey \
  --value "YOUR_API_KEY"

# Grant function access
az webapp identity assign \
  --name my-captcha-function \
  --resource-group myResourceGroup

az keyvault set-policy \
  --name captchaai-vault \
  --object-id <principal-id> \
  --secret-permissions get

Rujuk Secret dari Application Settings

Setelah policy aktif, referensikan secret itu langsung di application settings — Azure Functions me-resolve nilainya saat runtime tanpa API key pernah muncul di kode:

CAPTCHAAI_KEY=@Microsoft.KeyVault(SecretUri=https://captchaai-vault.vault.azure.net/secrets/CaptchaAIKey/)

Proses Batch CAPTCHA lewat Azure Queue Storage

Untuk volume tinggi, trigger HTTP satu per satu kurang efisien. Queue trigger ini membaca task dari antrean captcha-tasks, memanggil fungsi solve() yang sama, lalu menyimpan hasilnya.

@app.queue_trigger(
    arg_name="msg",
    queue_name="captcha-tasks",
    connection="AzureWebJobsStorage",
)
def process_queue_task(msg: func.QueueMessage):
    """Process CAPTCHA task from queue."""
    task = json.loads(msg.get_body().decode())
    api_key = os.environ["CAPTCHAAI_KEY"]

    try:
        token = solve(api_key, task["method"], task["params"])
        logging.info(f"Task {task['id']} solved")

        # Store result in Table Storage or return queue
        _store_result(task["id"], "success", token)

    except Exception as e:
        logging.error(f"Task {task['id']} failed: {e}")
        _store_result(task["id"], "error", str(e))


def _store_result(task_id, status, value):
    """Store result (simplified — use Table Storage in production)."""
    logging.info(f"Result: {task_id} = {status}")

Kalau solve() melempar exception, tiga hal terjadi berurutan:

  • Error dicatat ke Application Insights lewat logging.error
  • _store_result menyimpan status "error" untuk task itu
  • Azure Queue Storage menjadwalkan retry otomatis untuk pesan yang sama

Menentukan Paket Thread CaptchaAI untuk Beban Kerja Azure

CaptchaAI menagih berdasarkan jumlah thread yang aktif bersamaan, bukan per solve — begitu satu task selesai, thread itu langsung bebas mengambil task berikutnya. Jumlah pesan yang diproses paralel oleh queue trigger di atas idealnya tidak melebihi jumlah thread pada paket CaptchaAI Anda, supaya tidak ada task yang antre percuma.

Untuk tim scraping atau automation skala kecil-menengah di Indonesia — termasuk yang mengerjakan project lepas lewat Upwork atau Fastwork — pemetaan volume ke paket kurang lebih begini:

  • Di bawah 1.000 CAPTCHA/hari: BASIC ($15/bulan, 5 thread) atau STANDARD ($30/bulan, 15 thread)
  • Ribuan CAPTCHA/hari lewat queue trigger: ADVANCE ($90/bulan, 50 thread) atau PREMIUM ($170/bulan, 100 thread)

Tarif tetap ini lebih gampang diproyeksikan dibanding skema per-solve, terutama kalau beban kerja Anda musiman.


Struktur Proyek Azure Functions

Struktur project Python untuk Azure Functions cukup ringkas — satu file function_app.py untuk semua trigger, requirements.txt untuk dependency, dan dua file konfigurasi:

captcha-function/
├── function_app.py
├── requirements.txt
├── host.json
└── local.settings.json

requirements.txt

Cukup satu baris karena SDK azure-functions sudah menyediakan semua binding yang dipakai di atas:

azure-functions

host.json

Mengatur batas waktu function — defaultnya 5 menit, di sini diperpanjang ke 2 menit sesuai kebutuhan solve CAPTCHA yang bisa memakan waktu puluhan detik:

{
  "version": "2.0",
  "functionTimeout": "00:02:00",
  "logging": {
    "logLevel": {
      "default": "Information"
    }
  }
}

local.settings.json

Untuk development lokal, menyimpan API key CaptchaAI versi development, terpisah dari Key Vault produksi:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "CAPTCHAAI_KEY": "YOUR_API_KEY_FOR_LOCAL_DEV"
  }
}

Deploy Function App ke Azure

Perintah az functionapp create di bawah memakai westus2 sebagai contoh region. Setelah function app dibuat, deploy kodenya dengan Azure Functions Core Tools, lalu uji endpoint /api/solve dengan curl:

Tip: kalau tim Anda mengoperasikan automation dari Indonesia, ganti --consumption-plan-location ke region yang secara fisik lebih dekat seperti Azure Asia Tenggara (Singapura) — latensi polling ke CaptchaAI jadi sedikit lebih rendah, terutama saat volume task tinggi lewat queue trigger.

# Create function app
az functionapp create \
  --resource-group myResourceGroup \
  --consumption-plan-location westus2 \
  --runtime python \
  --runtime-version 3.11 \
  --functions-version 4 \
  --name my-captcha-solver \
  --storage-account mystorageaccount

# Deploy
func azure functionapp publish my-captcha-solver

# Test
curl -X POST https://my-captcha-solver.azurewebsites.net/api/solve \
  -H "Content-Type: application/json" \
  -d '{
    "method": "userrecaptcha",
    "params": {
      "googlekey": "SITE_KEY",
      "pageurl": "https://example.com"
    }
  }'

Kirim Task ke Antrean dari Kode Python

Script ini mengirim 10 task reCAPTCHA ke antrean captcha-tasks sekaligus — di produksi Anda mengganti range dengan daftar URL asli yang perlu diselesaikan CAPTCHA-nya, misalnya hasil crawl halaman produk atau form pendaftaran:

from azure.storage.queue import QueueClient
import json

queue = QueueClient.from_connection_string(
    conn_str="YOUR_STORAGE_CONNECTION_STRING",
    queue_name="captcha-tasks",
)

# Submit batch
for i in range(10):
    task = {
        "id": f"task-{i}",
        "method": "userrecaptcha",
        "params": {
            "googlekey": "SITE_KEY",
            "pageurl": f"https://example.com/page{i}",
        },
    }
    queue.send_message(json.dumps(task))
    print(f"Queued task-{i}")

Masalah Umum dan Cara Mengatasinya

Berikut pola masalah yang paling sering muncul saat menjalankan CaptchaAI di Azure Functions:

  • Function timeout di menit ke-5 — penyebab: batas waktu default Azure Functions. Solusi: perpanjang functionTimeout di host.json.
  • Referensi Key Vault kembali kosong — penyebab: managed identity belum diberi izin, atau policy salah. Solusi: pastikan identity function app di-assign dan Key Vault policy sudah benar.
  • Pesan antrean terus dicoba ulang — penyebab: function melempar exception yang tidak ditangani. Solusi: tangani error yang sudah dikenali, log, lalu return normal.
  • Cold start lebih dari 10 detik — penyebab: inisialisasi runtime Python dari nol. Solusi: gunakan Premium plan, atau atur FUNCTIONS_WORKER_PROCESS_COUNT.

Pertanyaan Umum seputar CaptchaAI di Azure Functions

Apakah CaptchaAI mendukung semua jenis CAPTCHA lewat Azure Functions?

Untuk tipe yang didukung CaptchaAI — reCAPTCHA v2/v3, Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3, CAPTCHA gambar/grid, dan BLS — semuanya lewat endpoint in.php/res.php yang sama seperti pada contoh kode di atas, tinggal ganti parameter method. hCaptcha dan FunCaptcha (Arkose Labs) belum didukung, dan GeeTest v4 masih berstatus segera hadir. CaptchaFox, Friendly Captcha, dan Lemin sudah bisa dipakai tapi masih berstatus beta.

Paket Consumption atau Premium — mana yang cocok untuk beban kerja CAPTCHA?

Untuk volume rendah (di bawah 100 solve/hari) paket Consumption sudah cukup dan lebih hemat karena Anda hanya membayar saat function berjalan. Begitu beban kerja stabil dan tinggi, paket Premium lebih masuk akal — instance tetap warm sehingga cold start hilang, dan Anda dapat integrasi VNET kalau CaptchaAI dipanggil dari jaringan privat.

Berapa lama waktu yang dibutuhkan satu task CAPTCHA sampai selesai?

Tergantung tipenya. Cloudflare Turnstile biasanya selesai di bawah 10 detik, reCAPTCHA v3 di bawah 4 detik, dan reCAPTCHA v2 standar di bawah 60 detik, dengan tingkat keberhasilan tinggi pada tipe yang didukung. Timeout 90 detik pada fungsi solve() di atas memberi margin aman bahkan untuk tipe yang paling lambat.

Apakah region Azure memengaruhi kecepatan polling ke CaptchaAI?

Ya, meskipun efeknya kecil dibanding waktu solve CAPTCHA itu sendiri. Kalau tim Anda mengoperasikan automation dari Indonesia, deploy function app ke region yang lebih dekat seperti Azure Asia Tenggara (Singapura) mengurangi latensi round-trip saat polling res.php dibanding region default seperti westus2 pada contoh deploy. Untuk volume tinggi lewat queue trigger, perbedaan ini bisa terasa di total waktu pemrosesan batch.

Apa yang terjadi kalau task CAPTCHA di queue gagal terus-menerus?

Azure Queue Storage otomatis mencoba ulang pesan yang gagal sampai batas dequeue tercapai. Karena fungsi process_queue_task di atas menangkap exception dan mencatat statusnya lewat _store_result, Anda bisa memantau task yang gagal berulang dari log Application Insights alih-alih menebak-nebak dari luar.


Panduan Terkait


Bangun automation serverless Anda di Azure — dapatkan API key CaptchaAI dan solve CAPTCHA pertama Anda hari ini.

Komentar dinonaktifkan untuk artikel ini.