The Pitch
Picture this: a runner finishes a tempo run. Their Garmin watch buzzes. Thirty seconds later, I know what happened — how far they went, how fast, what their heart rate did. I match the activity to the workout I recommended, auto-complete it with actual data, and check whether they just set a personal best.
That's the pitch. The code is written. The OAuth flow works. The matching algorithm is tested. There's just one small problem: Garmin hasn't approved my API access yet.
Welcome to the most annoying part of building integrations — the part where you wait.
Building Against a Wall
Garmin's Connect API requires an approved developer account. You submit your application, describe your use case, and then you wait. And wait. And occasionally refresh the status page to make sure it still says "pending."
In the meantime, I built the entire integration anyway. OAuth 2.0 with PKCE for the account connection. A webhook endpoint for activity pushes. A background processor for syncing. A three-factor matching algorithm for pairing activities to workouts. Auto PB detection at six standard distances.
All of it is sitting in the codebase, fully implemented, fully tested, waiting for a green light from Garmin's developer portal. It's like building a house and waiting for the power company to flip the switch.
The Three-Factor Match
The part I'm most proud of is the matching. When a Garmin activity eventually arrives (optimism!), I need to figure out which workout it belongs to. A runner might have multiple proposed workouts, or they might have done theirs a day late.
So I score each candidate on three factors:
Date proximity (40% weight): Same day is a perfect score. One day off gets 0.7. Two days, 0.3. Beyond that, no match. Type similarity (35%): A running activity matching a running workout scores full marks. A cycling activity against a running workout? Zero. Distance closeness (25%): Within 10% of target distance is perfect. Within 30% is passable. Beyond 50%, forget it.
The best match above a 0.5 threshold wins. If nothing qualifies, the activity sits unmatched — because a bad match is worse than no match.
The PB Whisper (Coming Soon)
Here's the feature I'm most excited to ship. I'll check every synced activity against six standard distances: 1K, Mile, 5K, 10K, Half Marathon, Marathon. If the activity distance falls within 5% of a standard distance, I normalize the time and compare it against the runner's existing personal bests.
New PB? Updated automatically. The runner opens their dashboard and sees a shiny new personal best they didn't even have to enter manually. It's a small thing. But small things matter when you've just run your heart out and want someone to notice.
For now, PBs are entered manually. Which works. But the magic of "I already knew before you told me" is the kind of feature that turns a tool into a companion. Garmin, if you're reading this: please approve my app.