Tutorials

Ekstraksi Sitekey Cloudflare Turnstile

Request ke in.php balik ERROR_WRONG_USER_KEY, atau task macet lama di CAPCHA_NOT_READY? Penyebabnya sering bukan API key Anda — melainkan sitekey Turnstile yang diambil dari tempat salah, atau pageurl yang tidak cocok dengan sitekey-nya. Cloudflare Turnstile kini terpasang di ribuan situs sebagai pengganti reCAPTCHA, dan CaptchaAI butuh dua nilai yang tepat sebelum bisa menyelesaikannya: sitekey dan URL halaman.

Panduan ini membongkar tiga tempat sitekey Turnstile bisa ditemukan, sampai ke langkah solve dan pemasangan token ke formulir.


Tiga Tempat Sitekey Turnstile Bisa Ditemukan

Sitekey Turnstile tidak disembunyikan, tapi cara mengambilnya beda-beda tergantung cara situs memasang widget-nya:

Sumber sitekey Kapan muncul Butuh eksekusi JavaScript?
Atribut data-sitekey pada elemen .cf-turnstile Widget dirender langsung di HTML awal Tidak
Parameter sitekey di panggilan turnstile.render() Widget dirender dinamis lewat script, umum di single-page application Ya
Parameter sitekey di URL src iframe Turnstile Setelah widget benar-benar termuat di browser Ya, atau browser otomatis

Urutan cek paling efisien: coba Metode 1 dulu karena tidak perlu menjalankan JavaScript sama sekali. Kalau elemen .cf-turnstile kosong atau baru muncul setelah script berjalan, lanjut ke Metode 2 untuk intersepsi turnstile.render(). Kalau Anda hanya bisa mengakses DOM setelah widget termuat penuh — misalnya lewat headless browser yang menunggu event networkidle — Metode 3 lewat src iframe nyaris selalu berhasil karena sitekey wajib ada di parameter URL-nya.


Metode 1: Ambil Sitekey Langsung dari Atribut DOM

Cara paling cepat: buka console browser di halaman yang menampilkan widget Turnstile, lalu query semua elemen .cf-turnstile sekaligus. Cocok untuk pengecekan manual sebelum menulis skrip otomatisasi penuh.

// Browser console
document.querySelectorAll('.cf-turnstile').forEach((el, i) => {
  console.log(`Turnstile ${i}:`, {
    sitekey: el.getAttribute('data-sitekey'),
    action: el.getAttribute('data-action'),
    cData: el.getAttribute('data-cdata'),
    theme: el.getAttribute('data-theme'),
  });
});

Versi Python: HTML Statis vs Halaman yang Butuh Selenium

Kalau widget sudah ada di HTML awal (bukan hasil render JavaScript), regex sederhana atas response HTML sudah cukup, tanpa perlu browser sama sekali:

import re
import requests

html = requests.get("https://staging.example.com/qa-login").text

matches = re.findall(
    r'class=["\'][^"\']*cf-turnstile[^"\']*["\'][^>]*data-sitekey=["\']([^"\']+)',
    html
)
for sk in matches:
    print(f"Sitekey: {sk}")

Kalau sebaliknya — JavaScript harus jalan dulu sebelum widget muncul — pakai Selenium supaya DOM benar-benar ter-render sebelum atributnya dibaca:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")

widgets = driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile")
for w in widgets:
    sitekey = w.get_attribute("data-sitekey")
    action = w.get_attribute("data-action")
    print(f"Sitekey: {sitekey}, Action: {action}")

Metode 2: Intersepsi Panggilan turnstile.render()

Sejumlah situs tidak menaruh sitekey di HTML sama sekali — widget dirender penuh lewat JavaScript setelah halaman termuat. Sitekey tetap ada, hanya dikirim sebagai parameter ke fungsi turnstile.render():

turnstile.render('#captcha-container', {
  sitekey: '0x4AAAAAAAB...',
  callback: function(token) {
    document.getElementById('cf-token').value = token;
  },
});

Ekstrak dari sumber halaman dengan regex serupa:

# Find turnstile.render calls
render_match = re.search(
    r'turnstile\.render\s*\([^,]*,\s*\{([^}]+)\}',
    html
)
if render_match:
    config = render_match.group(1)
    sk = re.search(r'sitekey\s*:\s*["\']([^"\']+)', config)
    if sk:
        print(f"Sitekey from render: {sk.group(1)}")

Intersepsi dengan Puppeteer

Kalau sumber halaman tidak menampilkan pemanggilan itu secara statis — misalnya di-bundle lewat build tool seperti webpack — pasang hook sebelum skrip situs berjalan, supaya parameternya tertangkap begitu turnstile.render() benar-benar dipanggil:

// Intercept turnstile.render before page loads
await page.evaluateOnNewDocument(() => {
  window.__turnstileParams = [];
  const origRender = window.turnstile?.render;
  Object.defineProperty(window, 'turnstile', {
    set(val) {
      this._turnstile = val;
      const orig = val.render;
      val.render = function(container, params) {
        window.__turnstileParams.push(params);
        console.log('Turnstile render:', JSON.stringify(params));
        return orig.apply(this, arguments);
      };
    },
    get() { return this._turnstile; }
  });
});

await page.goto('https://staging.example.com/qa-login', { waitUntil: 'networkidle2' });

const params = await page.evaluate(() => window.__turnstileParams);
console.log('Captured Turnstile params:', params);

Metode 3: Ambil Sitekey dari src Iframe Turnstile

Turnstile pada akhirnya selalu merender iframe ke challenges.cloudflare.com, dan sitekey ikut terbawa sebagai parameter URL-nya. Ini fallback paling andal — kalau Metode 1 dan 2 gagal, cara ini nyaris pasti bekerja karena tidak bergantung pada bagaimana situs menaruh sitekey di kode sumbernya:

document.querySelectorAll('iframe').forEach(iframe => {
  if (iframe.src.includes('challenges.cloudflare.com')) {
    console.log('Turnstile iframe:', iframe.src);
    const match = iframe.src.match(/sitekey=([A-Za-z0-9_-]+)/);
    if (match) console.log('Sitekey:', match[1]);
  }
});

Tip: kalau ketiga metode gagal sekaligus, situs mungkin memakai widget Turnstile custom atau versi API yang lebih baru — screenshot elemennya dan cek ulang nama class-nya.


Solve Sitekey Turnstile via API CaptchaAI

Setelah sitekey dan pageurl di tangan, kirim keduanya ke in.php dengan method=turnstile, simpan task_id yang dikembalikan, lalu polling res.php setiap beberapa detik sampai statusnya berubah jadi token. Alur intinya sama seperti tipe CAPTCHA lain di CaptchaAI: kirim → simpan task ID → polling → pakai token.

Sebelum submit, cek dulu tiga hal ini supaya tidak buang waktu debug token yang ditolak:

  • Sitekey sudah diverifikasi cocok dengan halaman target, bukan hasil salin dari tab lain
  • pageurl memakai skema persis yang dibuka browser (http vs https)
  • YOUR_API_KEY disimpan di environment variable saat kode ini masuk produksi, bukan hardcode

Untuk tim otomasi kecil — freelancer scraping di Upwork/Fastwork, agensi price-monitoring, startup data lokal — paket BASIC ($15/bulan, 5 thread) biasanya cukup sebelum naik ke ADVANCE ($90/bulan, 50 thread) saat volume produksi meningkat, karena CaptchaAI menagih per thread aktif, bukan per solve. Server di region AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta) biasanya tetap punya latensi rendah ke endpoint CaptchaAI, tapi sisakan jeda polling untuk jaringan mobile-first yang kadang kurang stabil.

Contoh Kode: Python dan JavaScript

Tim yang lebih nyaman di Python bisa langsung pakai kerangka requests berikut:

import requests
import time

API_KEY = "YOUR_API_KEY"
SITEKEY = "0x4AAAAAAAB..."
PAGE_URL = "https://staging.example.com/qa-login"

# Submit
resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": SITEKEY,
    "pageurl": PAGE_URL,
    "json": "1",
}).json()

if resp["status"] != 1:
    raise Exception(f"Submit error: {resp['request']}")

task_id = resp["request"]

# Poll
for _ in range(24):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id, "json": "1"
    }).json()

    if result["status"] == 1:
        token = result["request"]
        print(f"Turnstile token: {token[:50]}...")
        break
    if result["request"] != "CAPCHA_NOT_READY":
        raise Exception(f"Error: {result['request']}")

Versi Node.js-nya sama persis alurnya, hanya di-port ke axios:

const axios = require('axios');

const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
  params: {
    key: 'YOUR_API_KEY',
    method: 'turnstile',
    sitekey: '0x4AAAAAAAB...',
    pageurl: 'https://staging.example.com/qa-login',
    json: 1,
  }
});
const taskId = submit.data.request;

// Poll for result
let token = null;
for (let i = 0; i < 24; i++) {
  await new Promise(r => setTimeout(r, 5000));
  const poll = await axios.get('https://ocr.captchaai.com/res.php', {
    params: { key: 'YOUR_API_KEY', action: 'get', id: taskId, json: 1 }
  });
  if (poll.data.status === 1) {
    token = poll.data.request;
    break;
  }
}
console.log(`Token: ${token.substring(0, 50)}...`);

Menyuntikkan Token ke Formulir

Turnstile menyimpan tokennya di hidden input bernama cf-turnstile-response. Kalau widget mendaftarkan data-callback, panggil juga callback itu secara manual — beberapa implementasi menunggu callback dipanggil dulu sebelum tombol submit aktif:

# Selenium
driver.execute_script("""
    const input = document.querySelector('input[name="cf-turnstile-response"]');
    if (input) input.value = arguments[0];

    // Also set in the Turnstile widget's callback
    const widget = document.querySelector('.cf-turnstile');
    const callbackName = widget?.getAttribute('data-callback');
    if (callbackName && typeof window[callbackName] === 'function') {
        window[callbackName](arguments[0]);
    }
""", token)

Mengatasi Masalah Umum Ekstraksi Sitekey

Sebagian besar kegagalan solve Turnstile bukan soal API CaptchaAI-nya, tapi sitekey atau pageurl yang salah diambil:

Masalah Penyebab Solusi
Elemen .cf-turnstile tidak ditemukan Widget dirender secara dinamis setelah page load Tunggu event load selesai, atau pakai MutationObserver untuk mendeteksi elemen begitu muncul
Sitekey kosong meski elemen ada Sitekey diset lewat JavaScript, bukan atribut HTML Cari pemanggilan turnstile.render di script halaman (Metode 2)
Token ditolak situs Sitekey atau pageurl tidak cocok dengan situs target Periksa ulang kedua nilai — termasuk skema http/https dan domain persis
Parameter method salah Memakai userrecaptcha alih-alih turnstile Gunakan method=turnstile saat submit ke in.php
Task macet lama di CAPCHA_NOT_READY Interval polling terlalu rapat, atau sitekey tidak valid Jaga interval polling di kisaran 3-5 detik dan validasi sitekey secara manual dulu di browser

Catatan kepatuhan: proses ekstraksi ini menyentuh halaman milik pihak lain — pastikan target Anda adalah sistem yang memang berwenang Anda uji (staging environment, sandbox internal, atau situs milik sendiri), sejalan dengan UU Pelindungan Data Pribadi (UU 27/2022) dan UU ITE. Jangan mengambil data pribadi di luar cakupan izin yang Anda miliki.


Pertanyaan Umum Seputar Sitekey Turnstile

Apa yang harus dilakukan kalau atribut data-sitekey tidak ditemukan sama sekali di HTML?

Kemungkinan besar widget-nya dirender lewat JavaScript. Coba Metode 2 (intersepsi turnstile.render()) atau Metode 3 (baca src iframe) — keduanya tidak bergantung pada atribut HTML statis.

Apakah mode managed atau non-interactive Turnstile tetap punya sitekey yang bisa diekstrak?

Ya. Mode "managed" dan "non-interactive" hanya menyembunyikan tampilan widget dari pengguna — sitekey-nya tetap tersimpan di atribut DOM, panggilan render, atau iframe seperti biasa, dan ketiga metode ekstraksi di atas bekerja sama persis.

Berapa lama CaptchaAI menyelesaikan Turnstile setelah sitekey dikirim?

Biasanya kurang dari 10 detik dengan tingkat keberhasilan tinggi pada implementasi yang didukung — lebih cepat dibanding reCAPTCHA v2 standar yang bisa mendekati 60 detik. Waktu solve aktual tetap tergantung antrean thread dan interval polling.

Apakah satu domain selalu memakai sitekey yang sama di semua halamannya?

Umumnya ya, tapi jangan diasumsikan otomatis — developer situs bisa membuat sitekey berbeda per section untuk analytics Cloudflare yang terpisah. Selalu ambil sitekey dari halaman yang benar-benar Anda targetkan.

Apakah aman kalau sitekey Turnstile ikut ter-commit ke repository publik?

Sitekey memang dirancang publik — beda dengan API key CaptchaAI, sitekey Turnstile bukan rahasia dan memang ditempel di HTML client-side. Yang tidak boleh ikut ter-commit adalah YOUR_API_KEY; simpan itu di environment variable.


Siap Solve Turnstile Secara Otomatis?

Begitu sitekey sudah di tangan, sisanya cuma satu panggilan API. Dapatkan API key CaptchaAI dan solve sitekey Turnstile pertama Anda hari ini di captchaai.com.


Panduan Terkait

Komentar dinonaktifkan untuk artikel ini.