Anwendungsfälle

Anzeigenüberprüfungs-Workflows mit CAPTCHA-Verwaltung

Ein reCAPTCHA v2 oder eine Cloudflare-Turnstile-Abfrage auf der Publisher-Seite bringt jede automatisierte Anzeigenprüfung sofort zum Stillstand. Der direkte Weg daran vorbei: CaptchaAI löst die CAPTCHA-Abfrage per API, Ihr Verifizierungs-Crawler ruft die Seite regulär ab und die Pipeline läuft ohne manuellen Eingriff weiter. Anzeigenverifizierung bedeutet, Tausende Publisher-URLs zu besuchen und Platzierung, Markensicherheit und Geo-Targeting zu prüfen – genau dieser Massenzugriff löst die Schutzmechanismen aus, die den Job blockieren.

Warum CAPTCHAs die Anzeigenverifizierung ausbremsen

Verifizierungs-Anbieter arbeiten breit gestreut über viele Publisher hinweg, oft über rotierende Proxys und Headless-Browser. Für die Schutzsysteme der Zielseiten sieht dieses Verhalten wie Scraping oder ein Bot-Angriff aus – und genau die Signale, die eine saubere Prüfung braucht, lösen die Abfrage aus. Eine Whitelist pro Publisher pflegen Sie bei mehreren hundert Domains nicht mehr von Hand. Die folgende Tabelle zeigt, welche Prüfpunkte betroffen sind und warum.

Prüfpunkt Beschreibung Warum CAPTCHAs blockieren
Anzeigenplatzierung Erscheint die Anzeige im sichtbaren Bereich (above the fold)? Automatisierte Seitenaufrufe lösen die Bot-Erkennung aus
Markensicherheit Keine Anzeigen neben schädlichen Inhalten Massenhafte URL-Prüfung ähnelt Scraping
Sichtbarkeit (Viewability) War die Anzeige tatsächlich sichtbar? Cloudflare markiert Headless-Browser
Geo-Targeting Richtige Anzeige in der richtigen Region Proxy-Traffic löst CAPTCHAs aus
Konkurrenzbeobachtung Welche Anzeigen schalten Wettbewerber? Anzeigenabfragen mit hohem Volumen

Die Verifizierungs-Pipeline mit CaptchaAI umsetzen

Der Ablauf ist bei jeder geschützten Seite gleich: Seite abrufen, prüfen ob ein sitekey im HTML steht, die Abfrage an CaptchaAI übergeben, das Token abwarten und mit dem Formular zurücksenden. Auf Publisher-Seiten ist reCAPTCHA v2 (Methode userrecaptcha) der häufigste Typ, meist auf Consent-Walls oder Login-Bereichen. Erst nach dem Lösen kommen Sie an das gerenderte HTML mit den Anzeigen-Tags.

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)

Das Ergebnis pro URL landet strukturiert in verification_report.json: erkannte Anzeigen-Tags, Markensicherheits-Flag und ob eine Abfrage gelöst werden musste. Diesen Report können Sie direkt in Ihr Reporting oder ein Dashboard einspeisen.

Cloudflare-geschützte Premium-Publisher abdecken

Ein großer Teil der reichweitenstarken Publisher – gerade im DACH-Raum bei etablierten Nachrichten- und Fachportalen – sitzt hinter Cloudflare. Hier begegnen Ihnen zwei Varianten: die leichtgewichtige Cloudflare-Turnstile-Abfrage (Methode turnstile, Token-Feld cf-turnstile-response) und die vollständige Cloudflare Challenge, bei der die Solve-Anfrage denselben Proxy nutzen muss wie der spätere Seitenaufruf. Beide Typen unterstützt CaptchaAI regulär.

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 cf_clearance and use same proxy
        return data

    return resp

Wichtig bei der vollständigen Challenge: Das zurückgegebene cf_clearance-Cookie ist an die IP der Solve-Session gebunden. Verwenden Sie für den anschließenden Seitenabruf denselben Proxy, sonst verwirft Cloudflare die Sitzung.

Durchsatz und Kosten über Threads planen

CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung – jeder Thread umfasst unbegrenzte Lösungen im Abrechnungsmonat, ohne Aufpreis je CAPTCHA-Typ. Für die Anzeigenverifizierung heißt das: Ihre Parallelität ist an die Thread-Zahl gebunden. Ein Thread verarbeitet eine laufende Abfrage; sobald sie fertig ist, nimmt er die nächste URL. Wer nachts einige tausend Publisher-Seiten prüft, skaliert schlicht über mehr Threads.

Für kleine, regelmäßige Läufe reicht BASIC (15 $/Monat, 5 Threads). Größere Kampagnen fahren Sie mit ADVANCE (90 $/Monat, 50 Threads) oder PREMIUM (170 $/Monat, 100 Threads). Die Preise sind in US-Dollar. Die Verifizierungs-Worker selbst laufen kostengünstig auf gängiger DACH-Infrastruktur wie Hetzner oder IONOS – die Solving-Kapazität liefert die API.

DSGVO und rechtliche Sorgfalt im DACH-Raum

Anzeigenverifizierung im großen Maßstab berührt zwei Themen, die im deutschsprachigen Raum ernst genommen werden. Erstens der Datenschutz: Sobald Sie über Residential-Proxys arbeiten, sind IP-Adressen im Spiel, die nach DSGVO als personenbezogene Daten gelten. Prüfen Sie Ihre Datenflüsse und die Rechtsgrundlage, bevor eine Kampagne live geht – das ist Sorgfaltspflicht auf Ihrer Seite, keine Compliance-Zusage von CaptchaAI. Zweitens die Konkurrenzbeobachtung: Wer Wettbewerberanzeigen erfasst und daraus vergleichende Aussagen ableitet, sollte diese nach UWG § 6 sachlich und nachprüfbar halten. Konservative, belegbare Angaben schaffen bei DACH-Lesern mehr Vertrauen als jede Superlativ-Behauptung.

Häufige Fragen

Welche CAPTCHA-Typen treten bei der Anzeigenverifizierung am häufigsten auf?

Überwiegend reCAPTCHA v2 und v3 sowie Cloudflare Turnstile und Cloudflare Challenge auf premium-geschützten Publishern. Alle vier löst CaptchaAI regulär; dazu kommen bei Bedarf Bild- und Grid-CAPTCHAs sowie GeeTest v3.

Wie viele Threads brauche ich für eine große Verifizierungskampagne?

Das hängt von der gewünschten Parallelität ab. Als grobe Orientierung schaffen Sie je nach CAPTCHA-Häufigkeit und Lösungszeit etwa 200–500 Seiten pro Stunde und Thread-Bündel; für nächtliche Läufe über tausende URLs sind 50–100 Threads (ADVANCE oder PREMIUM) ein guter Startpunkt.

Ist die automatisierte Anzeigenprüfung DSGVO-konform?

Das liegt in Ihrer Verantwortung, nicht in der des Solving-Dienstes. Dokumentieren Sie die Rechtsgrundlage für die Verarbeitung, insbesondere bei Proxy-gebundenen IP-Adressen, und beschränken Sie die Prüfung auf zulässige, öffentlich erreichbare Publisher-Inhalte.

Kann ich Video-Anzeigen genauso prüfen?

Für Display- und native Anzeigen genügt der HTTP-basierte Ansatz oben. Video-Anzeigen brauchen in der Regel echtes Browser-Rendering mit Selenium oder Playwright – CaptchaAI löst dabei die Abfrage, das Rendering übernimmt der Browser.

Verwandte Leitfäden

Kommentare sind für diesen Artikel deaktiviert.