Please write to Garmin protesting this situation
Its very unlikely protesting will make Garmin change their mind.
3rd party exports still contain your data but proprietory Garmin data is now deliberately excluded. This does not happen by accident!
My guess is that this is to reduce the usefulness of 3rd party data processors to help drive Garmin+ subscriptions. Its likely a business decision.
This affects me quite a lot too. I use several Garmin-specific FIT fields in Intervals.icu for custom charts and long-term analysis.
If Garmin strips those fields from the API while they are still present in the original FIT file, thatâs pretty frustrating. Manually downloading and uploading every activity isnât really a solution.
@dcrainmaker maybe you could use your Garmin contacts to raise this directly with them again? Would be great to understand if this is really intentional and if there is any chance of getting the full FIT data back through the API.
Without accurate per activity user-defined hardware inputs (crank length, wheel size, footpod calibration factor) and user-defined physiological baselines (age, weight, max HR), the math behind Force, Distance, Calories, VO2 Max and GAP calculations are downgraded, resulting in less accurate calculations.
By preventing third-party platforms from rendering full performance analytics automatically, consumers are coerced into staying within the manufacturerâs proprietary software ecosystem or forced into cumbersome manual file transfer workarounds.
@Pepe Read what you wrote again and you can see that few of those examples help make your case as none of those values changes regularly.
Age changes once a year, crank length will only change if pedals change. Footpod caliberation is undocumented in the FIT file spec. MaxHR if measured correctly will also rarely change and only decrease by approx 1 bpm a year after 50 years old. They do not need frequent updates.
The only genuine case here is for weight imho which can change frequently.
I do agree with your point, but weak arguments work opposite to your intention if you wish to present a strong case.
-
MASTER METRICS COMPARISON AND STRUCTURAL BREAKDOWN
Metric or Parameter Category | FIT Message Name | Global Msg ID | Key Field Defs or Metrics Included | Direct Garmin FIT File | Partner API Sync
Physiological Baselines | user_metrics | 79 | Age, Weight, Height, Gender, Max HR, Resting HR, FTP, LTHR, LTSpeed | Present | Stripped (Msg 79 removed)
Hardware Settings | sensor_settings | 147 | Crank Length, Manual or Auto Wheel Size, Footpod Calibration Factor (Field 11) | Present | Stripped (Msg 147 removed)
Active Sensor Binding | device_used and device_info | 22 and 23 | Msg 22 f_1 matched to Msg 23 Sensor Types (Footpod, Speed or Cadence, GPS) | Present | Stripped (Msgs 22 and 23 filtered)
VO2 max and Recovery | activity_metrics | 140 | VO2 Max (Field 7), Training Load Peak, Training Effect, Body Battery | Present | Stripped (Msg 140 removed)
Pedal Force Stream | record | 20 | Field 148 (force_stream), Force Vectors, Pedal Smoothness, Torque Effectiveness | Present | Stripped (Field 148 removed)
GAP and Stamina Streams | record and session | 20 and 18 | GAP (140 and 211), Stamina (137, 138, 205 to 207), Sweat Loss (178) | Present | Stripped (Fields removed)
GPS State and Ephemeris | epo_status, gps_event, cpe_status | 141, 326, 394 | Predictive satellite orbit data, satellite lock state, positioning events | Present | Stripped (Msgs 141, 326, 394 removed)
Interval Milestones | best_effort | 113 | Peak effort intervals, segment milestones, personal records | Present | Stripped (Msg 113 removed)
Raw Sensor Array Data | sensor_data | 160 | High-frequency raw sensor streams, secondary positioning diagnostics | Present | Stripped (Msg 160 removed)
DETAILED TECHNICAL ANALYSIS AND CORE ARGUMENTS
- Manual Profile Entry vs Systemic API Degradation
Entering age, weight, or Max HR manually into a third-party application is straightforward, but focusing on manual entry misses the core point. Those metrics served as clear examples of basic, user-entered parameters that involve no proprietary Garmin algorithms. They were provided reliably via the Garmin Activity API for years without issue and have now been systematically stripped out.
Garmin established an extraordinary, industry-leading hardware and software ecosystem precisely because of this rich metadata. Deliberately removing these fields does not protect intellectual property; instead, it degrades what used to be a seamless, open ecosystem for both athletes and third-party developers.
- The Critical Function of Activity-Level Calibration Snapshots
Garmin embeds hardware configuration settings and extensive physiological baselines directly into each FIT file to calculate real-time power, ground distance, pace, and caloric expenditure during the workout session.
Hardware Configuration Snapshots:
* Crank Length (Message 147): Vital for pedal power meters because sensors measure applied pedal force and require the exact lever arm length to calculate torque and total power (Power = Force x Crank Length x Cadence). Without this snapshot, third-party software cannot verify if wattage calculations match the physical leverage used during the ride.
* Manual or Auto Wheel Size (Message 147): Essential to convert speed sensor wheel revolution counts into accurate ground speed and distance.
* Footpod Calibration Factor Across different Paces (Message 147, Field 11): Essential to adjust for pace-dependent biomechanical shifts. Footpod algorithms rely on accelerometer integration, but running gait dynamics change significantly at different speeds. At an easy recovery pace (such as 5:30 min/km), impact forces are lower and vertical oscillation is higher, requiring a lower calibration factor (such as 100.0). At fast interval or 5K race pace (such as 3:15 min/km), flight time increases, stride cadence rises, and foot pitch changes, requiring a higher calibration factor (such as 103.0) to prevent the sensor from under-reporting distance by 3% to 4%. Stripping Message 147 prevents third-party tools from determining whether pace discrepancies across different workouts stem from footpod calibration scaling or actual stride changes. (or other source use message 22)Pedal Force Streams and Crank Length Relationships (Record Message 20, Field 148):
* Torque and Force Calculations: Power equals torque multiplied by angular velocity, where torque is the product of applied foot force and crank length. For a constant power output and cadence, a shorter crank arm provides a smaller lever arm, requiring higher applied force to produce identical wattage output. Generating 200 Watts at 90 RPM requires an effective force of 128.61 Newtons on a 165.0 mm crank versus 121.26 Newtons on a 175.0 mm crank. Evaluated force streams without the exact crank length parameter corrupt power recalculations.
* Raw Force and Torque Vectors: Modern dual-sided power meter pedals capture high-frequency circumferential force vectors and torque distribution throughout each 360-degree pedal stroke.Physiological Baseline Snapshots (user_metrics, Message 79):
* Age, Weight, Height, Gender, Max HR, Resting HR, FTP, LTHR, and LTSpeed.
* These parameters establish the exact baseline used during that specific workout session to compute Heart Rate Reserve (HRR = Max HR - Resting HR), and caloric expenditure.- The Widespread Impact of Other Stripped Messages and Fields
The degradation extends far beyond user profile snapshots and calibration settings. Stripping a wide range of operational, environmental, and diagnostic messages breaks core capabilities across third-party software:
* Hardware and Sensor Binding (Messages 22 and 23): Stripping Message 22 (device_used) and Message 23 (device_info) removes the ability to map specific time-series data streams to the physical hardware that generated them. Third-party platforms can no longer verify whether speed or pace originated from an optical watch sensor, an external chest strap, a wheel magnet or gps, what power meter, or a footpod, gps or watch accelerometer..
* Environmental and Hydration Metrics (Session Message 18, Field 178): Stripping Field 178 (est_sweat_loss) prevents endurance coaching platforms from auditing fluid loss, modeling hydration strategies, or correlating environmental heat stress with performance degradation.
* Diagnostic, Ephemeris, and GPS State Records (Messages 141, 160, 326, 394): Stripping epo_status (141), gps_event (326), cpe_status (394), and high-frequency sensor_data (160) eliminates the diagnostic metadata required to audit GPS lock loss, signal multipath errors, or receiver state changes during activity analysis.
* Segment Milestones and Peak Intervals (Message 113): Stripping best_effort (113) prevents platforms from parsing automated peak power or peak pace intervals detected natively by device firmware during the activity.- Technical Fallout Across Third-Party Applications and Multi-Athlete Coaching
* Pace-Dependent Footpod Audit Disruption: Because an athlete can use different calibration factors for recovery runs versus high-intensity speedwork, race pace, stripping the activity-level calibration factor makes it impossible for third-party platforms to evaluate workout accuracy across different pace zones.
* Corrupted Historical Re-Processing: If an athlete updates their weight, FTP, or Max HR months later, third-party analysis engines (such as Intervals.icu,) processing historical FIT files can no longer read the snapshot active at the time of the activity. They are forced to evaluate old files using current profile states.
* Broken Multi-Equipment Workflows: Athletes alternating between road bikes (170mm cranks), time-trial bikes (160mm cranks) and MTB bikes (175mm cranks) lose the ability to have third-party platforms parse the correct hardware geometry for that specific session.
* Violation of Stateless File Principles: The foundational design principle of the FIT protocol is self-containment. An activity file should be an immutable, standalone record. Stripping snapshot metadata, operational messages, and raw stream fields forces external tools to rely on external guesses rather than the true physical state recorded by the hardware at the moment of the workout.
- Manual Profile Entry vs Systemic API Degradation
With intervals.icu you can do complex analysis. But if you want to go simple, you can, and thatâs alright.
I did another detailed comparison today with a road cycling activity from an Edge 1040:
Garmin Connect original FIT: ~719 kB
FIT received by Intervals via Garmin API: ~601 kB
The actual recording itself seems intact â same number of record samples, and the important raw data like power, HR, cadence, GPS, altitude, temperature, etc. is still there.
My Connect IQ / developer fields such as a second power meter stream (Power2) and gearing data were also still present.
But quite a few Garmin-specific fields/messages were missing from the API version, including:
- Stamina / Potential Stamina
- Performance Condition
- Aerobic / Anaerobic Training Effect
- Recovery Time
- Garmin VO2max
- Estimated Sweat Loss
- Primary Benefit
- some sensor/device metadata
- workout / workout_step messages
There were also several Garmin/proprietary message types missing completely which I couldnât reliably identify.
So the core training data is still there, but quite a useful Garmin-specific analysis layer is lost.
For this test I deleted the auto-imported activity first and then uploaded the original FIT from Garmin Connect. The additional data was picked up correctly â for example the workout steps are present again.
@david â would it also work to simply upload the original Garmin FIT over the already existing auto-imported activity, without deleting it first?
Ideally Intervals would recognize it as the same activity and just replace/enrich the FIT data instead of creating a second activity.
If that works, it would be a very practical workaround for important rides: let the normal Garmin sync happen, and only upload the original FIT afterwards when the Garmin-specific fields are needed â without having to delete and re-import the activity first.
A manual upload will always create a double if it was already imported through the API.
If you plan to upload manually, then simply stop the Garmin Import, eventually filtering for the activities that you still want from the API.
Then you donât have to delete, but you need to remember that every activity must be imported manually. Which may not be too difficult if you have everything planned.
Anyway, this is a shitty situation. But looking at your list of missing metrics, they are not âyourâ data, but rather Garmin derived metrics. And I guess thatâs how they want to play it. Maybe we will get an option to subscribe to Connect+ and then get all data over the API???
Iâm actually a Connect+ subscriber â and unfortunately it makes (currently) no difference. The FIT data sent through the API is filtered exactly the same way for me.
When Strava changed their API terms for the worse, that was the reason I cancelled my subscription there.
If Garmin keeps going down the same road, theyâll lose me as a Connect+ subscriber as well. Not that theyâll notice one subscription less
â but for me itâs simply a matter of principle.
I pay for the hardware and even the subscription. I should be able to use the data with the tools I choose.
One thing that could at least make the workaround a bit less annoying: it would be really cool if the FIT import in Intervals could detect that an activity already exists and update/complete it instead of creating a duplicate.
Then we wouldnât have to manually import every activity â just the important ones where we need the missing fields. And if you forget to import one, at least the filtered Garmin version would still be there.
Anyway⌠if I get bored one evening I might have a look whether I can just automate the whole download/import process with Codex or Claude Work. ![]()
Iâve done some digging here, hoping I could make an on-device app that would take over a sync workflow out of the Connect(+) eco-system; and canât seem to find a way to do that.
There is no way for an on-device app to read activities/files on the device.
Honestly, this whole thing annoyed me enough that I spent my time (and a good pile of AI tokens) on solving it properly â because I donât believe Garmin will row back this time. March was a technical slip; September looks like a business decision, and those donât get reverted by forum threads.
So instead of the upload-and-delete dance (which, as @MedTechCD noted, always ends in duplicates because Intervals de-dupes by file hash), I wrote a small open-source bridge that keeps the official import on and adds the stripped data into the existing activity: it fetches the original FIT from Garmin Connect, compares it with what Intervals received, and writes only the missing fields and streams through the API â Stamina curve, Recovery Time, VOâmax, Performance Condition, Training Effect, Sweat Loss, grade-adjusted speed, whatever your custom fields define. No duplicates, nothing deleted, training load untouched. Backfill of the past is a single command, or let it run and it handles new activities within a minute of the import.
![]()
While I was at it: it also syncs the daily wellness data the official sync never delivers â night SpOâ, respiration, sleeping HR, Body Battery, HRV details, sleep stages, stress, readiness, logged nutrition and total burn, scores, race predictions, fitness age â with 19 charts for all of it in the chart library (âGarmin Bridgeâ).
Linux, container, or Windows with one command (pip install garmin-intervals-bridge).
More in the repo â what gets synced, the evidence from the live writes, and the caveats (Garminâs endpoints are private; a streams write sets icu_intervals_edited): github.com/futureweb/garmin-intervals-bridge.
Screenshots and a longer write-up in the separate thread.
@david â a webhook on new activity upload would make this instant instead of a one-minute poll, and cheaper for your API. Win/win?
Tremendous workâŚ
This might motivate a rethink on Garmin side or they might shutter access (but that likely would have unintended consequences).
If running in a container how do we log in to Garmin? Apologies if I missed that reading through the docs!
Thanks Ian! Login works the same in the container as on bare metal â itâs a one-off interactive step:
docker compose run --rm bridge login
run --rm gives it a terminal, so it can ask for your Garmin e-mail, password and the MFA code. The password is used once and never stored; whatâs kept are Garminâs session tokens in the mounted data/ volume (data/tokens), and they refresh themselves for about a year. Every other command (sync, watch, backfill, run) just uses those tokens. One thing to know: Garmin rate-limits logins â if you get a 429, wait an hour and try again.
Your question shows it wasnât obvious enough in the docs â Iâve just added it to the READMEâs container section.
On the âshutter accessâ point: the bridge talks to the same private API the Garmin Connect web app uses, so blocking it would mean breaking their own site. And whatever Garmin decides next, everything the tool has fetched stays with you â it archives every original FIT and every daily endpoint as JSON locally, so the data isnât lost even if the tap is turned off.
Brilliant work on the Fit file Activity API
Preserving unknown messages (like Messages 22, 79, and 147) under their original numeric keys instead of dropping them is pure awesome.
Great work @Andreas_Schnederle-W.
I was just going to say that you could just let Claude use Chrome and retrieve the fit files directly through connect, and then pass them through to Intervals. Your solution is much better!
Out of interest, I took a random run yesterday and compared the original (retrieved directly from Garmin Connect) to the one Intervals.icu got through the API. I have an old watch without any fancy metrics, but even still there was a noticeable size difference. Looks like the API re-encodes the `.fit` file completely upon request, instead of fetching the original. Among other things, the new encoder removes empty fields.
Otherwise I am untouched by this with my old watch. But it makes you wonder how long Garmin will remain âopenâ.
It was open for about 3+ years under Garth, then Garmin closed it off and Garth was sunsetâed. The repo this was based against/used had to rewrite to make garmin/cloudflare think itâs talking to a web browser (fingerprinting) so python-garminconnect did a headless browser style request to get the login.
Gonna be cat and mouse. Possibly depending on how popular the repo gets. If itâs <1% of GC users, could be unlikely Garmin would care.
Thanks Lars! Interesting data point. In my comparisons itâs not always a full re-encode: a hike from late September came through byte-identical (same SHA-256 as the Connect download), while the filtered activities lost whole message types plus the stamina record fields â so it looks like Garmin rewrites the file when it has something to strip, and your old watch may still be losing empty/optional fields in that pass. If youâre curious: garmin-intervals-bridge gap --activity-id <id> shows exactly which messages and fields differ between the original and the copy Intervals got (read-only, no --apply needed).
And yes â thatâs why the tool archives every original locally. Whatever Garmin does next, the files stay with you.
Iâm really awful with docker and my NAS has a really old docker version⌠which combine to a request of work for youâŚ
Any chance you could get it listed on https://hub.docker.com/ so I can install from there?
Done â thereâs a ready-made image now, no building needed:
docker pull Package garmin-intervals-bridge ¡ GitHub
Itâs on the GitHub Container Registry (same docker pull as Docker Hub, works with old Docker versions too), built for amd64 and arm64 so it runs on NAS boxes either way. Minimal setup without compose:
mkdir data
docker run --rm -it -v $PWD/data:/data -e INTERVALS_API_KEY=your-key ghcr.io/futureweb/garmin-intervals-bridge login
docker run --rm -v $PWD/data:/data -e INTERVALS_API_KEY=your-key ghcr.io/futureweb/garmin-intervals-bridge sync
(sync is a dry run; add --apply when it looks right, and run --apply keeps it going as one long-lived container.) If your NAS insists on Docker Hub, tell me and Iâll mirror it there.

