Fast, script-friendly CLI for Garmin Connect. Access activities, health data, body composition, workouts, courses, devices, gear, goals, badges, and more. JSON-first output, multiple accounts, and secure credential storage built in.
- Activities — list, search, view details, download (FIT/GPX/TCX/KML/CSV), upload, create manual entries (with date), rename, retype, delete, set exercise sets for strength training
- Exercise Catalog — browse Garmin's exercise categories and exercises for strength training
- Health Data — daily summaries, steps, heart rate, resting HR, sleep, stress, HRV, SpO2, respiration, body battery, floors, training readiness/status, VO2max, fitness age, race predictions, endurance/hill scores, intensity minutes, lactate threshold, cycling FTP
- Body Composition — weight tracking, body fat, muscle mass, blood pressure, FIT file encoding for composition uploads
- Workouts — list, view, download as FIT, upload from JSON, create with sport types and targets (pace/HR/power/cadence), schedule (add/list/remove), delete
- Courses — list courses, view favorites, get full course detail, import GPX files as new courses, send courses directly to a device, delete courses
- Devices — list registered devices, view settings, solar data, alarms, primary/last-used device
- Gear — list gear, usage stats, linked activities, defaults per activity type, link/unlink to activities
- Goals & Badges — active goals, earned/available/in-progress badges, challenges, personal records
- Training — browse and view training plans
- Profile — user profile and settings
- Hydration — view and log daily water intake
- Nutrition — view daily food logs, meals, and nutrition settings
- Events — list, add, and delete calendar events (races, group rides, etc.) with goals and training priority support
- Wellness — menstrual cycle data, pregnancy summary
- Multiple accounts — manage multiple Garmin accounts via
--accountflag - Secure credential storage using OS keyring (macOS Keychain, Linux Secret Service, encrypted file fallback)
- Auto-refreshing tokens — authenticate once, tokens refresh automatically on 401
- Resilient networking — automatic retry on 429/5xx with exponential backoff, circuit breaker for fault tolerance
- Shell completion — generated scripts for bash, zsh, fish, and PowerShell
- Parseable output — JSON and plain/TSV modes for scripting and automation
brew install bpauli/tap/gccliRequires Go 1.24+.
git clone https://github.com/bpauli/gccli.git
cd gccli
make buildThe binary is output to ./bin/gccli.
Run:
./bin/gccli --helpHelp:
gccli --helpshows top-level command groups.- Drill down with
gccli <group> --help(and deeper subcommands). - Make shortcut:
make run -- --help(ormake run -- activities --help).
gccli auth login you@example.comThis opens your browser for Garmin SSO authentication. The OAuth tokens are stored securely in your system keyring.
For servers or environments without a browser:
gccli auth login you@example.com --headlessYou'll be prompted for your password. If your account has two-factor authentication:
gccli auth login you@example.com --headless --mfa-code 123456Login automatically saves your email as the default account, so you don't need to pass --account or set GCCLI_ACCOUNT on every command.
gccli auth status
gccli activities list --limit 5gccli stores your OAuth tokens in a keyring backend. Default is auto-detection (best available backend for your OS/environment).
List current auth state:
gccli auth statusPrint the raw OAuth2 access token (useful for scripting):
gccli auth tokenRemove stored credentials:
gccli auth removeBackends:
- auto (default) — picks the best backend for the platform
- keychain — macOS Keychain
- secret-service — Linux D-Bus (GNOME Keyring, KWallet)
- file — encrypted on-disk keyring (fallback)
Set backend via environment variable:
export GCCLI_KEYRING_BACKEND=fileOr in the config file (config.json):
{
"keyring_backend": "file"
}On Linux, if D-Bus is unavailable, gccli automatically falls back to the file backend.
For Garmin China accounts (garmin.cn):
export GCCLI_DOMAIN=garmin.cnOr in config.json:
{
"domain": "garmin.cn"
}The account is resolved in this order:
--accountflagGCCLI_ACCOUNTenvironment variable- Default account saved by
gccli auth login(stored inconfig.json)
# Via flag
gccli activities list --account you@example.com
# Via environment
export GCCLI_ACCOUNT=you@example.com
gccli activities list
# Via login default (no flag or env var needed)
gccli auth login you@example.com
gccli activities list- Default: human-friendly tables on stdout.
--plain: stable TSV on stdout (best for piping).--json/-j: JSON on stdout (best for scripting).- Human-facing messages (errors, warnings, info) go to stderr.
- Colors are enabled by default in TTY mode and disabled for
--jsonand--plain.
Config path:
- macOS:
~/Library/Application Support/gccli/config.json - Linux:
~/.config/gccli/config.json(or$XDG_CONFIG_HOME/gccli/config.json)
Example:
{
"default_account": "you@example.com",
"keyring_backend": "file",
"domain": "garmin.com"
}| Variable | Description |
|---|---|
GCCLI_ACCOUNT |
Default account email (overrides config file default) |
GCCLI_DOMAIN |
Garmin domain (garmin.com or garmin.cn) |
GCCLI_JSON |
Enable JSON output (1, true, yes) |
GCCLI_PLAIN |
Enable plain/TSV output (1, true, yes) |
GCCLI_COLOR |
Color mode: auto, always, never |
GCCLI_KEYRING_BACKEND |
Keyring backend: keychain, secret-service, file |
OAuth tokens are stored securely in your system's keyring:
- macOS: Keychain Access
- Linux: Secret Service (GNOME Keyring, KWallet)
- Fallback: Encrypted on-disk file store
The CLI uses github.com/99designs/keyring for secure storage.
Tokens are keyed by email (gccli:token:<email>) and never stored in plaintext files.
gccli auth login <email> # Log in via browser SSO
gccli auth login <email> --headless # Log in via email/password
gccli auth login <email> --headless --mfa-code <code> # With MFA
gccli auth status # Show auth state and token expiry
gccli auth token # Print OAuth2 access token
gccli auth export # Export credentials (for transfer to another machine)
gccli auth import <token> # Import credentials from another machine
gccli auth remove # Remove stored credentials# List and search
gccli activities list --limit 20 --start 0
gccli activities list --type running
gccli activities count
gccli activities search --start-date 2024-01-01 --end-date 2024-12-31
# View details
gccli activity summary <id>
gccli activity details <id>
gccli activity splits <id>
gccli activity typed-splits <id>
gccli activity split-summaries <id>
gccli activity weather <id>
gccli activity hr-zones <id>
gccli activity power-zones <id>
gccli activity exercise-sets <id>
gccli activity exercise-sets set <id> -e "BENCH_PRESS/BARBELL_BENCH_PRESS:12@20:d30:r60" -e "BENCH_PRESS/BARBELL_BENCH_PRESS:10@25:d25"
gccli activity gear <id>
# Download and upload
gccli activity download <id> --format fit
gccli activity download <id> --format gpx --output track.gpx
gccli activity upload ./activity.fit
# Create and modify
gccli activity create --name "Morning Run" --type running --duration 30m --distance 5000
gccli activity create --name "Upper Body" --type strength_training --duration 34m --date 2026-03-13T19:01:00
gccli activity rename <id> "New Name"
gccli activity retype <id> --type-id 1 --type-key running
gccli activity delete <id>
gccli activity delete <id> --force# Daily summary
gccli health summary # Today
gccli health summary yesterday
gccli health summary 2024-06-15
gccli health summary 3d # 3 days ago
# Vitals
gccli health steps # Step chart for today
gccli health steps daily --start 2024-01-01 --end 2024-01-31
gccli health steps weekly --weeks 4
gccli health hr [date] # Heart rate
gccli health rhr [date] # Resting heart rate
gccli health floors [date] # Floors climbed
gccli health sleep [date] # Sleep data
gccli health respiration [date]
gccli health spo2 [date] # Blood oxygen
gccli health hrv [date] # Heart rate variability
# Stress and recovery
gccli health stress # Stress for today
gccli health stress weekly --weeks 4
gccli health body-battery [date]
gccli health body-battery range --start 2024-01-01 --end 2024-01-07
gccli health training-readiness [date]
gccli health training-status [date]
# Fitness metrics
gccli health fitness-age [date]
gccli health max-metrics [date] # VO2max and more
gccli health lactate-threshold
gccli health cycling-ftp
gccli health race-predictions
gccli health race-predictions range --start 2024-01-01 --end 2024-06-30
gccli health endurance-score [date]
gccli health hill-score [date]
gccli health intensity-minutes [date]
gccli health intensity-minutes weekly --start 2024-01-01 --end 2024-01-31
# Wellness events
gccli health events [date]
gccli health lifestyle [date]# View data
gccli body composition # Today
gccli body composition --start 2024-01-01 --end 2024-01-31
gccli body weigh-ins --start 2024-01-01 --end 2024-01-31
gccli body daily-weigh-ins [date]
# Add data
gccli body add-weight 75.5 --unit kg
gccli body add-weight 166.4 --unit lbs
gccli body add-composition 75.5 --body-fat 15.2 --muscle-mass 35.0
# Blood pressure
gccli body blood-pressure --start 2024-01-01 --end 2024-01-31
gccli body add-blood-pressure --systolic 120 --diastolic 80 --pulse 65
# Delete entries
gccli body delete-weight <pk> --date 2024-01-15
gccli body delete-blood-pressure <version> --date 2024-01-15gccli workouts list --limit 20
gccli workouts detail <id>
gccli workouts download <id> --output workout.fit
gccli workouts upload ./workout.json # See JSON structure below
gccli workouts schedule add <id> <YYYY-MM-DD>
gccli workouts schedule list <YYYY-MM-DD>
gccli workouts schedule list --start 2024-06-01 --end 2024-06-30
gccli workouts schedule remove <schedule-id>
gccli workouts schedule remove <schedule-id> --force
gccli workouts delete <id>
# Create a running workout with pace targets
gccli workouts create "Easy 30min Run" --type run \
--step "warmup:5m@pace:5:30-6:00" \
--step "run:20m@pace:5:00-5:30" \
--step "cooldown:5m"
# Running with heart rate targets
gccli workouts create "HR Zone Run" --type run \
--step "warmup:10m" \
--step "run:20m@hr:140-160" \
--step "cooldown:10m"
# Cycling with power targets
gccli workouts create "FTP Intervals" --type bike \
--step "warmup:10m" \
--step "run:5m@power:250-280" \
--step "recovery:3m" \
--step "run:5m@power:250-280" \
--step "cooldown:10m"
# Imperial paces (miles)
gccli workouts create "Easy 30min Run" --type run \
--step "warmup:5m@pace:8:51-9:39" \
--step "run:20m@pace:8:03-8:51" \
--step "cooldown:5m" \
--unit mi
# Strength workout (no targets)
gccli workouts create "Full Body" --type strength \
--step "warmup:5m" \
--step "run:30m" \
--step "cooldown:5m"Workout JSON structure for gccli workouts upload:
{
"workoutName": "Tempo Run",
"sportType": {
"sportTypeId": 1,
"sportTypeKey": "running"
},
"workoutSegments": [
{
"segmentOrder": 1,
"sportType": {
"sportTypeId": 1,
"sportTypeKey": "running"
},
"workoutSteps": [
{
"type": "ExecutableStepDTO",
"stepOrder": 1,
"stepType": { "stepTypeId": 1, "stepTypeKey": "warmup" },
"endCondition": { "conditionTypeId": 2, "conditionTypeKey": "time" },
"endConditionValue": 600,
"targetType": { "workoutTargetTypeId": 1, "workoutTargetTypeKey": "no.target" }
},
{
"type": "ExecutableStepDTO",
"stepOrder": 2,
"stepType": { "stepTypeId": 3, "stepTypeKey": "interval" },
"endCondition": { "conditionTypeId": 2, "conditionTypeKey": "time" },
"endConditionValue": 1200,
"targetType": { "workoutTargetTypeId": 6, "workoutTargetTypeKey": "pace.zone" },
"targetValueOne": 3.333333,
"targetValueTwo": 3.030303
},
{
"type": "ExecutableStepDTO",
"stepOrder": 3,
"stepType": { "stepTypeId": 2, "stepTypeKey": "cooldown" },
"endCondition": { "conditionTypeId": 2, "conditionTypeKey": "time" },
"endConditionValue": 600,
"targetType": { "workoutTargetTypeId": 1, "workoutTargetTypeKey": "no.target" }
}
]
}
]
}Key reference values:
- Sport types: running (1), cycling (2), other (3), swimming (4), strength_training (5), cardio_training (6), yoga (7), pilates (8), hiit (9), multi_sport (10), mobility (11)
- Step types: warmup (1), cooldown (2), interval (3), recovery (4), rest (5), other (7)
- Target types: no.target (1), power.zone (2), cadence (3), heart.rate.zone (4), pace.zone (6)
- End condition: time (2) — value in seconds
- Pace values: in m/s (e.g., 5:00/km = 1000/300 = 3.333 m/s)
# List all exercise categories
gccli exercises list
# List exercises in a category
gccli exercises list -c BENCH_PRESS
# Full catalog as JSON
gccli exercises list --jsongccli courses list # List all courses
gccli courses favorites # List favorite courses
gccli courses detail <id> # View full course detail
gccli courses import route.gpx # Import GPX as new course (default: cycling, private)
gccli courses import route.gpx --name "Ride" # Import with custom name
gccli courses import route.gpx --type hiking # Override activity type
gccli courses import route.gpx --privacy 1 # Import as public course
gccli courses send <course-id> <device-id> # Send course to a device
gccli courses delete <id> # Delete a course
gccli courses delete <id> -f # Delete without confirmationgccli devices list
gccli devices settings <device-id>
gccli devices primary
gccli devices last-used
gccli devices alarms
gccli devices solar <device-id> --start 2024-06-01 --end 2024-06-30gccli gear list
gccli gear stats <uuid>
gccli gear activities <uuid> --limit 20
gccli gear defaults
gccli gear link <uuid> <activity-id>
gccli gear unlink <uuid> <activity-id>gccli goals list
gccli goals list --status active
gccli badges earned
gccli badges available
gccli badges in-progress
gccli challenges list
gccli challenges badge
gccli recordsgccli profile
gccli profile settingsgccli hydration [date] # View hydration data
gccli hydration add 500 # Log 500ml of water
gccli hydration add 500 --date 2024-06-15gccli nutrition [date] # View daily food log
gccli nutrition meals [date] # View meal summaries
gccli nutrition settings [date] # View nutrition settingsgccli training plans --locale en
gccli training plan <id>gccli events list # List upcoming events
gccli events list --start 2024-01-01 --limit 50
gccli events list --sort eventDate_desc
gccli events delete <id> # Delete an event (with confirmation)
gccli events delete <id> -f # Delete without confirmation
# Add a race event
gccli events add --name "Berlin Marathon" --date 2026-09-27 --type running \
--race --location "Berlin, Germany" --distance 42.195km \
--time 09:15 --timezone Europe/Berlin
# Add an event with a goal and training priority
gccli events add --name "Spring 10K" --date 2026-05-10 --type running \
--race --distance 10km --goal 40m --trainingEvent flags:
- Required:
--name,--date(YYYY-MM-DD, today, +30d),--type(running, trail_running, cycling, gravel_cycling, mountain_biking, swimming, triathlon, multi_sport, hiking, walking, fitness_equipment, motorcycling, winter_sport, other) - Optional:
--race,--location,--time(HH:MM),--timezone,--distance(e.g. 10km, 26.2mi, 400m),--private,--note,--url - Goal & training priority:
--goal(duration, e.g. 50m, 1h30m, 2400s),--primaryor--training(mutually exclusive)
gccli wellness menstrual-cycle --start-date 2024-01-01 --end-date 2024-03-31
gccli wellness menstrual-summary --start-date 2024-01-01 --end-date 2024-03-31
gccli wellness pregnancy-summarygccli reload # Reload today's data
gccli reload 2024-06-15 # Reload specific dateGenerate completion scripts for your shell:
gccli completion bash
gccli completion zsh
gccli completion fish
gccli completion powershellTo enable completions, add the appropriate line to your shell profile:
Bash (~/.bashrc):
source <(gccli completion bash)Zsh (~/.zshrc):
source <(gccli completion zsh)Fish (~/.config/fish/config.fish):
gccli completion fish | sourcePowerShell ($PROFILE):
gccli completion powershell | Invoke-ExpressionCompletions cover all commands, subcommands, flags, and enum flag values (e.g. --color auto|always|never).
Human-readable output with colors:
$ gccli activities list --limit 3
ID NAME TYPE DATE
123456789 Morning Run running 2024-06-15
123456780 Evening Walk walking 2024-06-14
123456771 Cycling Workout cycling 2024-06-13Machine-readable output for scripting and automation:
$ gccli --json activities list --limit 3
[
{
"activityId": 123456789,
"activityName": "Morning Run",
"activityType": {"typeKey": "running"},
"startTimeLocal": "2024-06-15 07:30:00"
},
...
]Data goes to stdout, errors and progress to stderr for clean piping:
gccli --json activities list --limit 100 | jq '.[] | select(.activityType.typeKey == "running")'Stable, tab-separated output for scripting:
$ gccli --plain activities list --limit 3
123456789 Morning Run running 2024-06-15
123456780 Evening Walk walking 2024-06-14
123456771 Cycling Workout cycling 2024-06-13gccli --json activities search --start-date 2024-05-15 --end-date 2024-06-15 --limit 100 | \
jq -r '.[] | select(.activityType.typeKey == "running") | .activityId' | \
while read id; do
gccli activity download "$id" --format gpx --output "run_${id}.gpx"
donegccli --json health summary | jq '{
steps: .totalSteps,
calories: .totalKilocalories,
distance_km: (.totalDistanceMeters / 1000),
active_minutes: .moderateIntensityMinutes + .vigorousIntensityMinutes
}'gccli --json body weigh-ins --start 2024-01-01 --end 2024-06-30 | \
jq -r '.dailyWeightSummaries[] | [.summaryDate, .weight.value] | @tsv'latest=$(gccli --json activities list --limit 1 | jq -r '.[0].activityId')
gccli activity download "$latest" --format fitAll commands support these flags:
| Flag | Description |
|---|---|
--account <email> |
Account to use (overrides GCCLI_ACCOUNT and config default) |
--json, -j |
Output JSON to stdout |
--plain |
Output stable TSV to stdout |
--color <mode> |
Color mode: auto, always, never (default: auto) |
--version |
Print version information |
--help |
Show help for any command |
Many commands accept flexible date formats:
| Format | Example | Description |
|---|---|---|
YYYY-MM-DD |
2024-06-15 |
Explicit date |
today |
Today's date | |
yesterday |
Yesterday's date | |
Nd |
3d, 7d |
N days ago |
After cloning, install tools:
make toolsBuild, test, and lint:
make build # Build to ./bin/gccli
make test # Unit tests with race detector
make lint # golangci-lint
make fmt # Format with goimports + gofumpt
make ci # Full CI gate (fmt-check + lint + test)Run individual tests:
go test -run TestFuncName ./internal/pkg/...End-to-end tests hit the real Garmin Connect API. They require a .env file with test credentials:
cp .env.example .env
# Edit .env with your test account credentials
make test-e2eWarning: E2E tests create and delete activities/workouts. Use a dedicated test account.
Inspired by gogcli. API coverage based on python-garminconnect (113 API methods).
Platforms: macOS (amd64, arm64), Linux (amd64, arm64). macOS builds with CGO enabled for Keychain access.
MIT
- Garmin Connect
- python-garminconnect — API reference
- gogcli — architecture inspiration
Architecture inspired by gogcli by Peter Steinberger. API coverage modeled after python-garminconnect by Ron Klinkien.
Not affiliated with Garmin. Garmin and Garmin Connect are trademarks of Garmin Ltd. or its subsidiaries.