Anda tidak perlu melatih model OCR sendiri untuk membaca CAPTCHA gambar dari Node.js. Kirim gambarnya ke endpoint in.php milik CaptchaAI, ambil teksnya dari res.php, selesai — dua panggilan HTTP dengan axios, dan hasilnya berupa string biasa yang langsung bisa Anda isikan ke form.
CAPTCHA jenis ini, teks terdistorsi yang harus diketik ulang, memang terasa kuno, tetapi justru itulah yang paling sering ditemui pekerjaan otomatisasi sehari-hari: portal instansi, panel admin lama, dan halaman pendaftaran vendor yang belum pernah dimigrasikan ke reCAPTCHA. Banyak developer Indonesia yang mengerjakan proyek scraping atau pengisian form untuk klien menghabiskan waktu di form warisan seperti ini, bukan di tantangan modern. Seluruh kode di bawah memakai axios dan Puppeteer, dan bisa langsung Anda jalankan.
Yang perlu disiapkan lebih dulu
- API key CaptchaAI — ambil dari captchaai.com; satu key berlaku untuk semua tipe yang didukung, jadi tidak perlu key terpisah untuk OCR.
- Node.js 14+ — cukup versi yang sudah mendukung
async/await; seluruh contoh di sini memakaiaxios. - Library
axiosdanfs— tambahkanform-datajika Anda memilih cara unggah file, danpuppeteeruntuk contoh utuh di bagian akhir. - Gambar JPG, PNG, atau GIF berukuran 100 byte – 100 KB — di luar rentang itu
in.phpmenolak permintaan sebelum gambar sempat dibaca.
Satu hal soal biaya yang sebaiknya dipahami sebelum menulis kode: CaptchaAI menagih per thread, bukan per solve. Paket BASIC ($15/bulan, 5 thread) berarti lima gambar bisa diproses bersamaan tanpa biaya tambahan per gambar, sedangkan STANDARD ($30/bulan, 15 thread) memberi ruang untuk beberapa worker paralel. Untuk pekerja lepas dan agensi price monitoring yang volumenya naik-turun tiap bulan, biaya tetap semacam ini jauh lebih mudah diprediksi daripada tarif per solve.
Cara 1: kirim gambar sebagai base64
Pakai cara ini kalau gambarnya sudah ada di memori — misalnya hasil screenshot elemen Puppeteer. Baca file, encode ke base64, kirim ke in.php, lalu simpan task ID yang dikembalikan.
const axios = require('axios');
const fs = require('fs');
const API_KEY = 'YOUR_API_KEY';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// Read and encode the image
const imageB64 = fs.readFileSync('captcha.png').toString('base64');
// Submit to CaptchaAI
const { data: submitData } = await axios.post('https://ocr.captchaai.com/in.php', null, {
params: {
key: API_KEY,
method: 'base64',
body: imageB64,
json: 1,
},
});
if (submitData.status !== 1) throw new Error(submitData.request);
const taskId = submitData.request;
console.log(`Task submitted: ${taskId}`);
Ada tiga hal pada respons ini yang sering salah dibaca pemula:
status: 1hanya berarti task sudah masuk antrean, bukan berarti teksnya sudah siap.requestberisi task ID — simpan nilainya, karena itu satu-satunya pegangan untuk mengambil hasil darires.php.- Ketika
statusbukan1, isirequestberubah menjadi kode error, jadi cetak apa adanya saat debugging alih-alih menelannya diam-diam.
Cara 2: unggah file langsung dengan form-data
Kalau gambarnya ada di disk atau datang sebagai stream, form-data menghemat langkah encoding. Parameter method berubah menjadi post, sisanya identik — respons tetap mengembalikan task ID yang sama bentuknya.
const FormData = require('form-data');
const form = new FormData();
form.append('key', API_KEY);
form.append('method', 'post');
form.append('json', '1');
form.append('file', fs.createReadStream('captcha.png'));
const { data: submitData } = await axios.post('https://ocr.captchaai.com/in.php', form, {
headers: form.getHeaders(),
});
const taskId = submitData.request;
Ambil teks hasilnya lewat polling
Setelah task terkirim, beri jeda sekitar 5 detik lalu polling res.php sampai statusnya tidak lagi CAPCHA_NOT_READY. Waktu penyelesaian untuk tipe image/OCR biasanya di bawah 0.5 detik, jadi loop 30 percobaan dengan jeda 5 detik di bawah ini sudah sangat longgar; perpendek jedanya kalau alur Anda interaktif.
await sleep(5000);
let captchaText;
for (let i = 0; i < 30; i++) {
const { data: pollData } = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
});
if (pollData.status === 1) {
captchaText = pollData.request;
console.log(`CAPTCHA text: ${captchaText}`);
break;
}
if (pollData.request !== 'CAPCHA_NOT_READY') {
throw new Error(pollData.request);
}
await sleep(5000);
}
Beberapa penyesuaian yang biasanya terbayar di produksi:
- Batasi total waktu tunggu, bukan hanya jumlah percobaan, supaya satu task yang macet tidak menahan worker Anda.
- Perlakukan
ERROR_CAPTCHA_UNSOLVABLEsebagai sinyal untuk mengambil gambar baru, bukan untuk mengulang task yang sama. - Catat task ID beserta hasilnya; ID itu yang Anda butuhkan kalau nanti perlu melaporkan hasil yang salah.
Naikkan akurasi dengan parameter tambahan
Semakin banyak yang Anda beri tahu tentang bentuk CAPTCHA-nya, semakin kecil peluang salah baca. Kalau target Anda selalu berisi empat sampai enam digit angka, batasi saja ruang tebakannya.
// Digits only, 4-6 characters
const { data } = await axios.post('https://ocr.captchaai.com/in.php', null, {
params: {
key: API_KEY,
method: 'base64',
body: imageB64,
numeric: 1, // digits only
min_len: 4, // minimum length
max_len: 6, // maximum length
json: 1,
},
});
| Parameter | Nilai | Tujuan |
|---|---|---|
numeric |
1 = angka, 2 = huruf |
Membatasi karakter |
min_len / max_len |
bilangan bulat | Batasan panjang |
calc |
1 |
Menghitung ekspresi matematika |
regsense |
1 |
Peka huruf besar-kecil |
Setel parameter ini per target, bukan sekali untuk semua: satu form pendaftaran mungkin selalu memakai enam digit angka, sementara form lain memakai huruf yang peka besar-kecil. Salah menyetel numeric justru menurunkan akurasi.
Contoh utuh: dari screenshot sampai form terkirim
Potongan berikut menggabungkan semuanya — Puppeteer memuat halaman, memotret elemen CAPTCHA, mengirimkannya, menunggu teks, lalu mengetik dan submit.
const axios = require('axios');
const puppeteer = require('puppeteer');
const fs = require('fs');
const API_KEY = 'YOUR_API_KEY';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function solveImageCaptcha() {
// 1. Load page and screenshot CAPTCHA
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/register');
const captchaEl = await page.$('#captcha-image');
await captchaEl.screenshot({ path: 'captcha.png' });
// 2. Encode and submit
const imageB64 = fs.readFileSync('captcha.png').toString('base64');
const { data: submit } = await axios.post('https://ocr.captchaai.com/in.php', null, {
params: { key: API_KEY, method: 'base64', body: imageB64, json: 1 },
});
const taskId = submit.request;
// 3. Poll for text
await sleep(5000);
let text;
for (let i = 0; i < 30; i++) {
const { data: poll } = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
});
if (poll.status === 1) { text = poll.request; break; }
if (poll.request !== 'CAPCHA_NOT_READY') throw new Error(poll.request);
await sleep(5000);
}
// 4. Type and submit
await page.type('#captcha-input', text);
await page.click('form [type="submit"]');
console.log(`Solved: ${text}`);
await browser.close();
}
solveImageCaptcha().catch(console.error);
Output yang muncul di terminal:
Solved: ABC123
Kode error yang sering muncul
Empat kode berikut menutup hampir semua kegagalan yang muncul di alur image/OCR.
| Kode error | Penyebab | Penanganan |
|---|---|---|
ERROR_WRONG_FILE_EXTENSION |
Format tidak didukung | Gunakan JPG, PNG, atau GIF |
ERROR_TOO_BIG_CAPTCHA_FILESIZE |
Gambar > 100 KB | Kompres dulu sebelum dikirim |
ERROR_ZERO_CAPTCHA_FILESIZE |
Gambar < 100 byte | Periksa hasil screenshot-nya |
CAPCHA_NOT_READY |
Masih diproses | Lanjutkan polling tiap 5 detik |
Dua error ukuran file itu hampir selalu berasal dari sumber yang sama: screenshot diambil sebelum elemen CAPTCHA selesai dirender, sehingga file yang terkirim praktis kosong. Tunggu elemennya benar-benar terlihat sebelum dipotret, dan periksa ukuran file sebelum mengirim — satu baris fs.statSync menghemat banyak waktu debugging.
Urutan pemeriksaan yang cepat saat sebuah target tiba-tiba gagal:
- Buka file
captcha.pnghasil screenshot terakhir — kalau kosong atau abu-abu polos, masalahnya di Puppeteer, bukan di API. - Cocokkan ekstensi dengan isi file; elemen yang sebenarnya berupa SVG atau canvas perlu dirender dulu ke PNG.
- Periksa saldo dan jumlah thread yang sedang terpakai sebelum menyalahkan gambarnya.
Pertanyaan yang sering muncul
Berapa lama satu CAPTCHA gambar diproses?
Untuk tipe image/OCR, waktu penyelesaian tipikal di bawah 0.5 detik. Jeda 5 detik pada contoh di atas sengaja dibuat longgar agar aman untuk skrip batch; untuk alur interaktif Anda bisa memperpendeknya menjadi 1–2 detik.
Berapa banyak gambar yang bisa diproses bersamaan?
Sebanyak jumlah thread pada paket Anda. BASIC ($15/bulan) memberi 5 thread, ADVANCE ($90/bulan) memberi 50 thread, dan jumlah solve dalam satu bulan tidak dibatasi. Jadi yang perlu Anda ukur adalah concurrency worker, bukan total gambar per hari.
Apakah endpoint OCR ini juga menangani hCaptcha?
Tidak. hCaptcha dan FunCaptcha belum didukung CaptchaAI. Endpoint ini untuk CAPTCHA teks bergambar dan grid image; untuk reCAPTCHA v2, Cloudflare Turnstile, atau GeeTest v3, gunakan metode khusus masing-masing tipe.
Haruskah gambarnya disimpan ke disk dulu?
Tidak wajib. elementHandle.screenshot() dapat mengembalikan Buffer sehingga Anda langsung memanggil .toString('base64') tanpa menulis file — berguna saat kode berjalan di lingkungan serverless yang filesystem-nya read-only, misalnya fungsi yang di-deploy di region ap-southeast-3 (Jakarta).
Bagaimana cara melaporkan hasil yang salah?
Panggil https://ocr.captchaai.com/res.php?key=KEY&action=reportbad&id=TASK_ID dengan task ID terkait. Laporan ini berguna kalau satu jenis gambar konsisten salah dibaca, bukan sekadar meleset sesekali.