Withings to Garmin Instant Sync

A real-time bridge between Withings scales and Garmin Connect, because life’s too short to wait to be sassed about my Watts per Kilogram

Because Being Sassed About My Watts per Kilogram Won’t Wait

The Spark

I’m deep in the Garmin ecosystem for fitness tracking, but have a Withings scale in my bathroom. There are great utilities out there for doing periodic syncs between Withings and Garmin Connect, but nothing works instantaneously.

I might be a little obsessed with my lack of Watts per kilogram on the bike (power-to-weight ratio) and wanted to make sure Garmin has all the data it needs to do its calculations in advance of a workout. Without forcing a manual sync.

Yes I could have used MyFitnessPal. Really I wanted an integration mission. How well could Claude work from available code to access APIs, and cook something home-brewed?

So I thought: webhooks exist. APIs exist. ngrok exists. I haven’t worked with any of this stuff – but can I get Claude to orchestrate, and build a real-time bridge?

The Journey

Withings has webhooks that fire the moment you step off the scale. Garmin has an API. The plan Claude and I concocted was : Build a Flask app to catch the webhook, fetch the data, push it to Garmin. Ship it.

Except.. Claude kept falling back to an old version of the Garmin libraries, which failed in annoying ways. Claude would occasionally try the same failed approach multiple times in a row. I ended up having to wade in and ask it to take a different approach a few times.

This is where I learned about claude.md files – a way to leave persistent instructions for Claude so it doesn’t keep circling back to the same dead ends. “Don’t try library version X, it breaks dependency Y” etc.

Again: as a weekend project, I cooked up something with webhooks, OAuth token refresh logic, the duplicate detection (because you don’t want to accidentally upload the same weight five times), an ngrok tunnel for local testing. All new territory for me. All in place in a few evening jam sessions with Claude.

What I Learned

The biggest learning was about productive collaboration with AI coding assistants.

Galton’s Goalie was pure forward momentum. This one was about needing to actively guide the AI away from patterns it wants to repeat. The claude.md file became my “lessons learned” document that persisted across conversations.

In future I will ask Claude to memorialize changes there more often. Make a habit of asking it to be updated, just like I would the readme.md on GitHub.

Why Bother?

This one is a bit of a stretch; I just started using this myself, and seeing my weight appear in Garmin Connect seconds after stepping off the scale is satisfying.

The really interesting thing here, that in my honest opinion is totally wild: this is a Side Quest that would have made no practical sense before GenAI. But now it’s a perfect example of solving a real friction point in your daily life. Now it’s infrastructure I’ll use every day..

For now, anyway! I have a cunning plan to get this off my local machine and running in the cloud so it’s always available. That’s the follow-up mission.

Try It Yourself

The full code is on GitHub: withings-garmin-webhook-sync

You’ll need:

  • Python 3.12+
  • A Withings account with a smart scale
  • A Garmin Connect account
  • Withings API credentials (free developer account)
  • ngrok (for webhook testing) or a cloud deployment

The README has detailed setup instructions including the OAuth dance for both platforms, webhook configuration, and all the environment variables you need. Fair warning: you’ll be storing Garmin credentials locally in plaintext (limitation of the unofficial library), so don’t run this on a shared machine.

Once configured, it runs as a Flask app that listens for Withings webhooks and instantly syncs your measurements to Garmin. You can also manually trigger syncs for historical data.


Built with: Python, Flask, Withings API, unofficial Garmin Connect library, ngrok, and a healthy dose of “why is this dependency version wrong?”