Explainers

Mode Widget Cloudflare Turnstile: Managed, Non-Interaktif, Invisible

Kenapa satu form Turnstile menampilkan checkbox, form lain cuma spinner sekejap, dan form ketiga tidak menampilkan tanda widget sama sekali? Bukan bug — itu tiga mode widget yang berbeda, dan ketiganya tetap menghasilkan token cf-turnstile-response yang sama untuk di-solve.

Singkatnya:

  • Managed — Cloudflare menentukan level challenge per pengunjung, widget kadang terlihat kadang tidak.
  • Non-interactive — cuma proof-of-work di background, UI tidak pernah tampil.
  • Invisible — tidak ada container yang terlihat sama sekali di viewport.

Apakah Mode Widget Ini Memengaruhi Cara CaptchaAI Solve?

Tidak. CaptchaAI memakai method turnstile untuk ketiga mode dengan parameter yang sama: sitekey dan page URL. Yang berbeda cuma tampilan ke pengguna dan cara Anda mendeteksinya dari HTML.

Ringkasan Perbedaan Ketiga Mode

Fitur Managed Non-interactive Invisible
Widget terlihat? Terkadang Tidak pernah (hanya spinner) Tidak pernah
Butuh elemen container? Ya Ya Ya (tersembunyi)
Butuh interaksi pengguna? Terkadang (checkbox) Tidak Tidak
Ada proof-of-work challenge? Ya (bisa naik eskalasi) Ya (selalu) Ya (selalu)
Ada fallback ke checkbox interaktif? Ya Tidak (langsung gagal) Tidak (langsung gagal)
Output token cf-turnstile-response cf-turnstile-response cf-turnstile-response
Method CaptchaAI turnstile turnstile turnstile
Cocok dipakai untuk Login, registrasi Form low-friction Verifikasi background

Mode Managed: Cloudflare yang Menentukan Level Challenge

Managed adalah mode default. Cloudflare memutuskan level challenge per pengunjung berdasarkan sinyal reputasi: sebagian besar lolos tanpa UI, traffic mencurigakan melihat checkbox, traffic sangat mencurigakan bisa menghadapi challenge lebih rumit.

Implementasi

<!-- Managed mode (default) -->
<div class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-theme="light">
</div>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

Yang Dilihat Otomasi

Mode managed beradaptasi berdasarkan sinyal reputasi pemohon:

  • Kepercayaan tinggi — lolos invisible, tidak ada UI terlihat
  • Kepercayaan sedang — widget checkbox, klik untuk verifikasi
  • Kepercayaan rendah — challenge interaktif, atau blok langsung

Untuk otomasi, managed paling sering ditemui sekaligus paling sulit ditebak.

Heuristik untuk deteksi dari HTML: elemen cf-turnstile ada, tapi tidak ada atribut mode eksplisit.

def is_managed_mode(html):
    """Check if Turnstile is using managed mode (default)."""
    # Managed mode is the default — no explicit mode attribute
    has_turnstile = "cf-turnstile" in html
    has_explicit_mode = 'data-appearance="interaction-only"' in html or \
                        'data-appearance="always"' in html or \
                        'appearance: "interaction-only"' in html
    return has_turnstile and not has_explicit_mode

Mode Non-Interactive: Proof-of-Work Tanpa Checkbox

Mode ini tidak pernah menampilkan checkbox. Proof-of-work berjalan di background, dan yang muncul di layar cuma spinner loading. Kalau challenge gagal diselesaikan secara non-interactive, prosesnya langsung gagal — tidak ada eskalasi ke checkbox seperti pada mode managed. Markup-nya:

<!-- Non-interactive mode -->
<div class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-appearance="interaction-only">
</div>

Atau lewat JavaScript API:

turnstile.render('#turnstile-container', {
    sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
    appearance: 'interaction-only',
    callback: function(token) {
        document.getElementById('cf-turnstile-response').value = token;
    },
});

Alurnya di balik layar:

Page loads → Widget initializes
    ↓
Background proof-of-work runs
    ↓
Success → Token generated (no visible UI)
    OR
Failure → Widget reports error (no fallback to checkbox)

Kapan Situs Pakai Mode Ini

Skenario Kenapa non-interactive
Form komentar, widget feedback Friction harus mendekati nol
Pendaftaran newsletter Aksi bernilai rendah
API endpoint sisi browser Proteksi tanpa mengganggu UX

Mode Invisible: Container yang Sepenuhnya Tersembunyi

Mode invisible benar-benar tidak kelihatan — tidak ada elemen container yang muncul di viewport. Widget jalan otomatis saat page load (atau dipicu lewat kode), lalu menghasilkan token tanpa indikasi visual apa pun.

Implementasi

<!-- Invisible mode — container is hidden -->
<div id="turnstile-invisible"
     class="cf-turnstile"
     data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
     data-size="invisible">
</div>

Atau sepenuhnya lewat JavaScript:

// Programmatic invisible Turnstile
turnstile.render('#hidden-container', {
    sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
    size: 'invisible',
    callback: function(token) {
        // Token ready — submit form automatically
        submitForm(token);
    },
    'error-callback': function() {
        // Challenge failed
        console.error('Invisible Turnstile failed');
    },
});

Turnstile invisible lebih sulit dideteksi karena containernya tidak punya dimensi yang terlihat — perlu mengecek beberapa indikator sekaligus:

import re

def detect_invisible_turnstile(html):
    """Detect invisible Turnstile on a page."""
    indicators = {
        "script_loaded": "challenges.cloudflare.com/turnstile" in html,
        "size_invisible": 'data-size="invisible"' in html or
                          "size: 'invisible'" in html or
                          'size: "invisible"' in html,
        "api_render_call": "turnstile.render" in html,
        "response_field": "cf-turnstile-response" in html,
    }

    if indicators["script_loaded"] and indicators["size_invisible"]:
        return {"mode": "invisible", "confidence": "high"}
    elif indicators["script_loaded"] and indicators["api_render_call"]:
        return {"mode": "invisible_or_programmatic", "confidence": "medium"}
    elif indicators["response_field"]:
        return {"mode": "turnstile_present", "confidence": "low"}

    return {"mode": "none", "confidence": "high"}

Cara Ambil Sitekey, Apa Pun Mode yang Dipakai Situs

Apa pun modenya, Anda tetap butuh sitekey untuk solve. Fungsi berikut mencoba tiga pola — atribut HTML, config JavaScript, render call — sekaligus:

import re

def extract_turnstile_sitekey(html):
    """Extract Turnstile sitekey from page HTML (works for all modes)."""

    # Pattern 1: data-sitekey attribute in HTML
    match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', html)
    if match:
        return match.group(1)

    # Pattern 2: JavaScript render call
    match = re.search(r"sitekey:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
    if match:
        return match.group(1)

    # Pattern 3: Turnstile config object
    match = re.search(r"siteKey['\"]?\s*[:=]\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
    if match:
        return match.group(1)

    return None

Solve Turnstile via API CaptchaAI — Contoh Python dan Node.js

Ketiga mode di-solve dengan alur yang identik, tidak peduli mode-nya:

  1. Submit sitekey dan page URL ke in.php
  2. Simpan task ID dari respons
  3. Polling res.php tiap 5 detik sampai token siap

Python

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_turnstile(sitekey, page_url):
    """Solve any Turnstile mode — managed, non-interactive, or invisible."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": page_url,
        "json": 1,
    })

    task_id = submit.json()["request"]

    for _ in range(60):
        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.get("status") == 1:
            return result["request"]

    raise TimeoutError("Turnstile solve timed out")


# Use with any mode
token = solve_turnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
print(f"Token: {token[:50]}...")

Node.js

const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveTurnstile(sitekey, pageUrl) {
  const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method: "turnstile",
      sitekey,
      pageurl: pageUrl,
      json: 1,
    },
  });

  const taskId = submit.data.request;

  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));

    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId, json: 1 },
    });

    if (result.data.status === 1) {
      return result.data.request;
    }
  }

  throw new Error("Turnstile solve timed out");
}

// Same function works for all Turnstile modes
solveTurnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
  .then((token) => console.log("Token:", token.substring(0, 50)));

Konteks lokal: tim price-monitoring atau agency scraping freelance yang deploy dari ap-southeast-1/asia-southeast2 dan pakai banyak thread paralel — ingat CaptchaAI menagih per thread konkuren, bukan per solve, jadi BASIC ($15/bulan, 5 thread) sudah cukup untuk memantau puluhan target.


Troubleshooting: Kenapa Token Ditolak atau Widget Tidak Ketemu

  • Token valid tapi form menolaknya — sitekey salah, beda dari widget yang terlihat. Periksa sitekey yang dirender lewat JavaScript.
  • Widget tidak ditemukan di HTML — mode invisible dimuat setelah render awal. Tunggu page load penuh, periksa respons XHR.
  • Ada beberapa widget Turnstile di satu halaman — sitekey beda untuk form beda. Cocokkan sitekey dengan form yang spesifik.
  • data-size="compact" bikin deteksi salah baca — compact itu varian ukuran, bukan mode. Tetap pakai managed secara default.
  • Atribut data-action ada — itu tag analitik, bukan mode. Sertakan saat solve kalau diperlukan validasi.
  • Token kedaluwarsa sebelum disubmit — token Turnstile berlaku 300 detik. Solve sesaat sebelum submit, jangan cache.

Pertanyaan yang Sering Diajukan

Pertanyaan yang paling sering muncul seputar mode widget Turnstile:

Berapa lama waktu penyelesaian Turnstile lewat CaptchaAI?

Biasanya di bawah 10 detik dengan tingkat keberhasilan tinggi, sama untuk ketiga mode karena tantangan di level API identik.

Bagaimana cara mengetahui mode Turnstile yang dipakai sebuah situs?

Cek atribut data-appearance atau data-size di HTML: data-size="invisible" berarti invisible, data-appearance="interaction-only" berarti non-interactive, tidak ada keduanya berarti managed (default).

Apakah non-interactive berarti CAPTCHA-nya lebih mudah diselesaikan?

Tidak. Proof-of-work tetap jalan di semua mode — non-interactive cuma menyembunyikan UI-nya. Dari sisi solving, ketiganya setara.

Bisakah satu situs mengganti mode Turnstile tanpa mengubah sitekey?

Bisa. Beberapa situs pakai managed default lalu beralih ke non-interactive untuk halaman tertentu, sitekey tetap sama. Deteksi ulang mode tiap navigasi.

Mode mana yang paling sering muncul di form checkout atau login?

Managed untuk login dan registrasi. Non-interactive untuk form bernilai rendah seperti newsletter atau komentar. Invisible untuk verifikasi latar belakang yang tidak boleh mengganggu alur checkout.


Ringkasan Singkat

Tiga mode widget Cloudflare Turnstile — managed, non-interactive, invisible — mengatur pengalaman pengguna, tapi menghasilkan token cf-turnstile-response yang sama. Untuk otomasi, semua mode di-solve identik lewat Turnstile solver CaptchaAI, biasanya di bawah 10 detik dengan tingkat keberhasilan tinggi.

Yang perlu diingat:

  • Mode cuma memengaruhi tampilan, bukan parameter API atau token.
  • Deteksi mode dari data-appearance/data-size, bukan dari perilaku solve.
  • Managed paling umum tapi paling variatif; invisible paling sulit dideteksi.

Artikel Terkait

Komentar dinonaktifkan untuk artikel ini.