- Published on
Garmin Connect Personal API: Python and TypeScript Guide
The Garmin Connect Personal API gives individual users an official way to read their own Garmin Connect data. Garmin provides an official Python client; for Node.js projects, our open-source connect-personal-api-ts provides a separate, community-maintained TypeScript client for the same service.
The distinction matters: Garmin operates the API. Garmin maintains the Python reference client. We maintain the independent TypeScript client, not another Garmin data service.
This guide covers what the API does, how authentication works, and a small sleep-and-steps example in each language. Examples target Python client 1.0.0 and TypeScript client 0.1.0, checked on October 30, 2026.
What is the Garmin Connect Personal API?
It is a cloud-data API for personal projects: a training dashboard, a local data export, or a script that combines your activity and recovery records. Garmin's program overview lists activity data in JSON and FIT formats, plus health and women's health data in JSON. Personal access uses a pull model: your application asks for available data.
Supported endpoints include activity searches and details, sleep, steps, stress, heart rate, HRV and Body Battery. Check the Personal API Swagger reference for the current endpoint definitions and parameters. Available records depend on what your account actually contains; an endpoint is not a promise that every watch records every metric.
This is different from Connect IQ, which is used to build software running on Garmin devices. Reading a sleep record from Garmin Connect does not install a watch app or control a phone camera. A product such as our Garmin camera remote belongs to that separate watch-app workflow.
Personal access is for your own account. A product collecting data from multiple customers should use Garmin's business developer program, not treat a collection of personal keys as commercial authorization. See Garmin's Personal API FAQ for that boundary.
Create a Personal API key
- Sign in to Garmin Connect in a browser and open Personal API Key settings.
- Choose Create Key, review the terms and select an expiration period.
- Copy the key when it appears. Garmin displays it only once.
- Keep it in a private local file or your application's secret store, outside version control.
Garmin currently offers key lifetimes of 30, 90 or 180 days, or one year. Deleting a key also invalidates its associated access tokens. These are key-management rules, not a requirement to create a new key for every request. Source: Garmin authentication FAQ.
The examples below use an application-defined environment variable pointing to a file containing only the key:
export GARMIN_PERSONAL_API_KEY_FILE="$HOME/.config/garmin/personal-api-key"
chmod 600 "$GARMIN_PERSONAL_API_KEY_FILE"
Create that file privately first. GARMIN_PERSONAL_API_KEY_FILE is our example convention, not a variable both libraries automatically discover. Do not put a real key in a command, a public repository, a NEXT_PUBLIC_ variable or browser-delivered JavaScript.
How Personal API authentication works
There are two credentials with different jobs:
- Personal API key: used to request an access token.
- Bearer access token: used when reading data endpoints.
Garmin's authentication documentation specifies a POST to /personalapitoken-service/personal-api/personal-api-key/token with an Authorization: ApiKey ... header. Data requests then use the issued token as a bearer credential. The token response is JWT text in the official Python implementation, not a JSON object that you should assume contains an access_token field.
Tokens last up to 24 hours, or until the key expires, whichever happens first. There is no OAuth refresh token: obtain another access token with the still-valid key. Both clients handle parts of this process, but their caching and retry behavior differ.
Official Python client or community TypeScript client?
| Garmin's Python client | Our TypeScript client | |
|---|---|---|
| Maintainer | Garmin | Likenttt, independently of Garmin |
| Package | garmin-connect-personal-api-python | @likenttt/connect-personal-api-ts |
| Runtime | Python 3.12+ | Node.js 20+ |
| Typical fit | Python scripts, notebooks and a ready-made CLI | Existing Node.js and TypeScript personal projects |
| Token handling | Authenticator with a disk cache | In-memory cache when configured with an API key |
| License | Apache-2.0 | Apache-2.0 |
These requirements come from the Python package metadata and TypeScript package metadata. Neither language changes which data Garmin permits your account to access.
Use Garmin's official Python client
The official project is garmin/connect-personal-api-python. It includes a reusable client, an authenticator and the gc-personal command-line tool. It is not the same package as third-party libraries named garminconnect or python-garminconnect.
Start with Python 3.12 or newer:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install garmin-connect-personal-api-python==1.0.0
gc-personal --api-key-file "$GARMIN_PERSONAL_API_KEY_FILE" sleep --date 2026-10-29
The activation command above is for macOS/Linux. Garmin's Python README also provides Windows instructions and an optional interactive interface. Shared CLI options such as --api-key-file go before the data command.
For a Python program, explicitly pass the key-file path to the official resolver:
import os
from garmin_personal_api import (
GarminPersonalApiClient,
PersonalApiAuthenticator,
resolve_api_key,
)
api_key = resolve_api_key(key_file=os.environ["GARMIN_PERSONAL_API_KEY_FILE"])
with PersonalApiAuthenticator() as authenticator:
token = authenticator.obtain_token(api_key)
with GarminPersonalApiClient(token.access_token) as client:
sleep = client.get_daily_sleep("2026-10-29")
steps = client.get_daily_steps("2026-10-23", "2026-10-29")
print({"has_sleep": sleep is not None, "step_days": len(steps or [])})
Replace the dates with a period containing your own synced records. The sample prints availability and a count, not raw health records.
One operational detail is worth knowing: the official authenticator saves a bearer-token cache to ~/.config/garmin/connect-personal-api-bearer-token.json by default. Protect it as a credential file. A data request that receives a premature 401 does not automatically retry; the documented recovery is to obtain a token with force_refresh=True and update the client's bearer token. See the official authentication implementation and data client.
Use connect-personal-api-ts in a TypeScript project
We built connect-personal-api-ts for developers who already work in Node.js and want a typed client without adding a Python process to their personal project. It follows Garmin's public API and references the official Python client; it is not an official Garmin SDK or an endorsed replacement.
The published 0.1.0 package supports ESM and CommonJS, uses native fetch, and has no runtime dependencies. Its coverage claim is specific: 26 GET routes in a pinned public OpenAPI snapshot, not every Garmin service. Source: project documentation.
Install the client and, for this standalone example, a TypeScript runner:
npm install @likenttt/[email protected]
npm install --save-dev tsx
Use the same private key file in garmin-personal.ts:
import { readFile } from 'node:fs/promises'
import { GarminPersonalApiClient } from '@likenttt/connect-personal-api-ts'
async function main() {
const keyFile = process.env.GARMIN_PERSONAL_API_KEY_FILE
if (!keyFile) throw new Error('Set GARMIN_PERSONAL_API_KEY_FILE')
const apiKey = (await readFile(keyFile, 'utf8')).trim()
const client = new GarminPersonalApiClient({ apiKey })
const sleep = await client.getDailySleep('2026-10-29')
const steps = await client.getDailySteps('2026-10-23', '2026-10-29')
console.log({ hasSleep: sleep !== null, stepDays: steps?.length ?? 0 })
}
main().catch(() => {
console.error('Garmin request failed; check credentials, dates and connectivity')
process.exitCode = 1
})
Run it on Node.js 20+:
npx tsx garmin-personal.ts
Trimming the file contents removes the usual trailing newline. The TypeScript client obtains and caches a token in memory; it does not read or write credential files itself. With an API key, a 401 triggers one token renewal and retry. A 429 does not trigger an automatic retry loop. These behaviors are implemented in the client source.
The generated response types help with editor completion and compile-time checking. They describe a schema snapshot; they do not validate Garmin's responses at runtime. This release targets Node.js, so do not assume a browser or edge runtime works unchanged just because the HTTP transport uses fetch.
Query windows, activity downloads and other limits
A request window is not a history-retention limit. Garmin's current Swagger definitions limit steps and stress range requests to 28 days, and sleep summaries, hydration and Body Battery ranges to 31 days. Split a longer report into valid requests rather than assuming all older data is unavailable. Do not assume unlimited requests or a universal historical cutoff: consult the current endpoint documentation and handle server responses.
An activity download is not a FIT parser. Both clients can return an activity download as ZIP bytes. The TypeScript method downloadActivity(activityId) returns a Uint8Array; saving, extracting and decoding its contents are separate steps. Garmin's FIT JavaScript SDK is a different tool for working with FIT file contents.
A client wrapper does not add write permissions. Do not expect these clients to create workouts, edit a training calendar or install watch software. Those are outside the current Personal API client scope. For multi-user integrations, start with Garmin's business program rather than adapting this personal-key example into a public signup flow.
Which one should you choose?
Choose Garmin's official Python client when you want the vendor's reference implementation, a ready-made CLI, or a natural fit for an existing Python analysis workflow.
Choose connect-personal-api-ts when your personal application already runs on Node.js and you want TypeScript methods and response types in that codebase. Start with the repository's quick start and API coverage, then read one small date range before building a larger exporter.
For device-side development rather than cloud data, our Garmin screenshot workflow guide covers a separate part of building and documenting Connect IQ apps.
The code above was checked against the published client interfaces and source. No personal Garmin account was authenticated to produce this article; the examples do not claim live results for your account or region.