API Tutorials

Bash + cURL + CaptchaAI: Otomatisasi CAPTCHA Shell

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)
  • jq untuk parsing JSON: apt install jq atau brew 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


Selesaikan CAPTCHA langsung dari terminal — ambil API key Anda dan mulai otomatisasi dengan Bash.

Komentar dinonaktifkan untuk artikel ini.