Use Cases

Verifikasi Iklan dengan Penanganan CAPTCHA

Crawler verifikasi iklan Anda mogok begitu sampai di penerbit yang memasang CAPTCHA — dan jawabannya bukan menulis ulang arsitektur crawler, tapi menyelesaikan tantangan itu lewat API sebelum melanjutkan pengecekan placement, brand safety, dan kepatuhan. CaptchaAI mengambil alih langkah reCAPTCHA atau Turnstile itu dalam hitungan detik, sehingga pipeline pemeriksaan ribuan halaman tetap berjalan tanpa campur tangan manual.

Apa yang Diperiksa dalam Verifikasi Iklan Otomatis

Yang diperiksa Penjelasan Kenapa CAPTCHA ikut memblokirnya
Placement iklan Apakah iklan tampil di area yang langsung terlihat (above the fold)? Kunjungan halaman otomatis dibaca sebagai pola bot
Brand safety Memastikan iklan tidak muncul di sebelah konten berbahaya Pemeriksaan URL massal terlihat seperti scraping
Viewability Apakah iklan benar-benar termuat dan terlihat pengguna? Browser headless ditandai oleh Cloudflare
Penargetan geografis Iklan yang tepat tampil di wilayah yang tepat Traffic dari proxy memicu CAPTCHA
Pemantauan pesaing Iklan apa yang sedang ditayangkan kompetitor Volume pencarian iklan yang tinggi dicurigai sebagai bot

Kenapa CAPTCHA Menghentikan Crawler Verifikasi Iklan

Penerbit premium punya insentif kuat untuk memblokir traffic otomatis: inventory iklan mereka dijual berdasarkan impression manusia asli, jadi sistem anti-bot seperti Cloudflare dan reCAPTCHA sengaja dibuat agresif terhadap pola kunjungan yang cepat dan berulang — persis pola yang dipakai crawler verifikasi iklan.

Di Indonesia, pekerjaan ini biasanya dipegang agency ad ops kecil yang memantau beberapa brand sekaligus, atau developer freelance yang membangun crawler custom untuk klien lewat platform seperti Fastwork atau Upwork. Tim seperti ini sering men-deploy crawler dari region AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta) supaya latensi ke penerbit lokal maupun global tetap rendah — tapi traffic dari IP data center itu justru yang paling gampang memicu CAPTCHA, jauh lebih sering dibanding traffic dari browser pengguna biasa.

Tanpa jalur otomatis untuk menyelesaikan tantangan itu, tim ad ops hanya punya dua pilihan: pantau manual (tidak scalable untuk ribuan halaman) atau membiarkan sebagian penerbit tidak pernah terverifikasi. CaptchaAI mengisi celah itu — crawler tetap jalan, CAPTCHA-nya diselesaikan lewat API, dan Anda tidak perlu menulis ulang logic scraping yang sudah ada.

Cara Mengatasi CAPTCHA di Alur Verifikasi Iklan

Polanya sama dengan integrasi CaptchaAI lainnya: kirim task ke in.php, simpan task_id yang dikembalikan, polling res.php sampai statusnya berubah dari CAPCHA_NOT_READY, lalu pakai token yang didapat untuk melanjutkan request. Contoh di bawah menggabungkan pola itu dengan pengecekan placement iklan — begitu CAPTCHA terselesaikan, crawler langsung memeriksa tag Google Ad Manager, DoubleClick, Amazon Ads, dan Criteo di HTML halaman, sekaligus menjalankan pemeriksaan brand safety sederhana berbasis kata kunci.

import requests
import time
import re
import json
import os
from datetime import datetime

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_captcha(method, params):
    params["key"] = API_KEY
    params["method"] = method

    resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
    if not resp.text.startswith("OK|"):
        raise Exception(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": API_KEY, "action": "get", "id": task_id,
        })
        if result.text == "CAPCHA_NOT_READY":
            continue
        if result.text.startswith("OK|"):
            return result.text.split("|", 1)[1]
        raise Exception(result.text)
    raise TimeoutError()


def verify_ad_placement(url, session):
    """Verify ad placement on a publisher page."""
    resp = session.get(url)

    # Solve CAPTCHA if present
    match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text)
    if match:
        token = solve_captcha("userrecaptcha", {
            "googlekey": match.group(1),
            "pageurl": url,
        })
        resp = session.post(url, data={"g-recaptcha-response": token})

    html = resp.text

    # Check for ad elements
    result = {
        "url": url,
        "timestamp": datetime.utcnow().isoformat(),
        "ads_found": [],
        "brand_safety": True,
        "captcha_solved": match is not None,
    }

    # Detect ad tags
    ad_patterns = [
        (r'googletag\.pubads', "Google Ad Manager"),
        (r'doubleclick\.net', "DFP/DoubleClick"),
        (r'ad\.doubleclick', "DoubleClick"),
        (r'amazon-adsystem', "Amazon Ads"),
        (r'criteo\.com/.*\.js', "Criteo"),
    ]

    for pattern, name in ad_patterns:
        if re.search(pattern, html):
            result["ads_found"].append(name)

    # Brand safety check — flag problematic content
    safety_keywords = [
        "violence", "hate speech", "explicit",
        "gambling", "illegal",
    ]
    page_text = re.sub(r'<[^>]+>', '', html).lower()
    for keyword in safety_keywords:
        if keyword in page_text:
            result["brand_safety"] = False
            break

    return result


def run_verification(urls, output_file="verification_report.json"):
    """Run ad verification across multiple publisher URLs."""
    session = requests.Session()
    session.headers["User-Agent"] = (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/120.0.0.0"
    )

    results = []
    for i, url in enumerate(urls):
        try:
            result = verify_ad_placement(url, session)
            results.append(result)
            ads = ", ".join(result["ads_found"]) or "None"
            safe = "SAFE" if result["brand_safety"] else "UNSAFE"
            print(f"  [{i+1}/{len(urls)}] {url}: {ads} [{safe}]")
        except Exception as e:
            results.append({
                "url": url,
                "error": str(e),
                "timestamp": datetime.utcnow().isoformat(),
            })
            print(f"  [{i+1}/{len(urls)}] {url}: ERROR - {e}")

        time.sleep(2)

    with open(output_file, "w") as f:
        json.dump(results, f, indent=2)

    # Summary
    total = len(results)
    safe = sum(1 for r in results if r.get("brand_safety"))
    captchas = sum(1 for r in results if r.get("captcha_solved"))
    errors = sum(1 for r in results if "error" in r)

    print(f"\n  Total: {total} | Safe: {safe} | CAPTCHAs solved: {captchas} | Errors: {errors}")

    return results


# Publisher URLs to verify
publisher_urls = [
    "https://publisher1.com/article/tech-news",
    "https://publisher2.com/sports/latest",
    "https://publisher3.com/finance/markets",
]

run_verification(publisher_urls)

Skrip ini memproses satu batch URL penerbit, menulis hasilnya ke verification_report.json, dan mencetak ringkasan jumlah halaman yang aman, jumlah CAPTCHA yang terselesaikan, dan error yang terjadi — cukup untuk dashboard harian tim ad ops tanpa infrastruktur tambahan.

Menyelesaikan Cloudflare Turnstile di Situs Penerbit Premium

Penerbit premium — media besar, portal berita, situs finansial — cenderung memakai Cloudflare, jadi crawler Anda perlu menangani dua skenario sekaligus: widget Turnstile yang muncul di halaman (cf-turnstile), dan tantangan penuh Cloudflare yang mengembalikan status 403 dengan cf-browser-verification. Fungsi berikut menangani keduanya lewat method turnstile dan cloudflare_challenge:

def handle_cloudflare(url, session):
    """Handle Cloudflare-protected publisher pages."""
    resp = session.get(url)

    if "cf-turnstile" in resp.text:
        match = re.search(r'data-sitekey=["\']([^"\']+)', resp.text)
        if match:
            token = solve_captcha("turnstile", {
                "sitekey": match.group(1),
                "pageurl": url,
            })
            return session.post(url, data={
                "cf-turnstile-response": token,
            })

    if resp.status_code == 403 and "cf-browser-verification" in resp.text:
        data = solve_captcha("cloudflare_challenge", {
            "pageurl": url,
            "proxy": "user:pass@proxy:port",
            "proxytype": "HTTP",
        })
        # Parse qa_validation_cookie and use same proxy
        return data

    return resp

Untuk cloudflare_challenge, sertakan proxy dari geografi yang sama dengan target penargetan iklan — parameter proxy dan proxytype di atas memastikan konteks penyelesaian CAPTCHA cocok dengan region yang sedang Anda verifikasi, jadi hasil placement dan targeting iklan tetap akurat.

Berapa Banyak Thread yang Anda Butuhkan

CaptchaAI dijual per thread aktif, bukan per CAPTCHA yang diselesaikan — jadi biaya bulanan Anda tetap flat berapa pun jumlah halaman yang diverifikasi, selama thread yang dipakai tidak melebihi paket. Untuk tim ad ops, kebutuhan thread biasanya mengikuti jumlah URL yang diverifikasi paralel, bukan volume iklan itu sendiri:

  • BASIC ($15/bulan, 5 thread) — cukup untuk uji coba atau agency kecil yang memantau segelintir penerbit.
  • STANDARD ($30/bulan, 15 thread) — volume menengah, beberapa brand sekaligus.
  • ADVANCE ($90/bulan, 50 thread) — agency yang menjalankan verifikasi harian untuk banyak klien.
  • PREMIUM ($170/bulan, 100 thread) — operasi ad ops skala besar dengan crawling paralel tinggi.

Model thread-based ini biasanya jadi pertimbangan utama tim yang sensitif biaya di Indonesia — dibanding solver yang mengenakan biaya per CAPTCHA, tagihan Anda tidak melonjak saat musim kampanye iklan sedang ramai dan volume verifikasi naik tajam.

Pertanyaan Umum

Berapa banyak halaman yang bisa diverifikasi per jam dengan CaptchaAI?

Kecepatannya bergantung pada seberapa sering CAPTCHA muncul di penerbit yang Anda pantau dan waktu penyelesaian tiap jenisnya. Pada praktiknya, alur seperti contoh di atas berjalan pada kisaran 200–500 halaman per jam.

Apakah hCaptcha didukung untuk crawler verifikasi iklan?

Belum. hCaptcha tidak didukung saat ini, jadi penerbit yang memakainya butuh solusi lain. CaptchaAI menangani reCAPTCHA v2/v3, Cloudflare Turnstile dan Challenge, GeeTest v3, serta CAPTCHA gambar/OCR — cakupan yang menutupi mayoritas penerbit besar.

Paket thread mana yang cocok untuk tim ad ops kecil vs agency besar?

Untuk uji coba atau segelintir penerbit, BASIC (5 thread) sudah cukup. Agency yang memverifikasi banyak klien sekaligus biasanya naik ke ADVANCE atau PREMIUM agar lebih banyak URL bisa diproses paralel tanpa antre.

Apakah verifikasi iklan video juga bisa memakai pendekatan ini?

Untuk iklan gambar dan native, ya. Iklan video umumnya perlu rendering browser penuh dengan Selenium atau Playwright, karena playback dan pengukuran viewability-nya berjalan lewat JavaScript, bukan HTML statis yang bisa langsung dibaca dari response.

Bagaimana menjaga kepatuhan saat scraping halaman penerbit untuk verifikasi iklan?

Verifikasi iklan hanya mengakses halaman publik penerbit, bukan data pribadi pengguna — tapi tetap perhatikan UU Pelindungan Data Pribadi (UU 27/2022) dan UU ITE saat menyimpan hasil crawl, terutama bila laporan menyertakan cuplikan konten yang menyinggung individu.

Panduan Terkait

Komentar dinonaktifkan untuk artikel ini.