Integrations

Airtable + CaptchaAI: Pemecahan CAPTCHA yang Dipicu Basis Data

Anda bisa membuat Airtable menyelesaikan reCAPTCHA v2 sendiri: begitu record baru masuk ke tabel, sebuah skrip mengirim sitekey dan URL ke CaptchaAI, menunggu token, lalu menuliskannya kembali ke record itu — tanpa server terpisah, tanpa antrean manual, semua di dalam Airtable Automations dan Scripting Extension.

Banyak tim data di Indonesia memakai Airtable sebagai basis data ringan untuk price monitoring dan scraping skala kecil — sampai halaman target dilindungi CAPTCHA. Panduan ini memasang alur "record masuk → CAPTCHA selesai → token tersimpan" di Airtable, dengan reCAPTCHA v2 sebagai contoh.

Cara kerja alur yang dipicu record

Bayangkan satu tabel berisi daftar URL target, masing-masing dengan CAPTCHA yang harus diselesaikan sebelum datanya diambil. Alurnya mengikuti pola standar CaptchaAI dalam empat langkah.

Automation mendeteksi record baru, skrip mengirim parameter CAPTCHA ke CaptchaAI, menyimpan task ID, polling sampai token siap, lalu menuliskannya kembali ke record. Karena pemicunya adalah kondisi field, alur yang sama menangani record baru maupun percobaan ulang tanpa kode tambahan.

Berapa thread yang perlu Anda bayar

Pahami modelnya: CaptchaAI menagih per thread konkuren, bukan per solve, dan tiap thread mencakup solve tak terbatas sebulan penuh — tabel yang membengkak tidak menaikkan tagihan.

  • BASIC ($15/bulan, 5 thread) — cukup untuk operasi khas, beberapa puluh record per hari.
  • STANDARD ($30/bulan, 15 thread) — untuk batch besar dengan beberapa record paralel.
  • ADVANCE ($90/bulan, 50 thread) — untuk volume tinggi dan paralelisme agresif.

Harga dalam USD, per thread, bukan per CAPTCHA.

Struktur tabel yang perlu disiapkan

Buat tabel bernama CAPTCHA Tasks. Pertahankan nama field dalam bahasa Inggris persis seperti di bawah — skrip merujuknya secara literal, dan salah huruf membuat updateRecordAsync gagal.

Field Tipe Fungsi
URL URL URL halaman target
Sitekey Single line text sitekey reCAPTCHA
Status Single select pending, solving, solved, failed
Token Long text token CAPTCHA terselesaikan
Solved At Date/time stempel waktu penyelesaian
Error Single line text pesan kesalahan bila gagal

Nilai field Status wajib teks Inggris (pending, solving, solved, failed) agar cocok dengan kondisi pemicu dan skrip.

Langkah 1: buat automation-nya

Di tab Automations, klik Create automation dan beri nama "Solve CAPTCHA on New Record". Untuk pemicunya, pilih When record matches conditions, arahkan ke table CAPTCHA Tasks, lalu set kondisi Status is pending. Pemicu ini aktif setiap kali record disetel ke pending — mencakup record baru maupun yang di-solve ulang.

Langkah 2: tambahkan aksi skrip

Tambahkan aksi -> Run a script:

// Airtable Automation Script — Solve CAPTCHA via CaptchaAI

// Input configuration (set in the left panel):
// - recordId: Record ID from trigger
// - sitekey: Sitekey field from trigger
// - pageurl: URL field from trigger
const config = input.config();
const recordId = config.recordId;
const sitekey = config.sitekey;
const pageurl = config.pageurl;

const API_KEY = 'YOUR_API_KEY'; // Use input.config() for security

// Update status to "solving"
const table = base.getTable('CAPTCHA Tasks');
await table.updateRecordAsync(recordId, {
  'Status': { name: 'solving' },
});

try {
  // Step 1: Submit task to CaptchaAI
  const submitUrl = `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`;

  const submitResponse = await fetch(submitUrl);
  const submitResult = await submitResponse.json();

  if (submitResult.status !== 1) {
    throw new Error(`Submit failed: ${submitResult.request}`);
  }

  const taskId = submitResult.request;
  console.log(`Task submitted: ${taskId}`);

  // Step 2: Poll for result (wait 15 seconds first)
  await new Promise(resolve => setTimeout(resolve, 15000));

  let token = null;
  for (let i = 0; i < 20; i++) {
    const pollUrl = `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const pollResponse = await fetch(pollUrl);
    const pollResult = await pollResponse.json();

    if (pollResult.status === 1) {
      token = pollResult.request;
      break;
    }

    if (pollResult.request !== 'CAPCHA_NOT_READY') {
      throw new Error(`Solve failed: ${pollResult.request}`);
    }

    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  if (!token) {
    throw new Error('Polling timeout — CAPTCHA not solved in time');
  }

  // Step 3: Update record with solved token
  await table.updateRecordAsync(recordId, {
    'Status': { name: 'solved' },
    'Token': token,
    'Solved At': new Date().toISOString(),
    'Error': '',
  });

  console.log(`CAPTCHA solved for record ${recordId}`);

} catch (error) {
  // Update record with error
  await table.updateRecordAsync(recordId, {
    'Status': { name: 'failed' },
    'Error': error.message,
  });
  console.error(`Failed: ${error.message}`);
}

Di panel kiri, petakan variabel input: recordId ke Record ID, sitekey ke field Sitekey, pageurl ke field URL.

Langkah 3: pemrosesan batch dengan Scripting Extension

Automation memproses satu record per pemicu. Untuk banyak record sekaligus — misalnya setelah impor CSV ratusan URL — pakai Scripting Extension di panel Apps:

// Batch CAPTCHA Solver — Airtable Scripting Extension
const API_KEY = 'YOUR_API_KEY';
const table = base.getTable('CAPTCHA Tasks');

// Get all pending records
const query = await table.selectRecordsAsync({
  fields: ['URL', 'Sitekey', 'Status'],
});

const pendingRecords = query.records.filter(
  r => r.getCellValueAsString('Status') === 'pending'
);

output.text(`Found ${pendingRecords.length} pending CAPTCHAs`);

for (const record of pendingRecords) {
  const sitekey = record.getCellValueAsString('Sitekey');
  const pageurl = record.getCellValueAsString('URL');

  if (!sitekey || !pageurl) {
    output.text(`Skipping ${record.id} — missing sitekey or URL`);
    continue;
  }

  output.text(`Solving for: ${pageurl}`);

  await table.updateRecordAsync(record.id, {
    'Status': { name: 'solving' },
  });

  try {
    // Submit
    const submitResp = await fetch(
      `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`
    );
    const submitData = await submitResp.json();

    if (submitData.status !== 1) throw new Error(submitData.request);

    // Poll
    await new Promise(r => setTimeout(r, 15000));
    let token = null;

    for (let i = 0; i < 20; i++) {
      const pollResp = await fetch(
        `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${submitData.request}&json=1`
      );
      const pollData = await pollResp.json();

      if (pollData.status === 1) { token = pollData.request; break; }
      if (pollData.request !== 'CAPCHA_NOT_READY') throw new Error(pollData.request);
      await new Promise(r => setTimeout(r, 5000));
    }

    if (!token) throw new Error('Timeout');

    await table.updateRecordAsync(record.id, {
      'Status': { name: 'solved' },
      'Token': token,
      'Solved At': new Date().toISOString(),
    });
    output.text(`✓ Solved: ${pageurl}`);

  } catch (e) {
    await table.updateRecordAsync(record.id, {
      'Status': { name: 'failed' },
      'Error': e.message,
    });
    output.text(`✗ Failed: ${e.message}`);
  }
}

output.text('Batch processing complete');

Jalankan manual atau jadwalkan dari komputer Anda. Karena reCAPTCHA v2 biasanya selesai dalam belasan detik, batch besar lebih hemat sebagai antrean thread, bukan sekaligus.

Pemecahan Masalah

Masalah Penyebab Solusi
Automation tidak terpicu Status belum pending Pastikan nilai field Status sama persis, termasuk huruf kecil
fetch is not defined Sebagian konteks Airtable memakai remoteFetchAsync Ganti fetch dengan remoteFetchAsync
Skrip kena batas waktu Automation dibatasi 30 detik Kurangi iterasi polling; naikkan jeda awal ke 20 detik
Update record gagal Nama field tidak cocok Samakan persis nama field di updateRecordAsync dengan tabel
API key bocor di skrip API key ditulis langsung di kode Pakai input.config() dengan variabel input rahasia

Pertanyaan Umum

Apakah pola ini bisa untuk Cloudflare Turnstile, bukan hanya reCAPTCHA v2?

Bisa. Polanya sama — hanya method dan parameternya yang berbeda. CaptchaAI mendukung reCAPTCHA v2/v3, Cloudflare Turnstile, dan GeeTest v3, jadi cukup ganti panggilan API-nya. hCaptcha belum didukung saat ini.

Berapa thread yang saya butuhkan untuk batch Airtable?

Untuk record yang diproses berurutan, satu thread cukup. Untuk beberapa record paralel lewat Scripting Extension, jumlah thread menentukan berapa solve berjalan bersamaan. BASIC ($15/bulan) memberi 5 thread — memadai untuk operasi skala tim.

Apakah automation ikut terpicu saat record lama diperbarui?

Ya. Karena pemicunya kondisi Status pending, record mana pun yang dikembalikan ke pending akan memicu ulang alur — bukan hanya record baru. Untuk mengulang CAPTCHA yang gagal, setel saja Status-nya ke pending; tambahkan field penghitung percobaan agar tidak tanpa batas.

Artikel Terkait

Langkah Selanjutnya

Biarkan tabel Airtable menyelesaikan CAPTCHA sendiri — ambil kunci API CaptchaAI dan rangkai automation pertama Anda.

Panduan terkait:

Komentar dinonaktifkan untuk artikel ini.