Marathon Race & Volunteer Alerts
To qualify for the TCS NY Marathon through NYRR’s 9+1 program, you need nine qualifying races plus one volunteer shift. Open spots are scarce and fill within hours, and the listing page itself is unreliable: its “available only” filter often shows slots that are already gone or gated behind a Leadership/Medical modal. Refreshing by hand doesn’t scale, and trusting the filter produces false alarms.
I built a watcher that renders the listing page, follows every event link, and re-checks true status on each event’s detail page. Because those pages are client-rendered and hydrate a few seconds after load, a plain HTTP request returns no assignment data at all. Getting an accurate read meant rendering headlessly with Playwright and waiting out that hydration window rather than trusting the raw response.
The harder problem was precision, not plumbing. NEAR CAPACITY spots looked open but often opened a Leadership/Medical-only modal on click, so I excluded them entirely and alert only on clean AVAILABLE status. Every qualifying rule (required tag, excluded roles, gated assignments, races the user is already running) lives in a config file rather than code, so the tool stays generic instead of hardcoded to my own race list. A dedupe store means a spot alerts once when it flips open, not on every poll.
Alert-only by design: it finds a qualifying spot and Discord-pings a direct registration link. No login, no credentials, no auto-booking. You still click register yourself. Deployed on a schedule via systemd, with a GitHub Actions cron path as a fallback.