Automating Concert Ticket Price Watching With GitHub Actions
Automating Concert Ticket Price Watching With GitHub Actions



Resale ticket prices move constantly. The window where a good deal appears and disappears can be hours — or minutes. Checking manually means either paying too much or missing it entirely.
I wanted a bot that watches for me.
The Setup
The monitor runs every 30 minutes via GitHub Actions cron. It scrapes two resale platforms, compares the lowest price (including fees) to my threshold, and emails me if it's below.
on: schedule: - cron: '*/30 * * * *'
No server. No hosting fees. GitHub Actions gives you 2,000 free minutes per month — more than enough for a 30-minute cron running a 30-second script.
The WAF Problem
Both StubHub and Viagogo sit behind AWS WAF. Load the page with a standard HTTP request and you get a JavaScript challenge page, not the actual prices.
Playwright solves this by running a real Chromium browser. The WAF challenge auto-resolves when a real browser executes the JavaScript. The trick is waiting for it:
page.wait_for_selector("[data-price]", timeout=20000)
Instead of scraping immediately after navigation, we wait for the price element to appear. The WAF has already resolved by then.
Fee Normalization
One platform shows the ticket price. Another shows the ticket price plus a processing fee at checkout. If you compare them directly, you're comparing different numbers.
The fix: a configurable VIAGOGO_FEE environment variable. The monitor adds it to the scraped price before comparing to threshold. You set it once in GitHub secrets and forget it.
viagogoPrice = scraped_price + int(os.getenv("VIAGOGO_FEE", 0))
Configuration Without Code Changes
All tunable parameters live in GitHub secrets and repository variables:
| Variable | What It Controls |
|---|---|
STUBHUB_URL | The specific event listing URL |
VIAGOGO_URL | The specific event listing URL |
PRICE_THRESHOLD | Alert below this price |
VIAGOGO_FEE | Fee to add to Viagogo prices |
GMAIL_USER | Sending Gmail account |
GMAIL_APP_PASSWORD | Gmail app password (not account password) |
ALERT_EMAIL | Where to send the alert |
Want to watch a different event? Update the URLs in the repo variables — no code change, no redeploy.
The Alert
When a price drops below threshold, Gmail SMTP sends a plain-text email with the current price on each platform and a direct link to buy. Simple, fast, actionable.
What I'd Do Differently
Persistent price history. Right now the monitor only checks the current price — it doesn't track trends. Adding a simple CSV append to the workflow would let me see whether prices are generally falling or spiking.
Smarter WAF handling. The wait_for_selector approach works, but it's brittle if the selector changes. A retry loop with multiple selector fallbacks would be more robust.
Telegram over email. Email alerts feel slow. A Telegram bot message is instant and works from anywhere without opening an email client.
The Broader Pattern
GitHub Actions as a free cron executor is underused. Any script that needs to run on a schedule — price monitoring, data aggregation, report generation, health checks — can run here without infrastructure. The repo becomes the deployment unit, secrets become the config layer, and the workflow file documents exactly what runs and when.