Stop Refreshing the Page.
How building a tee time monitor taught me more about product thinking than any PM course. A story about iteration, competition, and not accepting the queue.
By Danny Ekhaus
On April 4th, I booked a Saturday morning tee time at Torrey Pines 10 days in advance. That shouldn't have been possible.
Torrey Pines has two booking windows. The paid advance window opens 8-90 days out, at $32 per player, non-refundable. That is where prime weekend slots live, and they go fast. If you want Saturday morning, you are committing three months ahead and paying before you know who can make it. The free window opens 7 days out, with new slots dropping every evening at 7 PM. What you are getting there is decent: late-afternoon twilight times. Still contested, just not prime.
If you are not in either race, you are waiting for a cancellation.
I got tired of the races. So I stopped entering them.
The problem is supply and demand, not bad luck
Public golf in San Diego has been quietly collapsing. COVID drove a surge in demand in a short window. At the same time, courses have been selling to developers. Land in San Diego is too valuable to make golf pencil out. The result: more players chasing fewer tee sheets, with prices to match.
Torrey Pines is the worst case. It's city-owned, sits on some of the most iconic land in the country, and has name recognition from PGA Tour events. It's also the best value left in public San Diego golf. That combination means demand is permanent and ruthless.
I used to play the 90-day game. $128 upfront per round, hoping to find a foursome. You commit to a date three months out, lock in four players, and spend the next 90 days hoping everyone's schedule holds. Sometimes it doesn't. Transferring tee times is a pain. And every once in a while, you end up playing a round you no longer want to play because you can't get out of it.
Eventually I stopped. The math was wrong, and the flexibility was gone. Twilight times were not what I wanted either.
The only remaining path was cancellations: prime slots that open up when someone who planned months ahead changes their mind. But you have to be watching when they do, at any hour, on any day.
I was not willing to watch manually.
I wanted a product, not a script
When I decided to build something, I had a rough idea: monitor the tee sheet automatically, notify me when something opens up, let me decide. Simple in concept. But the moment I started mapping it out, it was a product problem, not a coding problem.
What are all the ways a tee time becomes available? There is the daily 7 PM release, where new slots drop for the date exactly seven days out. There are same-week cancellations. There are longer-range weekend cancellations from the 8-90 day booking window, which has a different fee structure and a different booking class. And there is a walk-up waitlist that operates entirely separately.
Four distinct scenarios. Four different solutions.
I did not design all of them upfront. I had a general direction and worked through it iteratively. The cancellation monitor came first, catching openings in the 0-7 day window. Then I realized the 7 PM release was its own problem. Polling every 60 seconds is useless when slots disappear in seconds. That became the release monitor, which fires parallel booking requests at exactly 7:00:00 PM. Then I noticed I kept missing prime weekend slots in the 8-90 day window. Those cancellations look different because you are watching for new inventory against a stable baseline. That became the extended monitor, with delta detection to separate true cancellations from normal unsold inventory. The waitlist came last.
Each piece started as a specific problem I had not solved yet. That is not bad product management. That is what iteration looks like when you are both the PM and the user.
The actual build
The system talks directly to the booking platform's API rather than scraping the website. No browser. No Chrome window left open in the background. The whole thing runs on a GCP e2-micro VM in Oregon, free tier, at about 22 MB of RAM.
Three services run continuously. A fourth fires as a daily cron at 6:55 PM Pacific.
The release monitor is the interesting one. At 6:55 PM it runs a recon scan: what slots are actually still open on the target date? It pre-builds booking payloads for only those slots. No point targeting times that are already gone. At exactly 7:00:00 PM it fires those payloads simultaneously, before confirming availability. Blind booking. If the platform opens the window at the same instant slots go live, you win the race before anyone else has refreshed their browser.
The cancellation monitor has a different constraint: a 48-hour cancellation policy. Book inside that window and you can't cancel without risking account suspension. So when it finds a slot inside 50 hours, it doesn't auto-book. It holds the slot on the booking server and sends a push notification with Book and Pass buttons. You have five minutes to respond. The slot is protected while you decide.
The notification layer is where it comes together. The monitor connects to a free notification app and sends rich alerts to my phone with interactive buttons: Book, Pass, Drop, Release, Cancel, Keep. No app to open. No tee sheet to check.
For the most common scenario, a cancellation more than 50 hours out, I never touch the booking UI at all. The monitor finds the slot, books it, and sends a confirmation. I find out after the fact.
For slots inside the 50-hour cancellation window, the monitor holds the slot on the server first so nobody else can grab it, then asks. I tap Book from my phone. The monitor releases the hold and confirms the reservation. Still no booking UI.
The extended monitor is the one exception. The 8-90 day paid window requires a non-refundable fee and a reCAPTCHA that can't be automated, so I complete that booking manually. But the monitor has already found the slot and held it. All I'm doing is showing up to pay.
I did not want a system that made me go check something. I wanted one that either handled it completely or asked me a single yes/no question.
Documentation is a product decision
The code is about 3,200 lines. The docs folder has five separate guides: a non-technical overview, a technical architecture doc, a notifications guide, a setup guide for additional users, and a waitlist guide. The README has a full configuration reference and every CLI command.
Three reasons I cared about this on a personal project.
First, I built it with the help of AI. Thorough documentation was the connective tissue between sessions, a way to hand context to the next agent without losing ground.
Second, this was a proof of concept for how I work professionally. Thorough documentation is not optional when the work matters. I held this project to the same standard.
Third, the repo is a shareable artifact. I can point anyone, or any system, at it and it has everything they need to understand what was built and how.
A personal project without documentation is a personal project that only works once.
April 4th
On March 25th, the extended monitor detected a cancellation. Saturday April 4th, North course, 10:39 AM. The system held the slot and sent me a notification. I opened the booking app, completed the booking, tapped Release.
That tee time does not exist in the normal flow of things. Prime Saturday mornings at Torrey Pines go in seconds during the 90-day window. Getting one 10 days out requires someone to cancel at exactly the right moment, with you watching.
I was not watching. The monitor was.
What you should take from this
This is not a golf story.
Most competitive booking systems follow the same pattern: scarcity, a release window, a first-mover advantage. Concert tickets. Restaurant reservations. Limited drops. The interface is designed for human speed. That is not a constraint you have to accept.
When a system rewards whoever moves first, the question is not how to refresh faster. The question is what the system is doing underneath the interface, and whether you can talk to it directly.
Find the API. Understand the rules. Build for the specific scenarios you are trying to solve. Document it like someone else will have to use it.
You will book the tee time.