Use Cases

Event Ticket Monitoring with CAPTCHA Handling

Ticket platforms use CAPTCHAs to prevent automated checks and purchases. When monitoring event ticket availability — concerts, sports, theater — your scraper will encounter reCAPTCHA challenges, Cloudflare protections, and rate limiting. CaptchaAI handles the CAPTCHA solving so your monitor can check availability reliably.

This guide builds a ticket monitoring workflow with integrated CAPTCHA solving.


The monitoring workflow

Configure events → Check availability → CAPTCHA?
                                           ↓ Yes
                                      Solve via CaptchaAI → Retry
                                           ↓ No
                                      Parse availability → Changed?
                                                             ↓ Yes
                                                         Send alert

What you need

Requirement Details
CaptchaAI API key captchaai.com
Python 3.8+ With requests
Proxy Residential proxy recommended
pip install requests

CAPTCHA solver helper

import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_captcha(method, params):
    """Generic CaptchaAI solver for any supported method."""
    params["key"] = API_KEY
    params["json"] = 1

    submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    initial_wait = 10 if method == "turnstile" else 20
    time.sleep(initial_wait)

    for _ in range(30):
        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"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")

Ticket monitor

from datetime import datetime
import json


class TicketMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        if proxy:
            self.session.proxies = {
                "http": f"http://{proxy}",
                "https": f"http://{proxy}"
            }
        self.last_status = {}

    def check_event(self, event):
        """Check ticket availability for an event, solving CAPTCHAs if needed."""
        url = event["url"]
        response = self.session.get(url)

        # Handle CAPTCHA if detected
        if "g-recaptcha" in response.text or "recaptcha" in response.text:
            sitekey = self._extract_sitekey(response.text)
            if sitekey:
                token = solve_captcha("userrecaptcha", {
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "g-recaptcha-response": token
                })

        elif "cf-turnstile" in response.text:
            sitekey = self._extract_turnstile_key(response.text)
            if sitekey:
                token = solve_captcha("turnstile", {
                    "method": "turnstile",
                    "sitekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "cf-turnstile-response": token
                })

        # Parse availability
        availability = self._parse_availability(response.text, event)

        # Check for changes
        event_key = event["name"]
        if event_key in self.last_status:
            if availability != self.last_status[event_key]:
                self._send_alert(event, availability)

        self.last_status[event_key] = availability
        return availability

    def _extract_sitekey(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _extract_turnstile_key(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _parse_availability(self, html, event):
        """Parse ticket availability. Customize per ticketing site."""
        available = "sold out" not in html.lower()
        return {
            "event": event["name"],
            "available": available,
            "checked_at": datetime.now().isoformat()
        }

    def _send_alert(self, event, availability):
        """Send availability change notification."""
        status = "AVAILABLE" if availability["available"] else "SOLD OUT"
        print(f"[ALERT] {event['name']}: {status}")

    def monitor_all(self, events):
        """Check all events and return results."""
        results = []
        for event in events:
            try:
                result = self.check_event(event)
                results.append(result)
                print(f"[OK] {event['name']}: {'available' if result['available'] else 'sold out'}")
            except Exception as e:
                print(f"[ERROR] {event['name']}: {e}")
        return results


# Usage
events = [
    {
        "name": "Concert - Madison Square Garden - Aug 15",
        "url": "https://example-tickets.com/event/12345"
    },
    {
        "name": "Basketball Finals - Game 7",
        "url": "https://example-tickets.com/event/67890"
    }
]

monitor = TicketMonitor(proxy="user:pass@proxy.example.com:8080")
results = monitor.monitor_all(events)

for r in results:
    print(json.dumps(r, indent=2))

Expected output:

[OK] Concert - Madison Square Garden - Aug 15: available
[OK] Basketball Finals - Game 7: sold out

Scheduling

Run checks on a regular interval:

# Check every 15 minutes
*/15 * * * * cd /path/to/project && python ticket_monitor.py >> /var/log/tickets.log 2>&1

Troubleshooting

Issue Cause Fix
Frequent CAPTCHAs on every check Same IP, no session persistence Use cookies, rotate residential proxies
Blocked after a few checks Rate limiting Increase check intervals, use proxy rotation
Wrong availability status Page structure changed Update the _parse_availability method
Slow CAPTCHA solving High solver load Implement retry logic with backoff

FAQ

How often should I check ticket availability?

Every 10–30 minutes for general monitoring. For high-demand events, every 2–5 minutes — but expect more CAPTCHAs at higher frequencies.

Which CAPTCHAs do ticket sites use?

Most commonly reCAPTCHA v2, Cloudflare Turnstile, and Cloudflare Challenge pages. Queue systems like virtual waiting rooms may use custom challenges.

Can I monitor multiple ticket platforms?

Yes. Customize the parser for each platform's HTML structure and add events from different sites.

Do I need residential proxies?

Yes. Ticket sites aggressively block datacenter IPs. Residential proxies reduce CAPTCHA frequency.

How do I handle waiting rooms/queues?

Waiting rooms are separate from CAPTCHAs. Your monitor should detect queue pages and either wait or retry. CaptchaAI solves the CAPTCHA that appears after the queue.


Get your CaptchaAI API key

Start monitoring ticket availability at captchaai.com. Handle CAPTCHAs automatically in your event monitoring workflow.


Full Working Code

Complete runnable examples for this article in Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin & Bash.

View on GitHub →

Discussions (0)

No comments yet.