Begitu proyek automation tim Anda bertambah dari satu ke tiga, empat, lima repo, pola yang sama selalu muncul: tiap service menulis ulang logika submit-poll-retry ke CaptchaAI sendiri-sendiri, dan API key ikut tersebar ke setiap codebase. Jawabannya bukan menulis ulang lagi di proyek keenam, melainkan menaruh semua logika solve CAPTCHA di satu microservice FastAPI yang dipanggil lewat REST oleh service lain mana pun.
Intinya: satu microservice, satu API key, satu plan thread CaptchaAI — service lain tinggal panggil endpoint REST-nya, tidak perlu implementasi submit-poll sendiri-sendiri lagi.
Kapan Pola Microservice Ini Masuk Akal
FastAPI cocok untuk peran ini karena dukungan async-nya native — sebagian besar waktu solve CAPTCHA dihabiskan menunggu respons CaptchaAI, bukan memakai CPU, jadi event loop tetap bisa melayani request lain sambil menunggu. Panduan ini membangun microservice tersebut dari nol: endpoint REST yang submit ke CaptchaAI, polling hasil, lalu mengembalikan token yang sudah selesai untuk reCAPTCHA v2/v3, Cloudflare Turnstile, dan CAPTCHA gambar.
Tanda-tanda pola ini cocok dipakai tim Anda:
- Lebih dari satu service atau proyek klien butuh solve CAPTCHA — misalnya agensi otomatisasi kecil yang mengerjakan beberapa proyek scraping dan form-testing sekaligus.
- API key CaptchaAI mulai tersebar di banyak repo berbeda, dan tidak ada satu tempat untuk mengubah logika retry.
- Anda ingin satu plan thread dipakai bersama oleh semua proyek, bukan beli plan terpisah per proyek.
Untuk tim kecil dengan beberapa proyek berjalan paralel, plan ADVANCE ($90/bulan, 50 thread) biasanya cukup — billing CaptchaAI berbasis thread konkuren dengan solve tak terbatas per thread, jadi menambah proyek baru di belakang microservice yang sama tidak otomatis menambah biaya per CAPTCHA. Kalau Anda deploy microservice ini di region yang sama dengan service pemanggilnya, misalnya AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta) untuk tim yang server produksinya di Asia Tenggara, round-trip internal tetap rendah; waktu total tetap didominasi waktu solve CaptchaAI itu sendiri.
Prasyarat: API Key, Python, dan FastAPI + httpx
- API Key CaptchaAI — ambil di captchaai.com
- Python 3.9+
- FastAPI + httpx — untuk request HTTP async ke CaptchaAI tanpa blocking
pip install fastapi uvicorn httpx
Struktur Proyek Microservice
captcha-service/
├── main.py # FastAPI app with endpoints
├── solver.py # CaptchaAI solving logic
└── requirements.txt
Microservice ini dipecah jadi dua modul dengan tanggung jawab terpisah: solver.py menyimpan semua komunikasi dengan CaptchaAI — submit, polling, dan error handling — sementara main.py hanya mendefinisikan endpoint REST dan validasi request lewat Pydantic. Pemisahan ini memudahkan Anda menambah endpoint baru nanti, misalnya untuk GeeTest v3, tanpa menyentuh logika HTTP yang sudah teruji.
Modul solver.py: Logika Solve CaptchaAI
# solver.py
import httpx
import asyncio
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://ocr.captchaai.com"
async def submit_task(params: dict) -> str:
"""Submit a CAPTCHA task and return the task ID."""
params["key"] = API_KEY
params["json"] = 1
async with httpx.AsyncClient() as client:
response = await client.post(f"{BASE_URL}/in.php", data=params)
data = response.json()
if data.get("status") != 1:
raise ValueError(f"Submit error: {data.get('request')}")
return data["request"]
async def poll_result(task_id: str, initial_wait: int = 15, max_attempts: int = 30) -> dict:
"""Poll for the CAPTCHA result."""
await asyncio.sleep(initial_wait)
async with httpx.AsyncClient() as client:
for _ in range(max_attempts):
response = await client.get(f"{BASE_URL}/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
})
data = response.json()
if data.get("status") == 1:
return {
"token": data["request"],
"user_agent": data.get("user_agent", "")
}
if data.get("request") != "CAPCHA_NOT_READY":
raise ValueError(f"Solve error: {data['request']}")
await asyncio.sleep(5)
raise TimeoutError("Solve timed out")
async def solve_recaptcha_v2(sitekey: str, pageurl: str, enterprise: bool = False) -> dict:
params = {"method": "userrecaptcha", "googlekey": sitekey, "pageurl": pageurl}
if enterprise:
params["enterprise"] = 1
task_id = await submit_task(params)
return await poll_result(task_id, initial_wait=20)
async def solve_recaptcha_v3(sitekey: str, pageurl: str, action: str, enterprise: bool = False) -> dict:
params = {
"method": "userrecaptcha", "version": "v3",
"googlekey": sitekey, "pageurl": pageurl, "action": action
}
if enterprise:
params["enterprise"] = 1
task_id = await submit_task(params)
return await poll_result(task_id, initial_wait=20)
async def solve_turnstile(sitekey: str, pageurl: str) -> dict:
task_id = await submit_task({"method": "turnstile", "sitekey": sitekey, "pageurl": pageurl})
return await poll_result(task_id, initial_wait=10)
async def solve_image(image_base64: str) -> dict:
task_id = await submit_task({"method": "base64", "body": image_base64})
return await poll_result(task_id, initial_wait=5, max_attempts=15)
Perhatikan initial_wait berbeda di tiap fungsi solve — ini sengaja dibedakan per tipe CAPTCHA supaya microservice tidak langsung nge-poll res.php begitu task disubmit dan boros request percuma. Kalau volume trafik Anda cukup besar untuk mengukur waktu solve rata-rata sendiri, sesuaikan angka initial_wait dan max_attempts dengan data itu alih-alih memakai nilai default di atas.
main.py: Endpoint FastAPI untuk Tiap Jenis CAPTCHA
# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
import solver
app = FastAPI(title="CaptchaAI Solver Service")
class RecaptchaV2Request(BaseModel):
sitekey: str
pageurl: str
enterprise: bool = False
class RecaptchaV3Request(BaseModel):
sitekey: str
pageurl: str
action: str
enterprise: bool = False
class TurnstileRequest(BaseModel):
sitekey: str
pageurl: str
class ImageRequest(BaseModel):
image_base64: str
class SolveResponse(BaseModel):
token: str
user_agent: Optional[str] = ""
@app.post("/solve/recaptcha-v2", response_model=SolveResponse)
async def solve_recaptcha_v2(req: RecaptchaV2Request):
try:
result = await solver.solve_recaptcha_v2(req.sitekey, req.pageurl, req.enterprise)
return SolveResponse(**result)
except (ValueError, TimeoutError) as e:
raise HTTPException(status_code=502, detail=str(e))
@app.post("/solve/recaptcha-v3", response_model=SolveResponse)
async def solve_recaptcha_v3(req: RecaptchaV3Request):
try:
result = await solver.solve_recaptcha_v3(req.sitekey, req.pageurl, req.action, req.enterprise)
return SolveResponse(**result)
except (ValueError, TimeoutError) as e:
raise HTTPException(status_code=502, detail=str(e))
@app.post("/solve/turnstile", response_model=SolveResponse)
async def solve_turnstile(req: TurnstileRequest):
try:
result = await solver.solve_turnstile(req.sitekey, req.pageurl)
return SolveResponse(**result)
except (ValueError, TimeoutError) as e:
raise HTTPException(status_code=502, detail=str(e))
@app.post("/solve/image", response_model=SolveResponse)
async def solve_image(req: ImageRequest):
try:
result = await solver.solve_image(req.image_base64)
return SolveResponse(**result)
except (ValueError, TimeoutError) as e:
raise HTTPException(status_code=502, detail=str(e))
@app.get("/health")
async def health():
return {"status": "ok"}
Tiap route memvalidasi body request lewat model Pydantic sebelum menyentuh solver.py, jadi payload yang salah bentuk gagal di lapisan validasi, bukan di tengah panggilan ke CaptchaAI. Error dari solver.py (ValueError untuk kegagalan submit/solve, TimeoutError untuk polling yang habis waktu) diteruskan sebagai HTTP 502 dengan pesan spesifik di field detail, supaya service pemanggil tahu persis apa yang gagal. Endpoint /health sendiri berguna untuk readiness check load balancer atau orchestrator seperti Kubernetes.
Menjalankan Service dengan Uvicorn
uvicorn main:app --host 0.0.0.0 --port 8000
--host 0.0.0.0 wajib kalau microservice ini dijalankan di dalam container atau diakses dari service lain di jaringan yang sama — 127.0.0.1 hanya menerima koneksi dari mesin itu sendiri. Untuk trafik produksi yang lebih tinggi, tambahkan --workers N supaya Uvicorn menjalankan beberapa proses worker, atau taruh reverse proxy (nginx, Traefik) di depannya untuk load balancing dan TLS termination.
Contoh Request dan Respons
Solve reCAPTCHA v2 lewat endpoint /solve/recaptcha-v2:
curl -X POST http://localhost:8000/solve/recaptcha-v2 \
-H "Content-Type: application/json" \
-d '{"sitekey": "6Le-wvkS...", "pageurl": "https://staging.example.com/qa-login"}'
Solve Cloudflare Turnstile lewat endpoint /solve/turnstile:
curl -X POST http://localhost:8000/solve/turnstile \
-H "Content-Type: application/json" \
-d '{"sitekey": "0x4AAAA...", "pageurl": "https://example.com/form"}'
Respons:
{
"token": "03AGdBq24PBCqLmOx2V4...",
"user_agent": "Mozilla/5.0..."
}
Field token inilah yang Anda suntikkan ke g-recaptcha-response (reCAPTCHA) atau cf-turnstile-response (Turnstile) di form target, sementara user_agent opsional dipakai kalau browser automation Anda perlu menyamakan header dengan sesi yang dipakai CaptchaAI saat solve.
Checklist Hardening Sebelum Deploy ke Production
- Baca API key dari environment variable dan fail cepat saat startup jika secret tidak ada — jangan hardcode
YOUR_API_KEYseperti di contohsolver.py. - Pisahkan validasi request dari eksekusi solver agar payload yang tidak valid tidak pernah mencapai jalur outbound call ke CaptchaAI.
- Tampilkan respons error terstruktur yang membedakan kegagalan validasi, kegagalan solver, dan penolakan upstream.
- Jangan log API key atau payload penuh; cukup log task ID dan status supaya kredensial tidak ikut bocor ke log aggregator.
- Pantau jumlah request yang sedang diproses dan bandingkan dengan thread yang tersedia di plan CaptchaAI Anda — upgrade plan dulu sebelum request mulai antre.
Pemecahan Masalah Umum
Kalau microservice sudah jalan tapi hasilnya tidak sesuai ekspektasi, cek dulu empat penyebab paling umum:
- Response 502 — CaptchaAI mengembalikan error; periksa field
detailuntuk pesan spesifik. - Timeout solve — CAPTCHA makan waktu lebih lama dari perkiraan; naikkan
max_attemptsatau cek status CaptchaAI. - Connection refused — service belum berjalan; pastikan
uvicornaktif di port yang benar. - Response lambat — ada blocking I/O; pastikan
httpx.AsyncClientdipakai, bukanrequests.
Pertanyaan Umum Seputar Setup Ini
Apakah endpoint ini juga bisa dipakai untuk hCaptcha?
Belum. hCaptcha tidak didukung CaptchaAI saat ini, jadi menambah endpoint /solve/hcaptcha di main.py di atas tidak akan berfungsi — kode solver.py hanya menangani tipe yang benar-benar didukung: reCAPTCHA v2/v3, Turnstile, dan CAPTCHA gambar. Kalau proyek Anda perlu hCaptcha, itu perlu layanan terpisah.
Apakah microservice ini bisa dipasang di server Jakarta atau Singapura untuk latensi lebih rendah?
Bisa. Kode di atas tidak terikat region tertentu, jadi Anda bebas deploy di AWS ap-southeast-1, ap-southeast-3, atau GCP asia-southeast2 seperti service lain di stack Anda. Menempatkan microservice ini dekat dengan service pemanggilnya memangkas latensi jaringan internal, tapi waktu total tetap didominasi waktu solve CaptchaAI, bukan jarak ke region.
Berapa thread CaptchaAI idealnya dipakai untuk trafik microservice tim kecil?
Tergantung berapa banyak solve yang berjalan bersamaan, bukan berapa banyak proyek yang memanggil microservice ini — billing CaptchaAI berbasis thread konkuren dengan solve tak terbatas per thread. Untuk tim kecil yang baru mulai, BASIC ($15/bulan, 5 thread) atau STANDARD ($30/bulan, 15 thread) biasanya cukup; naikkan ke ADVANCE ($90/bulan, 50 thread) begitu beberapa proyek klien berjalan paralel lewat microservice yang sama.
Butuh autentikasi dan Docker sebelum masuk production?
- Autentikasi endpoint — tambahkan dependency FastAPI yang memvalidasi header
X-API-Key(atau skema OAuth2) sebelum request masuk kesolver.py, dipasang lewat parameterDepends()di tiap route, bukan diulang manual di tiap fungsi. - Docker — disarankan, terutama kalau microservice ini dipanggil banyak service lain. Image
python:3.11-slimdengan dependensi di atas sudah cukup untukDockerfilesederhana yang expose port 8000, dan memudahkan Anda menjalankan beberapa instance di belakang load balancer kalau trafik naik.
Siap Bangun Microservice CAPTCHA Anda Sendiri?
Ambil API key CaptchaAI Anda di captchaai.com, lalu jalankan solver.py dan main.py di atas sebagai titik solve CAPTCHA tunggal untuk semua service Anda — satu API key, satu plan thread, tanpa logika submit-poll yang berulang di tiap proyek.