Troubleshooting

Turnstile Token'ı Çözümden Sonra Geçersiz: Teşhis ve Düzeltmeler

Kısa cevap: token'ınız bozuk değil, geç kalmış ya da yanlış yere konmuş. CaptchaAI turnstile yöntemi cf-turnstile-response döndürdüyse çözüm tamamlanmıştır; 403'ün nedeni token'ın ömrü, ait olduğu widget, gönderildiği alan ya da eşleştiği oturumdur. Altı nedeni sırayla eleyin.

Tipik vaka: ödeme adımını test eden bir e-ticaret ekibinde Europe/Istanbul saatinde gece çalışan QA işi sabah loglarına yüzlerce 403 bırakıyor; aynı script öğlen elle sorunsuz geçiyor. Fark, kuyrukta bekleyen token'ların ölmesidir.


Belirtiden nedene: hızlı eşleştirme

Görünen belirti hangi nedene bakacağınızı söyler.

Gözlemlediğiniz durum Muhtemel neden
Token gönderildikten sonra site 403 dönüyor Token'ın süresi gönderimden önce doldu
Form sessizce başarısız oluyor, hata yok Token yanlış alan adıyla gönderiliyor
Token kabul ediliyor ama işlem engelleniyor Sitekey uyuşmazlığı — yanlış widget çözüldü
İlk denemede çalışıyor, tekrarında düşüyor Token tek kullanımlık, yeniden kullanıldı
Tarayıcıda çalışıyor, script'te çalışmıyor Eksik çerez veya oturum bağlamı

İlk 30 saniyede toplayacağınız üç veri

Tabloyu doğru satırda kullanabilmek için şu üç veriyi loglayın:

  • Gecikme: token'ın CaptchaAI'den döndüğü an ile hedef siteye ulaştığı an arasındaki fark, milisaniye cinsinden.
  • sitekey: çözüm isteğine gerçekten yazdığınız değer — sayfada gördüğünüz değil.
  • Alan adı: gönderim gövdesinde token'ı taşıyan anahtarın tam adı.

Bu üçü elinizdeyken altı nedenden dördü tek bakışta elenir; kalan ikisi oturum ve action tarafındadır.

Log satırınızı Europe/Istanbul damgasıyla tutun. Gece koşan işlerde 403'lerin saat başına kümelenmesi, sorunun kodda değil kuyruk gecikmesinde olduğunu tek grafikle gösterir.


Token gönderilmeden önce öldü

Turnstile token'ları kısa ömürlüdür — tipik olarak 300 saniye (5 dakika), bazen daha kısa. Sorgulama ile gönderim arasına kuyruk, yeniden deneme veya sleep girerse token ölü gönderilir. Düzeltme: token'ı aldığınız satırda kullanın, ara belleğe yazmayın.

import requests
import time

API_KEY = "YOUR_API_KEY"

# Submit Turnstile task
submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": "0x4AAAAAAADnPIDROz1234",
    "pageurl": "https://staging.example.com/qa-login",
    "json": 1
}).json()

task_id = submit["request"]
time.sleep(10)

# Poll for result
for _ in range(24):
    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:
        token = result["request"]
        # USE TOKEN IMMEDIATELY — do not delay
        response = requests.post("https://staging.example.com/qa-login", data={
            "username": "user",
            "password": "pass",
            "cf-turnstile-response": token
        })
        break
    time.sleep(5)

Toplu işte önce hepsini çözüp sonra göndermeyin; her istek token'ını kendi anında alsın. Eşzamanlılığı thread sayınız belirler — BASIC ($15/ay, 5 thread) ile beş çözüm aynı anda akar. Darboğazda plan yükseltin: faturalama thread başınadır, çözüm sınırsızdır.


Yanlış widget'ın sitekey'i çözüldü

Her widget'ın kendi sitekey'i vardır. Sayfada birden fazla widget varsa — biri bülten kaydında, diğeri giriş formunda — yanlış anahtarla üretilen token geçerlidir ama form onu tanımaz. Doğru anahtarı okumak için:

// In browser console on the target page
document.querySelectorAll('[data-sitekey]').forEach(el => {
    console.log('Sitekey:', el.getAttribute('data-sitekey'));
    console.log('Element:', el);
});

Birden fazla sonuç dönüyorsa gönderdiğiniz <form> içindeki widget'ın anahtarını seçin. Anahtarı ortam değişkeninden okumak sessiz kırılmayı önler.


Alan adı cf-turnstile-response değil

Turnstile token'ı cf-turnstile-response alanında bekler; g-recaptcha-response reCAPTCHA'ya aittir. reCAPTCHA kodundan kopyalanan fonksiyonlarda en sık hata budur.

# WRONG — this is for reCAPTCHA
data = {"g-recaptcha-response": token}

# CORRECT — this is for Turnstile
data = {"cf-turnstile-response": token}

Bazı siteler özel alan adı kullanır; gerçek alanı formdan doğrulayın:

// Check what field the Turnstile widget populates
document.querySelector('[name*="turnstile"], [name*="cf-"]')

Aynı token ikinci kez yakıldı

Turnstile token'ları tek kullanımlıktır. Yeniden deneme aynı gövdeyi tekrarlıyorsa ikinci deneme reddedilir. Düzeltme: her denemede yeni çözüm alın; üstel geri çekilme (exponential backoff) kullanıyorsanız token alma adımı döngünün içinde kalmalıdır.

Bu hata en çok HTTP istemcisinin otomatik yeniden deneme özelliğinde saklanır: requests oturumuna bağladığınız bir retry adapter'ı, gövdeyi olduğu gibi tekrar gönderir ve token'ı ikinci kez yakar.

Yeniden denemeyi hangi katmanda yönetmeli

Katman Token açısından sonuç
Ağ/adapter seviyesinde otomatik retry Aynı gövde tekrar gider, token yakılır — kapatın
Uygulama katmanında elle retry Her denemede yeni çözüm alınır — tercih edilen
Kuyruk seviyesinde görev tekrarı Görev yeniden çözülür, güvenli — token kuyruğa yazılmadıysa

Kısacası: yeniden deneme kararını token'ı üreten fonksiyonun dışına asla çıkarmayın.


Oturum bağlamı sayfa ile gönderim arasında koptu

Cloudflare token'ı oturum çerezleriyle değerlendirebilir. Sayfayı bir istemciyle yükleyip token'ı başkasıyla gönderirseniz reddedilir; aynı hata ayrı worker kullanan mimarilerde de çıkar.

# Use the SAME session for page load and token submission
session = requests.Session()

# Load the page first to establish cookies
session.get("https://staging.example.com/qa-login")

# Then solve and submit using the same session
token = solve_turnstile(sitekey, pageurl)
session.post("https://staging.example.com/qa-login", data={
    "cf-turnstile-response": token
})

Ayrı worker mimarilerinde ne yapmalı

  • Sayfa yükleme ve gönderim işini aynı worker içinde tutun.
  • Bu mümkün değilse çerez kavanozunu (session.cookies) serileştirip gönderimi yapan worker'a taşıyın.
  • Çerezleri paylaşamıyorsanız gönderimden hemen önce sayfayı gönderen istemciyle bir kez daha yükleyin.

action ve cData eşleşmiyor

Bazı kurulumlar token'a bağlı action veya cData taşır. Site bunları bekliyorsa çözüm isteğinde de gönderin; aksi halde token üretilir ama bağlamı tutmaz.

submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": "0x4AAAAAAADnPIDROz1234",
    "pageurl": "https://staging.example.com/qa-login",
    "action": "login",           # If required by the site
    "data": "custom_cdata_value", # If required by the site
    "json": 1
}).json()

Değerleri widget tanımından okuyun — data-action ve data-cdata genellikle HTML içinde açıkça durur.


Üretimde tekrar etmemesi için

Altı nedeni tek tek elediyseniz aynı 403'ün üç ay sonra geri dönmemesi için üç alışkanlık yeterlidir.

  • Token'ı görev gibi değil, sonuç gibi taşıyın. Kuyruğa sitekey ve pageurl yazın; token tüketici tarafında üretilip aynı fonksiyon içinde tüketilsin. Kuyruk gecikmesi ne kadar öngörülemezse bu kural o kadar değerlidir.
  • Eşzamanlılığı thread sayısına göre planlayın. Çözüm sınırsız, faturalama thread başınadır; STANDARD ($30/ay, 10 thread) ile on istek aynı anda çözülür, on birincisi sırada bekler ve beklediği süre token ömründen düşmez — çünkü token henüz üretilmemiştir. Darboğazda sleep eklemek yerine plan yükseltin.
  • Reddedilmeyi ayrı metrik yapın. "Çözüm başarılı ama site reddetti" durumu, çözüm hatasından tamamen farklı bir sinyaldir; aynı sayaçta toplanırsa teşhis imkânsızlaşır. Turnstile çözümleri CaptchaAI tarafında <10 s SLA tavanı altında döner, bu süreyi aşan gecikmeler sizin kuyruğunuzdan gelir.

Kişisel veri içeren formlarla çalışıyorsanız test verilerinizi KVKK kapsamında değerlendirin: staging ortamında gerçek müşteri kaydı yerine üretilmiş +90 numaralar ve tr-TR biçiminde sahte adlar kullanmak, hem uyum hem de tekrarlanabilirlik açısından daha temizdir.


Sırayla eleyin: karar akışı

Tablo yön vermediyse akışı yukarıdan izleyin.

Token solved but rejected
    ↓
Used within 5 minutes? → No → Solve again, submit immediately
    ↓ Yes
Correct sitekey? → No → Find the correct sitekey from the page
    ↓ Yes
Using cf-turnstile-response field? → No → Change field name
    ↓ Yes  
Same session for page load + submit? → No → Use session persistence
    ↓ Yes
Token used only once? → No → Solve a new token per submission
    ↓ Yes
Site requires action/cData? → Check page source, add to API call

Sık sorulan sorular

Loglarımda 403 var ama CaptchaAI çözümü başarılı görünüyor. Faturada bir şey mi kaçırıyorum?

Hayır. Çözüm döndüyse görev tamamlanmıştır; 403 hedef sitenin token'ı kabul etmemesidir. Faturalama thread bazlıdır, reddedilen gönderim ayrı ücret doğurmaz.

Aynı sayfada birden fazla widget varsa hangi sitekey'i göndermeliyim?

Gönderdiğiniz formun içindeki widget'ın anahtarını. Sayfadaki ilk data-sitekey çoğu zaman yanlış olanıdır.

CaptchaAI hCaptcha'yı da çözüyor mu?

Hayır, hCaptcha ve FunCaptcha (Arkose Labs) desteklenmiyor. Turnstile, Cloudflare doğrulama akışı, reCAPTCHA v2/v3 ve GeeTest v3 destekleniyor; GeeTest v4 için "çok yakında" durumu geçerli.

Token'ı bir kuyruğa yazıp birkaç dakika sonra kullanabilir miyim?

Pratikte hayır; 300 saniyelik ömrün büyük kısmı kuyrukta tükenir. Kuyruğa görevi yazın, token'ı tüketici tarafında çözüp aynı anda gönderin.

Postman'da çalışıyor, script'imde çalışmıyor. Neden?

Postman farklı başlık ve çerez gönderiyor olabilir. User-Agent, Referer ve oturum çerezlerini sayfayı yükleyen istemciyle aynı tutun; ayrı requests.Session() nesneleri en yaygın kaynaktır.


Turnstile çözümünü üretime alın

Reddedilme oranını düşürün: captchaai.com.


İlgili rehberler

Bu makale için yorumlar devre dışı bırakılmıştır.