The problem
This one started as my own problem. I needed a specialist appointment, and Doctolib's first availability was months away. Cancellations do free up earlier slots — but they're gone within minutes, and the only "strategy" is refreshing the page every day and still losing. So I built a robot to do the refreshing for me, then made it free for everyone with the same problem.
What I built
- An alert is a city, a medical specialty, a date limit, and smart filters — Secteur 1 (no extra fees) and practitioners accepting new patients
- Automatic checks every 15 minutes, around the clock
- Exactly one email per alert, containing the direct booking link, the moment a matching slot appears — then the alert closes itself. No spam by design
- Free, and deliberately minimal on data: an email address is all it needs
How it works
Rather than scraping HTML, DoctoAlerte talks to the same internal availability API that Doctolib's own frontend calls — mapped by reverse-engineering the network traffic. Structured JSON means precise matching on sectors, dates and availability, and far fewer breakages than parsing markup that can change any day.
- User creates an alert (city, specialty, filters, deadline)
- Hangfire recurring job ticks every 15 minutes
- Throttled batch queries Doctolib's availability API
- Results are matched against each alert's filters
- One email goes out with the direct booking link
- The alert closes itself
Being a polite guest is an architectural requirement here, enforced at two levels: per-user quotas cap how many alerts an account can run, and a global internal throttle spaces and batches every outgoing request, so the total traffic DoctoAlerte generates stays a small, steady fraction of ordinary browsing. Only active alerts are ever queried, and results are cached.
Scheduling is Hangfire recurring jobs on .NET; alerts and state live in SQL Server; sign-in is Google; notifications go out as transactional email. The UI is Blazor Server.
Hard problems
- Working against an undocumented API: mapping it in the first place, then adapting quickly whenever it shifts underneath you.
- Fitting every active alert inside a strict politeness budget in each 15-minute window — batching, spacing and prioritizing the checks.
- Exactly-one-email semantics: deduplication so a slot that appears in several consecutive checks never alerts the same user twice.
Results & lessons
Users regularly find appointments in days that Doctolib listed as months away — at zero cost to them. And the constraint turned out to be the teacher: designing for restraint — scrape less, cache more, alert once — produced a better system than designing for scale would have.