Ya, CAPTCHA bisa diselesaikan tanpa satu baris Python pun. Bash dan cURL sudah terpasang di hampir semua server Linux dan macOS — pilihan praktis untuk cron job atau pipeline CI/CD di VPS minim atau container Alpine, tanpa runtime tambahan yang bisa rusak setiap kali OS di-update.
Panduan ini menunjukkan cara menyelesaikan reCAPTCHA v2/v3, Cloudflare Turnstile, dan CAPTCHA gambar lewat API CaptchaAI, murni pakai Bash — dari fungsi submit-and-poll dasar sampai library captchaai.sh yang siap di-source ke skrip lain.
Kapan Bash + cURL Jadi Pilihan yang Tepat
- Tanpa dependency – Bash dan cURL sudah tersedia di setiap sistem Linux/macOS
- Ringan – tidak perlu runtime, package manager, atau langkah instalasi tambahan
- Ramah cron – jadwalkan task yang bergantung pada CAPTCHA dengan cron standar
- Siap CI/CD – langsung jalan di Docker, GitHub Actions, Jenkins, GitLab CI
- Mudah di-pipe – gabungkan penyelesaian CAPTCHA dengan
jq,grep,awk, dan tool lain di pipeline yang sama
Yang Anda Butuhkan
- Bash 4.0+
- cURL (sudah terpasang secara default di Linux/macOS)
jquntuk parsing JSON:apt install jqataubrew install jq- API key CaptchaAI (ambil di sini)
Dua Fungsi Inti: Kirim lalu Polling
Pola yang sama berlaku untuk semua tipe CAPTCHA: kirim task ke in.php, simpan task_id, lalu polling res.php sampai selesai.
Kirim Task ke API
#!/bin/bash
CAPTCHAAI_URL="https://ocr.captchaai.com"
submit_task() {
local api_key="$1"
shift
local params=("$@")
local response
response=$(curl -s -X POST "${CAPTCHAAI_URL}/in.php" \
-d "key=${api_key}" \
-d "json=1" \
"${params[@]}")
local status
status=$(echo "$response" | jq -r '.status')
local request
request=$(echo "$response" | jq -r '.request')
if [ "$status" != "1" ]; then
echo "ERROR: Submit failed: $request" >&2
return 1
fi
echo "$request"
}
Polling Sampai Task Selesai
poll_result() {
local api_key="$1"
local task_id="$2"
local max_wait="${3:-300}"
local interval="${4:-5}"
local elapsed=0
while [ "$elapsed" -lt "$max_wait" ]; do
sleep "$interval"
elapsed=$((elapsed + interval))
local response
response=$(curl -s "${CAPTCHAAI_URL}/res.php?key=${api_key}&action=get&id=${task_id}&json=1")
local status
status=$(echo "$response" | jq -r '.status')
local request
request=$(echo "$response" | jq -r '.request')
if [ "$request" = "CAPCHA_NOT_READY" ]; then
echo "Waiting... (${elapsed}s/${max_wait}s)" >&2
continue
fi
if [ "$status" != "1" ]; then
echo "ERROR: Solve failed: $request" >&2
return 1
fi
echo "$request"
return 0
done
echo "ERROR: Timeout after ${max_wait}s" >&2
return 1
}
Menyelesaikan reCAPTCHA v2 dari Bash
Fungsi ini membungkus submit_task dan poll_result: masukkan sitekey dan URL, keluarannya token siap pakai.
solve_recaptcha_v2() {
local api_key="$1"
local site_url="$2"
local sitekey="$3"
echo "Submitting reCAPTCHA v2..." >&2
local task_id
task_id=$(submit_task "$api_key" \
-d "method=userrecaptcha" \
-d "googlekey=${sitekey}" \
-d "pageurl=${site_url}")
if [ $? -ne 0 ]; then return 1; fi
echo "Task ID: $task_id" >&2
echo "Polling for solution..." >&2
local token
token=$(poll_result "$api_key" "$task_id")
if [ $? -ne 0 ]; then return 1; fi
echo "$token"
}
# Usage
API_KEY="YOUR_API_KEY"
TOKEN=$(solve_recaptcha_v2 "$API_KEY" \
"https://staging.example.com/qa-login" \
"6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-")
echo "Token: ${TOKEN:0:50}..."
Menyelesaikan Cloudflare Turnstile via cURL
Pola sama seperti reCAPTCHA v2 — hanya method dan parameter sitekey yang berbeda.
solve_turnstile() {
local api_key="$1"
local site_url="$2"
local sitekey="$3"
local task_id
task_id=$(submit_task "$api_key" \
-d "method=turnstile" \
-d "key=${sitekey}" \
-d "pageurl=${site_url}")
if [ $? -ne 0 ]; then return 1; fi
poll_result "$api_key" "$task_id"
}
# Usage
TOKEN=$(solve_turnstile "$API_KEY" \
"https://example.com/form" \
"0x4AAAAAAAB5...")
Menyelesaikan reCAPTCHA v3
reCAPTCHA v3 tanpa widget yang diklik — kirim parameter version dan action tambahan agar skor dari Google sesuai konteks halaman.
solve_recaptcha_v3() {
local api_key="$1"
local site_url="$2"
local sitekey="$3"
local action="${4:-verify}"
local task_id
task_id=$(submit_task "$api_key" \
-d "method=userrecaptcha" \
-d "googlekey=${sitekey}" \
-d "pageurl=${site_url}" \
-d "version=v3" \
-d "action=${action}" \
if [ $? -ne 0 ]; then return 1; fi
poll_result "$api_key" "$task_id"
}
Menyelesaikan CAPTCHA Gambar (OCR)
Gambar di-encode base64 lalu dikirim sebagai body; ada juga varian yang mengambil gambar langsung dari URL.
solve_image_captcha() {
local api_key="$1"
local image_path="$2"
if [ ! -f "$image_path" ]; then
echo "ERROR: File not found: $image_path" >&2
return 1
fi
local base64_data
base64_data=$(base64 -w 0 "$image_path" 2>/dev/null || base64 "$image_path")
local task_id
task_id=$(submit_task "$api_key" \
-d "method=base64" \
--data-urlencode "body=${base64_data}")
if [ $? -ne 0 ]; then return 1; fi
poll_result "$api_key" "$task_id"
}
# From URL
solve_image_from_url() {
local api_key="$1"
local image_url="$2"
local tmp_file
tmp_file=$(mktemp /tmp/captcha_XXXXXX.png)
curl -s -o "$tmp_file" "$image_url"
local result
result=$(solve_image_captcha "$api_key" "$tmp_file")
rm -f "$tmp_file"
echo "$result"
}
# Usage
TEXT=$(solve_image_captcha "$API_KEY" "captcha.png")
echo "CAPTCHA text: $TEXT"
Library Lengkap: captchaai.sh
Gabungkan semua fungsi di atas jadi satu file yang bisa Anda source dari skrip mana pun. Simpan sebagai captchaai.sh:
#!/bin/bash
# CaptchaAI Solver Library
# Source this file: source ./captchaai.sh
CAPTCHAAI_URL="https://ocr.captchaai.com"
CAPTCHAAI_POLL_INTERVAL=5
CAPTCHAAI_MAX_WAIT=300
captchaai_submit() {
local api_key="$1"; shift
local response
response=$(curl -s -X POST "${CAPTCHAAI_URL}/in.php" \
-d "key=${api_key}" -d "json=1" "$@")
local status=$(echo "$response" | jq -r '.status')
local request=$(echo "$response" | jq -r '.request')
[ "$status" = "1" ] && echo "$request" || { echo "Submit: $request" >&2; return 1; }
}
captchaai_poll() {
local api_key="$1" task_id="$2" elapsed=0
while [ "$elapsed" -lt "$CAPTCHAAI_MAX_WAIT" ]; do
sleep "$CAPTCHAAI_POLL_INTERVAL"
elapsed=$((elapsed + CAPTCHAAI_POLL_INTERVAL))
local resp=$(curl -s "${CAPTCHAAI_URL}/res.php?key=${api_key}&action=get&id=${task_id}&json=1")
local req=$(echo "$resp" | jq -r '.request')
local st=$(echo "$resp" | jq -r '.status')
[ "$req" = "CAPCHA_NOT_READY" ] && continue
[ "$st" = "1" ] && { echo "$req"; return 0; }
echo "Solve: $req" >&2; return 1
done
echo "Timeout" >&2; return 1
}
captchaai_balance() {
local api_key="$1"
curl -s "${CAPTCHAAI_URL}/res.php?key=${api_key}&action=getbalance&json=1" | jq -r '.request'
}
captchaai_recaptcha_v2() {
local key="$1" url="$2" sk="$3"
local tid=$(captchaai_submit "$key" -d "method=userrecaptcha" -d "googlekey=$sk" -d "pageurl=$url") || return 1
captchaai_poll "$key" "$tid"
}
captchaai_turnstile() {
local key="$1" url="$2" sk="$3"
local tid=$(captchaai_submit "$key" -d "method=turnstile" -d "key=$sk" -d "pageurl=$url") || return 1
captchaai_poll "$key" "$tid"
}
captchaai_image() {
local key="$1" path="$2"
local b64=$(base64 -w 0 "$path" 2>/dev/null || base64 "$path")
local tid=$(captchaai_submit "$key" -d "method=base64" --data-urlencode "body=$b64") || return 1
captchaai_poll "$key" "$tid"
}
Cara Pakai Library
Setelah di-source, semua fungsi captchaai_* langsung tersedia — termasuk cek saldo sebelum menjalankan batch:
#!/bin/bash
source ./captchaai.sh
API_KEY="YOUR_API_KEY"
# Check balance
echo "Balance: $(captchaai_balance "$API_KEY")"
# Solve reCAPTCHA v2
TOKEN=$(captchaai_recaptcha_v2 "$API_KEY" \
"https://staging.example.com/qa-login" \
"6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-")
echo "Token: ${TOKEN:0:50}..."
Kirim Formulir dengan Token dari CaptchaAI
Token dari poll_result dikirim sebagai field g-recaptcha-response di request POST berikutnya. Catatan kepatuhan: otomatisasi login atau formulir hanya untuk akun dan data yang memang berwenang Anda akses (UU PDP/UU ITE).
submit_form_with_token() {
local url="$1"
local token="$2"
shift 2
curl -s -X POST "$url" \
-d "g-recaptcha-response=${token}" \
"$@"
}
# Usage: solve then submit
TOKEN=$(captchaai_recaptcha_v2 "$API_KEY" \
"https://staging.example.com/qa-login" "SITEKEY")
RESPONSE=$(submit_form_with_token "https://staging.example.com/qa-login" \
"$TOKEN" \
-d "username=user@example.com" \
-d "password=password")
echo "Response: $RESPONSE"
Menyelesaikan CAPTCHA Paralel dengan Background Job
Skenario umum bagi tim automation yang memantau beberapa situs sekaligus (misalnya agensi price-monitoring dari VPS Singapura/Jakarta): jalankan proses & paralel lalu kumpulkan hasilnya lewat file, bukan menunggu satu per satu.
#!/bin/bash
source ./captchaai.sh
API_KEY="YOUR_API_KEY"
RESULTS_DIR=$(mktemp -d)
# Define tasks
declare -A TASKS
TASKS["site-a"]="https://site-a.com|SITEKEY_A"
TASKS["site-b"]="https://site-b.com|SITEKEY_B"
TASKS["site-c"]="https://site-c.com|SITEKEY_C"
# Launch parallel solves
pids=()
for name in "${!TASKS[@]}"; do
IFS='|' read -r url sitekey <<< "${TASKS[$name]}"
(
token=$(captchaai_recaptcha_v2 "$API_KEY" "$url" "$sitekey" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$token" > "${RESULTS_DIR}/${name}.token"
else
echo "FAILED" > "${RESULTS_DIR}/${name}.token"
fi
) &
pids+=($!)
done
# Wait for all
for pid in "${pids[@]}"; do
wait "$pid"
done
# Collect results
echo "=== Results ==="
for name in "${!TASKS[@]}"; do
token=$(cat "${RESULTS_DIR}/${name}.token")
if [ "$token" = "FAILED" ]; then
echo "$name: FAILED"
else
echo "$name: ${token:0:50}..."
fi
done
rm -rf "$RESULTS_DIR"
Coba Ulang Otomatis dengan Exponential Backoff
Untuk error sementara (slot penuh, CAPTCHA belum selesai), coba ulang dengan jeda meningkat eksponensial agar tidak membanjiri API.
solve_with_retry() {
local api_key="$1"
local solve_cmd="$2"
shift 2
local max_retries="${1:-3}"
local retryable_errors=("ERROR_NO_SLOT_AVAILABLE" "ERROR_CAPTCHA_UNSOLVABLE")
local attempt=0
while [ "$attempt" -le "$max_retries" ]; do
if [ "$attempt" -gt 0 ]; then
local delay=$((2 ** attempt + RANDOM % 3))
echo "Retry $attempt/$max_retries after ${delay}s..." >&2
sleep "$delay"
fi
local result
result=$($solve_cmd "$api_key" "${@:2}")
if [ $? -eq 0 ]; then
echo "$result"
return 0
fi
# Check if error is retryable
local is_retryable=0
for err in "${retryable_errors[@]}"; do
if echo "$result" | grep -q "$err"; then
is_retryable=1
break
fi
done
if [ "$is_retryable" -eq 0 ]; then
echo "$result"
return 1
fi
attempt=$((attempt + 1))
done
echo "Max retries exceeded" >&2
return 1
}
Menjadwalkan Lewat Cron Job
Kasus penggunaan paling umum: task harian tanpa campur tangan manusia, misalnya export data sebelum jam kerja. Sesuaikan jadwal dengan timezone server (Asia/Jakarta untuk VPS di AWS ap-southeast-3 atau GCP asia-southeast2):
# Edit crontab: crontab -e
# Run daily at 8 AM
0 8 * * * /path/to/captcha-automation.sh >> /var/log/captcha.log 2>&1
Contoh Skrip Cron
#!/bin/bash
source /path/to/captchaai.sh
API_KEY="YOUR_API_KEY"
LOG_FILE="/var/log/captcha-$(date +%Y%m%d).log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
# Check balance first
BALANCE=$(captchaai_balance "$API_KEY")
log "Balance: $BALANCE"
if (( $(echo "$BALANCE < 1.0" | bc -l) )); then
log "WARNING: Low balance!"
exit 1
fi
# Solve and process
TOKEN=$(captchaai_recaptcha_v2 "$API_KEY" \
"https://portal.example.com" "SITEKEY")
if [ $? -eq 0 ]; then
log "Solved successfully"
# Submit form, download data, etc.
curl -s "https://portal.example.com/data" \
-d "g-recaptcha-response=$TOKEN" \
-o "/data/export-$(date +%Y%m%d).csv"
log "Data exported"
else
log "ERROR: Failed to solve CAPTCHA"
exit 1
fi
Deploy dengan Docker
Bash, cURL, dan jq muat dalam image Alpine yang sangat kecil — container ini jauh lebih ringan dibanding image berbasis Python atau Node.js:
FROM alpine:3.19
RUN apk add --no-cache bash curl jq
COPY captchaai.sh /usr/local/lib/captchaai.sh
COPY automation.sh /app/automation.sh
RUN chmod +x /app/automation.sh
CMD ["/app/automation.sh"]
Kesalahan Umum dan Solusinya
Sebagian besar masalah bukan di API, tapi di environment shell tempat script jalan:
| Kesalahan | Penyebab | Solusi |
|---|---|---|
ERROR_WRONG_USER_KEY |
API key tidak valid | Verifikasi key di dashboard |
ERROR_ZERO_BALANCE |
Saldo habis | Isi ulang saldo akun |
curl: (60) SSL certificate |
Paket CA hilang | Tambahkan --cacert /path/to/ca-bundle.crt atau -k untuk pengujian |
jq: command not found |
jq belum terpasang | apt install jq atau brew install jq |
base64: invalid option -- 'w' |
Sintaks base64 versi macOS | Gunakan base64 file bukan base64 -w 0 file |
| Respons kosong | Masalah jaringan | Tambahkan flag -v ke curl untuk debugging |
Pertanyaan Umum
Apakah script ini butuh Python atau Node.js?
Tidak. Semua fungsi di panduan ini murni Bash dan cURL — cocok untuk server atau container yang cuma punya shell access.
Perlukah saya menginstal jq?
Untuk parsing JSON respons API, ya. grep dan sed bisa jadi alternatif darurat, tapi jq jauh lebih andal untuk mengekstrak field seperti status dan request.
Apakah GeeTest v4 sudah bisa diselesaikan lewat cURL?
Belum tersedia. GeeTest v3 sudah didukung dengan pola submit-and-poll yang sama seperti di panduan ini; GeeTest v4 masih berstatus "segera hadir".
Berapa biaya menjalankan otomatisasi CAPTCHA seperti ini per bulan?
CaptchaAI memakai paket berbasis thread dengan solve tanpa batas per thread, bukan biaya per-CAPTCHA. BASIC ($15/bulan, 5 thread) cukup untuk cron job skala kecil; volume lebih besar bisa naik ke ADVANCE ($90/bulan, 50 thread) atau PREMIUM ($170/bulan, 100 thread).
Bagaimana cara menyimpan API key dengan aman di server?
Gunakan environment variable: export CAPTCHAAI_KEY="..." lalu referensikan $CAPTCHAAI_KEY di script. Jangan pernah hardcode key langsung di file yang masuk version control.
Panduan Terkait
- Otomatisasi Windows dengan PowerShell + CaptchaAI
- Menggunakan cURL + CaptchaAI dari CLI
- Dokumentasi setup API key CaptchaAI
Selesaikan CAPTCHA langsung dari terminal — ambil API key Anda dan mulai otomatisasi dengan Bash.