Health Sync — Garmin health data in your Daily Notes (beta testers wanted!)

Hey everyone,

I built this plugin for myself because I wanted my Garmin health data right next to my journal entries — steps, sleep, workouts, all in one place without copy-pasting or switching apps. It’s been working well for me, so I figured I’d share it. Free and open source.

What it does

  • Syncs 20+ metrics from Garmin Connect (steps, sleep score, HRV, resting HR, stress, body battery, SpO2, weight, and more)
  • Each workout shows up as a readable summary like hiking: 8.2 km · 157min · Ø105 bpm · 696 kcal
  • Reverse-geocodes your first GPS activity into a workout_location field
  • Auto-syncs the last 7 days when Obsidian starts
  • Backfill command for historical data
  • Works with Daily Notes in subdirectories (Day One imports, monthly folders, etc.)
  • Multi-language UI (EN, DE, ZH, JA, ES, FR)

Example frontmatter

---
steps: 15185
resting_hr: 69
sleep_score: 81
sleep_duration: 7h 43min
hrv: 39
stress: 30
hiking: 8.2 km · 157min · Ø105 bpm · 696 kcal
workout_location: Königswinter, Deutschland
---

Everything is queryable with Dataview. There’s also an optional machine-readable trainings field if you want to build more advanced dashboards.

How to install (manual for now)

  1. Download main.js and manifest.json from the latest release
  2. Drop them into .obsidian/plugins/obsidian-health-sync/
  3. Enable the plugin and log in to Garmin

Desktop only for now — the Garmin auth requires Electron’s BrowserWindow.

Looking for feedback on

  • Bugs, edge cases, unexpected behavior
  • Missing metrics you’d want to see
  • Other providers you’d like supported (Fitbit, Oura, Whoop are on the roadmap)
  • General UX — does the setup flow make sense?

GitHub: https://github.com/fcandi/obsidian-health-sync

This is a beta (v0.9.0), so expect some rough edges. Issues and feedback welcome on GitHub. Thanks for testing!

3 Likes

Hello! Thanks for making this. I’ve tried it out, and my daily notes are sorted into folders for year and month, then named YYYY-MM-DD. With the Daily Note format
YYYY/MM/YYYY-MM-DD” in the plugin.

I am getting an error that it is syncing my data to new files in my 03 folder with the following titles “YYYY-MM-18”.

Thanks for testing and catching this! The issue is fixed in v0.9.1.

Your bug: The date formatting function used JavaScript’s String.replace(), which
only replaces the first occurrence of a pattern. So a format like
YYYY/MM/YYYY-MM-DD would produce 2026/03/YYYY-MM-18 instead of
2026/03/2026-03-18. Fixed by switching to regex with the global flag. Subdirectories
(like 2026/03/) are now also created automatically when they don’t exist yet.

Other improvements in v0.9.1:

  • Duplicate frontmatter keys — If a daily note ends up with corrupt YAML (e.g.
    duplicate steps: keys from a previous sync), the plugin now detects and repairs this
    automatically instead of failing with a YAML parse error.
  • Smart Re-Sync — Data within the last 72 hours is automatically refreshed when you
    open a daily note (30 min after first sync, then every 6 hours). This means late
    Garmin watch syncs are picked up without any manual action — just wear your watch, sync
    it to your phone, and the plugin catches up on its own.
  • HRV: per-night value — HRV now uses the nightly value (lastNightAvg) instead of
    the weekly average, so you get meaningful day-to-day variation in your notes.
  • Removed: Hydration metric — Hydration requires manual input on Garmin Connect and
    isn’t sensor-tracked, so it has been removed from the metrics list.

Please update and let me know if the nested folder format works for you now!

Thanks for fixing the issue in the update! Apologies if this is clearly user error, but I can’t seem to find the new main.js file on github to download?

Hi! Totally my fault — I accidentally forgot to attach the compiled main.js to the release.
It’s fixed now! :slightly_smiling_face:

Head over to Releases → 0.9.1,

download main.js and manifest.json, and replace the existing files in your plugin folder:

.obsidian/plugins/obsidian-health-sync/

Then reload Obsidian and you should be good to go!

1 Like

Hey there,

version 0.9.2 is out now! Would love it if you guys could give it a test run! :blush:

Thanks for sharing. It seems not support [Garmin connect in China]( Garmin Connect | Sign In ). Could be kind enough to make it compatible?

Garmin official website offer a selection for changing geo location. You can check it here: Garmin | Select a Location .

I change some contents in file main.js to:

var O="https://connect.garmin.com.cn",H=`${O}/app`,Te=`${O}/modern`,Re="https://sso.garmin.cn/portal/sso/zh-CN/sign-in",
```

Relaunch obsidian, and it works. Hope you can improve to make it available to change garmin server location when login. Thanks!

1 Like

Thanks for testing! I had no idea there was a separate Chinese server tbh. I’ll get that implemented and when you’re ready, I’d love to have you test the new version before I add it to the official version. Does this look good? :+1:

@direct I’ve added a Server region setting so you can switch between International and China without
editing main.js. Here’s a pre-release build for testing:

https://github.com/fcandi/Garmin-Health-Sync/releases/tag/v0.9.4-beta.1

Install

  1. Download main.js, manifest.json, styles.css from the release
  2. Copy into .obsidian/plugins/garmin-health-sync/ (replace existing)
  3. Restart Obsidian
  4. Settings → Garmin Health Sync → Server region → China (garmin cn)
  5. Log in with your garmin-cn account

I can’t test the China servers myself — would be great if you could try it and report back! If it works, I’ll ship it in the next release.

The improvement is great. Login with cn account works.

Here, I have another question. Just for discussion: does this useful plugin rely on Period Notes or Daily Notes plugin? My idea is: use garmin plugin like this to download or sync or pull health(sports) data from garmin connectto `obsidian` markdown file(s), and then reference or query health data from any file including Daily Notes in obsidian.

My tradition is that: daily notes generated by plugin Daily Notes are highly structured and composed of dataview blocks where several queries happen.

Just a discussion. It would be nice if this plugin is not constricted to Period or Daily Notes plugin.

Hey, glad to hear the CN login works :slight_smile:

Good question — and the short answer is: no, the plugin does not depend on Periodic Notes or Daily Notes plugin at all. It only checks for them to auto-detect your daily note folder path, but you can configure everything manually.

So here’s the thing — what you’re describing is actually already possible with the current setup:

You can point the plugin to its own separate folder (e.g. Garmin/) instead of your actual daily notes folder. The plugin will create its own markdown files there with all the health data stored as YAML frontmatter — steps, sleep, HR, HRV, stress, trainings, the whole thing.

Then from your daily notes, you just query that data with Dataview. Something like:

TABLE steps, sleep_score, resting_hr, hrv, stress
  FROM "Garmin"
  WHERE file.name = this.file.name

That way your daily notes stay 100% yours, structured however you like, and the Garmin data just lives in its own corner of the vault, ready to be pulled in wherever you need it.

So basically: the plugin writes the data, Dataview reads it, your daily notes stay clean. Best of both worlds.

Let me know if you run into any issues setting it up that way!

Thanks. It works as you described.

Another suggestions:

  1. In the plugin setup UI, let the user to download garmin data from a given date. It would be useful since many garmin users have data for years.
  2. How to fetch running information such as kilometer, duration, heart rate (max, min, average) and so on ?

Thanks for the feedback! Glad it’s working for you.

Backfill / historical data: This feature actually already exists! You can access it through Obsidian’s Command Palette (Cmd/Ctrl+P on Mac, Ctrl+P on Windows) — search for “Backfill health data” and it will open a dialog where you pick a start and end date. It then fetches all data for that range.

I realize this isn’t very discoverable if you’re not used to the Command Palette, so I’ll make it more prominent in the README. I may also add a shortcut button in the settings tab.

Workout details (distance, duration, heart rate etc.): The plugin already syncs some of this — for each activity you should see distance (km), duration, average heart rate, and calories. You can find these in the daily note’s frontmatter under trainings (structured data) and as human-readable strings like running: "8.2 km · 45min · Ø152 bpm · 420 kcal".

That said, I intentionally keep the data somewhat compact to avoid cluttering the daily notes. Garmin’s API provides a lot of fields per activity, and dumping everything would make the notes hard to read. So the current approach focuses on the key summary metrics.

But I’d love to hear from you: which specific fields matter most to you? For example:

  • Max / min heart rate (in addition to average)?
  • Pace (min/km)?
  • Elevation gain?
  • Training effect / VO2max?
  • Heart rate zones?

Knowing what’s most useful for your workflow helps me prioritize without overloading the output. Happy to add the most requested fields in a future update!

This is really cool! Thanks for creating it. Is there a way to change from km to miles?

1 Like

Thanks! Super happy the plugin is useful for others too :raising_hands:

And yeah, totally valid point about miles vs kilometers - I’ll push a new version tomorrow, should be a quick fix!

@jbloink just did that and uploaded a new beta! You can switch between Imperial and Metric in the Settings menu :+1:Simply swap out the two files in the plugin directory and let me know if it works for you!

https://github.com/fcandi/Garmin-Health-Sync/releases/tag/0.9.5

1 Like

Great. Thanks for your improvement.

  1. A button for backfill data would be better.
  2. Seems that yaml does not render “training“ pretty. See the screenshot.
  3. date format “ddd“ is not recognized (since I would like to see which day it is in a week). “Garmin YYYY-MM-DD-ddd“

Hey @direct

Thanks for the feedback :grinning_face:

Backfill button: You can do that yourself! The plugin already registers a backfill command in Obsidian’s command palette. With the Commander plugin you can assign it to a button and place it wherever you like in the UI.

Training YAML: That’s intentional — it’s meant to be machine-readable (e.g. for Dataview queries). If you don’t need it, you can simply disable it in the plugin settings.

ddd date format: Good catch! Our custom date formatter only handles the basics right now. I’ll fix this by switching to moment.js (which Obsidian already bundles), so all format tokens Obsidian itself supports will work. Coming in the next releas!