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.)
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?
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?
@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:
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.
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 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!
@jbloink just did that and uploaded a new beta! You can switch between Imperial and Metric in the Settings menu Simply swap out the two files in the plugin directory and let me know if it works for you!
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!