Repository navigation
get_goals() returns empty results for goals visible in current Garmin Connect UI #431
Description
Activity
Really solid diagnostic work here — confirmed the current
get_goals()implementation (__init__.py) does exactly what you tested manually against/goal-service/goal/goals, with the same params, same pagination. So this isn't a code bug on our side — the endpoint is being called correctly, it just doesn't have this goal.Conclusion: Garmin's newer Goals UI (custom accumulation goals, custom date ranges) appears to be backed by a different endpoint than the legacy
/goal-service/goal/goalsthis library queries. TheTaxuspt/garmin_mcpPR's "drop thestatusparam" workaround doesn't apply here either — you already showed that 400s on your account, so it's not just a missing/extra param on the same endpoint; the legacy endpoint likely doesn't carry these newer goal types at all.I don't have a live account with one of these newer goals to discover the real endpoint against, so I can't chase this further blind. You offered to help — the most useful next step:
- Open the Garmin Connect website (connect.garmin.com), not the mobile app.
- Open browser DevTools → Network tab, filter by Fetch/XHR.
- Navigate to the page showing this cycling distance goal.
- Find the request that loads it — endpoint path, method, query params, and (sanitized, no personal values needed) response shape.
That'll tell us the real endpoint and field names to add support for. Happy to help wire it up once we know what it actually is.
Looks like it does a
GETtohttps://connect.garmin.com/gc-api/goal-service/goal/goals?status=activeResponse:
[{"id":41139679,"name":"GCC 2026","type":"distance_accumulation","distanceInMeters":160934.0,"durationInSeconds":null,"caloriesInKiloCalories":null,"numberOfActivities":null,"startDate":"2026-09-01","activityType":"cycling","period":"one_month","privacy":"public","progress":{"percent":17,"days":17,"distanceInMeters":28089.0,"durationInSeconds":null,"caloriesInKiloCalories":null,"numberOfActivities":null},"remaining":{"percent":83,"days":13,"distanceInMeters":132845.0,"durationInSeconds":null,"caloriesInKiloCalories":null,"numberOfActivities":null},"overage":{"percent":0,"days":0,"distanceInMeters":0.0,"durationInSeconds":null,"caloriesInKiloCalories":null,"numberOfActivities":null},"endDate":"2026-09-30","active":true,"completed":false}]It also does a
GETtohttps://connect.garmin.com/gc-api/goal-service/goal/goals?status=futureandhttps://connect.garmin.com/gc-api/goal-service/goal/goals?status=past&start=1&limit=100&sortOrder=descI narrowed this down further. The
Sec-Fetch-Site: same-originrequest header appears to be significant.Using the request copied from Garmin Connect as cURL returns my active goal as expected. If I remove only:
-H 'Sec-Fetch-Site: same-origin'the request no longer returns my active goal.
Restoring that header causes the goal to be returned again.
This may explain why the Garmin Connect web UI returns goals while
python-garminconnectreceives an empty response from the same/goal-service/goal/goals?status=activeendpoint.That's the root cause — great isolation work with the header-by-header curl test. Confirmed: `get_goals()` now sends `Sec-Fetch-Site: same-origin` explicitly. PR: #434
Browsers send that header automatically on any same-origin fetch; this client doesn't send any `Sec-Fetch-*` headers otherwise since it presents as a native/API client, not a browser page — so it was silently missing exactly the one header the newer goal-type response apparently gates on.
Confirmed the
Sec-Fetch-Site: same-originchange in 0.3.16 is necessary and works, but I found a second issue preventingget_goals()from returning goals.The
startparameter appears to be 1-based rather than 0-based.Testing through
api.connectapi()with the new header:
status=active -> goal returned
status=active&start=0 -> []
status=active&start=1 -> goal returned
status=active&limit=30 -> goal returned
status=active&sortOrder=asc -> goal returned
status=active&start=0&limit=30 -> []
status=active&start=1&limit=30 -> goal returned
status=active&start=0&limit=30&sortOrder=asc -> []
status=active&start=1&limit=30&sortOrder=asc -> goal returnedapi.get_goals("active")still returns[]because it currently starts pagination at0.I also tested the exact past-goals request observed in Garmin Connect:
status=past&start=1&limit=100&sortOrder=desc
and it successfully returned my historical goals.It therefore looks like
get_goals()needs to start pagination at1instead of0.- added a commit that references this issue
on Sep 18, 2026 - added a commit that references this issue
on Sep 20, 2026
get_goals()returns an empty list even though I have an active goalvisible in Garmin Connect.
I originally encountered this through
Taxuspt/garmin_mcp:Taxuspt/garmin_mcp#317
However, I have reproduced the behavior directly with
python-garminconnect, outside of the MCP server.The active goal is a cycling distance accumulation goal created through
the current Garmin Connect Goals UI. It has a custom date range and a
target of 100 miles.
Testing
I initially reproduced this using
garminconnect==0.3.2, which is theversion currently pinned by
Taxuspt/garmin_mcp.Result:
I then tested the underlying endpoint directly:
Result:
I also tested
pastandfuture, which both return empty lists.Calling the endpoint without a
statusparameter:returns:
Because of that error, I also retrieved the ID from
get_user_profile()and explicitly supplied it as
userId:This still returns:
The same is true for
pastandfuturewhenuserIdis explicitlysupplied.
Current version
Before filing this issue, I upgraded to
garminconnect==0.3.15andrepeated the test.
The problem is still reproducible with 0.3.15.
get_goals("active")continues to return an empty list despite the goal being present and
active in the Garmin Connect UI.
Related investigation
There is also a proposed fix in
Taxuspt/garmin_mcp:Taxuspt/garmin_mcp#325
That PR proposes querying
/goal-service/goal/goalswithout the legacystatusparameter and parsing the newer Connect UI goal formatseparately.
On my account, however, querying that endpoint without
statusresultsin:
so that approach does not appear to work against my live account as
currently implemented.
Expected behavior
get_goals("active")should return the active cycling distance goalshown in Garmin Connect, including its target, date range, and current
progress.
Actual behavior
returns:
despite the goal being visible and active in Garmin Connect.
Additional notes
This appears to be related specifically to goals created/displayed
through Garmin Connect's current Goals UI rather than the older goal API
behavior.
I'm happy to run additional API calls or provide sanitized response data
from my account if that would help identify the endpoint or parameters
now used by Garmin Connect.