Comparisons

reCAPTCHA v2 onay kutusu ile görünmez reCAPTCHA arasındaki farklar

Entegrasyon yazıldı, API OK| döndü, token elinizde — ama form doğrulamadan geçmiyorsa büyük ihtimalle görünmez varyantla uğraşıyorsunuz. İki varyant aynı sitekey biçimini ve aynı g-recaptcha-response alanını kullanır; ayrım üç noktada toplanır:

  • Tespit: görünür widget yoksa HTML'de data-size="invisible" arayın.
  • İstek: tek fark invisible=1 parametresidir.
  • Enjeksiyon: onay kutusunda gizli alan yeter; görünmez sürümde callback'i elle çağırırsınız.

Sıra da bu: önce tespit, sonra çözüm isteği, en sonda enjeksiyon.

Sayfa kaynağında iki varyant

v2 Onay Kutusu

<!-- Standard checkbox widget -->
<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
     data-callback="onSubmit">
</div>

<!-- Widget renders as: -->
<!-- [✓] I'm not a robot     reCAPTCHA logo -->

Kullanıcı kutuyu görür ve tıklar; Google şüphelenirse ızgara doğrulaması satır içinde açılır.

v2 Görünmez

<!-- Pattern 1: Invisible widget on a button -->
<button class="g-recaptcha"
        data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
        data-callback="onSubmit"
        data-size="invisible">
  Submit
</button>

<!-- Pattern 2: Invisible div (programmatic trigger) -->
<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
     data-size="invisible"
     data-callback="onSubmit">
</div>

<!-- Pattern 3: Programmatic render -->
<script>
  grecaptcha.render('submit-btn', {
    sitekey: '6Le-wvkSAAAAAPBMRTvw...',
    callback: onSubmit,
    size: 'invisible'
  });
</script>

Görünür widget yoktur; reCAPTCHA, öğe tetiklendiğinde veya grecaptcha.execute() çağrıldığında devreye girer. Üç kalıbın tespit zorluğu aynı değildir:

  • Düğmedeki widget: data-size="invisible" HTML'de görünür.
  • Görünmez div: aynı öznitelik var, tetikleyici JavaScript'te.
  • Programatik render: HTML'de iz kalmaz, script içini taramanız gerekir.

Varyantı çalışma anında tespit edin

sitekey değerine bakarak karar veremezsiniz; biçim ikisinde de aynıdır. Ayrım HTML'dedir. Python ile:

import requests
from bs4 import BeautifulSoup
import re

def detect_recaptcha_variant(url):
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")

    # Check for invisible indicators
    invisible_widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
    if invisible_widget:
        return {
            "variant": "invisible",
            "sitekey": invisible_widget.get("data-sitekey"),
            "callback": invisible_widget.get("data-callback")
        }

    # Check for programmatic invisible in scripts
    for script in soup.find_all("script"):
        if script.string and "invisible" in str(script.string):
            key_match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", script.string)
            if key_match:
                return {
                    "variant": "invisible-programmatic",
                    "sitekey": key_match.group(1),
                    "callback": "check grecaptcha.render() call"
                }

    # Check for standard checkbox
    checkbox_widget = soup.find(class_="g-recaptcha")
    if checkbox_widget:
        return {
            "variant": "checkbox",
            "sitekey": checkbox_widget.get("data-sitekey"),
            "callback": checkbox_widget.get("data-callback")
        }

    return None

result = detect_recaptcha_variant("https://staging.example.com/qa-login")
print(result)

Node.js tarafında aynı mantık:

const axios = require("axios");
const cheerio = require("cheerio");

async function detectRecaptchaVariant(url) {
  const { data } = await axios.get(url);
  const $ = cheerio.load(data);

  // Check for invisible
  const invisible = $(".g-recaptcha[data-size='invisible']");
  if (invisible.length) {
    return {
      variant: "invisible",
      sitekey: invisible.attr("data-sitekey"),
      callback: invisible.attr("data-callback"),
    };
  }

  // Check scripts for programmatic invisible
  const scripts = $("script")
    .map((_, el) => $(el).html())
    .get()
    .join("\n");
  if (scripts.includes("invisible")) {
    const keyMatch = scripts.match(/sitekey['"]?\s*[:=]\s*['"]([^'"]+)/);
    if (keyMatch) {
      return {
        variant: "invisible-programmatic",
        sitekey: keyMatch[1],
        callback: "check render call",
      };
    }
  }

  // Check for standard checkbox
  const checkbox = $(".g-recaptcha");
  if (checkbox.length) {
    return {
      variant: "checkbox",
      sitekey: checkbox.attr("data-sitekey"),
      callback: checkbox.attr("data-callback"),
    };
  }

  return null;
}

Elle bakarken konsoldaki tek satır da yeter:

const el = document.querySelector('[data-size="invisible"]');
console.log(el ? "Invisible reCAPTCHA" : "Checkbox reCAPTCHA");
Algılama sinyali v2 Onay Kutusu v2 Görünmez
data-size="invisible" Yok Var
Görünür onay kutusu Evet Hayır
grecaptcha.execute() Hayır, kullanıcı tıklar Evet, programatik

Not: Varyantı sabit varsaymayın — aynı site masaüstünde onay kutusunu, mobilde görünmez sürümü sunabilir.

Özellik karşılaştırması

Özellik v2 Onay Kutusu v2 Görünmez
Görsel doğrulama Satır içi ızgara Sağ alt köşede açılır pencere
Kullanıcı sürtünmesi Orta Düşük
Token alanı g-recaptcha-response g-recaptcha-response
Callback İsteğe bağlı Neredeyse her zaman zorunlu
CaptchaAI yöntemi method=userrecaptcha method=userrecaptcha + invisible=1
Token ömrü 120 saniye 120 saniye
Çözüm süresi 10–30 saniye 10–25 saniye

Tablodaki gerçek ayrım iki satırda: invisible=1 ve callback zorunluluğu.

Çözüm isteği: tek parametrelik fark

Akış ikisinde de aynı: görevi in.php'ye gönderin, res.php'yi sorgulayın, token'ı alın.

v2 Onay Kutusu

import requests
import time

resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "6Le-wvkSAAAA...",
    "pageurl": "https://example.com/form"
})
task_id = resp.text.split("|")[1]

for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

v2 Görünmez

import requests
import time

resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "6Le-wvkSAAAA...",
    "pageurl": "https://example.com/form",
    "invisible": 1  # Only parameter difference
})
task_id = resp.text.split("|")[1]

for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

Tek fark invisible: 1 satırı. Sorgulama döngüsü, zaman aşımı ve hata kodları iki varyantta da aynı.

Token enjeksiyonu: asıl ayrışma noktası

İki akış buraya kadar aynıydı; fark burada çıkıyor.

Onay kutusu: gizli alan çoğu zaman yeter

# Selenium — inject into hidden field
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# If the page uses a callback, also call it
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
    driver.execute_script(f'{callback}("{token}");')

Görünmez: callback'i çağırmadan olmaz

# Selenium — inject AND call the callback
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# CRITICAL: Invisible reCAPTCHA almost always requires calling the callback
callback_name = driver.find_element(
    "css selector", ".g-recaptcha[data-size='invisible']"
).get_attribute("data-callback")

driver.execute_script(f'{callback_name}("{token}");')

Puppeteer tarafında aynı yaklaşım:

// Puppeteer — invisible callback injection
await page.evaluate((tok) => {
  // Set the hidden field
  document.getElementById("g-recaptcha-response").value = tok;

  // Find and call the callback function
  const widget = document.querySelector("[data-size='invisible']");
  const cbName = widget?.getAttribute("data-callback");
  if (cbName && typeof window[cbName] === "function") {
    window[cbName](tok);
  }
}, token);

Neden? Onay kutusunda kullanıcının tıklaması callback'i (geri çağırma) zaten tetikler. Görünmez sürümde o tıklama hiç olmaz; callback'i siz çağırmazsanız form boş doğrulama durumuyla gider.

İki varyantı tek çözücüyle karşılayın

İki ayrı kod yolu bakım maliyetini ikiye katlar; tespiti ve çözümü tek sınıfta toplayın:

import requests
import time
from bs4 import BeautifulSoup

class RecaptchaV2UniversalSolver:
    def __init__(self, api_key):
        self.api_key = api_key

    def detect_and_solve(self, page_url, page_html=None):
        if not page_html:
            page_html = requests.get(page_url).text

        soup = BeautifulSoup(page_html, "html.parser")

        # Detect variant
        invisible = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
        widget = invisible or soup.find(class_="g-recaptcha")

        if not widget:
            raise Exception("No reCAPTCHA widget found")

        sitekey = widget.get("data-sitekey")
        is_invisible = invisible is not None
        callback = widget.get("data-callback")

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url
        }
        if is_invisible:
            params["invisible"] = 1

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

        task_id = resp.text.split("|")[1]
        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key, "action": "get", "id": task_id
            })
            if result.text.startswith("OK|"):
                return {
                    "token": result.text.split("|")[1],
                    "variant": "invisible" if is_invisible else "checkbox",
                    "callback": callback,
                    "sitekey": sitekey
                }
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve error: {result.text}")

        raise Exception("Timed out")

# Usage
solver = RecaptchaV2UniversalSolver("YOUR_API_KEY")
result = solver.detect_and_solve("https://staging.example.com/qa-login")
print(f"Variant: {result['variant']}, Callback: {result['callback']}")

Aynı iskelet başka türlere de genişler; değişen tek şey method değeridir:

  • Cloudflare Turnstile — aynı gönder/sorgula döngüsü.
  • GeeTest v3 — aynı in.php / res.php mantığı.
  • reCAPTCHA v2 Enterprise — ek alanlar dışında aynı.

Türkiye'den bir senaryo: ödeme akışının QA testi

Buradaki ekiplerin ağırlığı e-ticaret ve fintech entegrasyonlarında; regresyon paketlerinde en sık takılan yer ödeme adımı. Tipik tablo şu: staging'deki giriş formu onay kutusunu, mobil ödeme akışı görünmez sürümü kullanıyor — aynı sitekey, ama mobil senaryolar sessizce düşüyor. Sebep genelde çağrılmayan callback'tir; yukarıdaki çözücü varyantı çalışma anında ayırır.

Maliyet tarafı thread sayısına bağlı, çözüm adedine değil:

  • Gecelik pakette en fazla beş eşzamanlı doğrulama varsa BASIC ($15/ay, 5 thread) yeter.
  • Paralel senaryolar artınca STANDARD ($30/ay, 15 thread) rahat eder.
  • Her push'ta koşan CI için ADVANCE ($90/ay, 50 thread).

Fiyatlar USD üzerinden sabittir. Test verilerinizde kişisel veri varsa KVKK yükümlülüklerini de hesaba katın.

Sorun giderme

Belirti Onay kutusu Görünmez
Token reddedildi g-recaptcha-response alanını doldurun data-callback fonksiyonunu bulun ve çağırın
Widget bulunamadı .g-recaptcha sınıfını arayın data-size="invisible" ve grecaptcha.render() çağrılarına bakın
Form gidiyor, doğrulama geçmiyor Sayfa callback bekliyor olabilir Callback zorunlu; adını bulup çalıştırın
Enjeksiyondan sonra sayfa yenileniyor JavaScript doğrulaması düşmüştür Callback'i otomatik gönderimden önce çağırın
Token'ın süresi doldu 120 saniye içinde kullanın Aynı kural; sorgulama aralığını kısaltın

Tablo yetmezse şu üçüne bakın:

  • pageurl formun URL'siyle birebir aynı mı?
  • Token üretileli kaç saniye oldu?
  • Callback, otomatik gönderimden önce mi çalışıyor?

Sık sorulan sorular

invisible=1 göndermezsem ne olur?

Genellikle yine token alırsınız, ama hedef site reddedebilir. Parametre çözümün doğru varyant bağlamında üretilmesini sağlar; görünmez widget'ta atlanması yaygın bir doğrulama hatası nedenidir.

Callback fonksiyonunun adını bulamıyorum, ne yapmalıyım?

Önce widget'ın data-callback özniteliğine, yoksa grecaptcha.render() çağrısının callback alanına bakın. Callback anonimse token'ı yazdıktan sonra gönderim düğmesini tetikleyin.

Görünmez reCAPTCHA yine de görsel doğrulama çıkarır mı?

Evet. Google şüpheli davranış gördüğünde sağ alt köşede doğrulama penceresi açılır; "görünmez", doğrulamanın hiç çıkmaması değil varsayılanda gösterilmemesi demektir.

CaptchaAI hangi reCAPTCHA varyantlarını destekliyor?

reCAPTCHA v2'nin onay kutusu, görünmez, callback ve Enterprise varyantları ile v3 ve v3 Enterprise desteklenir. Listede ayrıca Cloudflare Turnstile, Cloudflare doğrulama akışı, GeeTest v3, görsel/OCR ve ızgara CAPTCHA'ları ile BLS var. hCaptcha ve FunCaptcha (Arkose Labs) desteklenmez; GeeTest v4 için yalnızca "çok yakında" geçerlidir. CaptchaFox, Friendly Captcha ve Lemin beta aşamasındadır.

İlgili kılavuzlar

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