Skip to content

bpauli/gccli

gccli — Garmin Connect in your terminal.

ci Go Report Card Docs Buy Me A Coffee

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.

Features

  • 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 --account flag
  • 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

Installation

Homebrew (macOS / Linux)

brew install bpauli/tap/gccli

Build from Source

Requires Go 1.24+.

git clone https://github.com/bpauli/gccli.git
cd gccli
make build

The binary is output to ./bin/gccli.

Run:

./bin/gccli --help

Help:

  • gccli --help shows top-level command groups.
  • Drill down with gccli <group> --help (and deeper subcommands).
  • Make shortcut: make run -- --help (or make run -- activities --help).

Quick Start

1. Log In (Browser SSO)

gccli auth login you@example.com

This opens your browser for Garmin SSO authentication. The OAuth tokens are stored securely in your system keyring.

2. Log In (Headless)

For servers or environments without a browser:

gccli auth login you@example.com --headless

You'll be prompted for your password. If your account has two-factor authentication:

gccli auth login you@example.com --headless --mfa-code 123456

Login automatically saves your email as the default account, so you don't need to pass --account or set GCCLI_ACCOUNT on every command.

3. Test Authentication

gccli auth status
gccli activities list --limit 5

Authentication & Secrets

Accounts and Tokens

gccli 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 status

Print the raw OAuth2 access token (useful for scripting):

gccli auth token

Remove stored credentials:

gccli auth remove

Keyring Backend

Backends:

  • 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=file

Or in the config file (config.json):

{
  "keyring_backend": "file"
}

On Linux, if D-Bus is unavailable, gccli automatically falls back to the file backend.

Garmin Domain (China)

For Garmin China accounts (garmin.cn):

export GCCLI_DOMAIN=garmin.cn

Or in config.json:

{
  "domain": "garmin.cn"
}

Configuration

Account Selection

The account is resolved in this order:

  1. --account flag
  2. GCCLI_ACCOUNT environment variable
  3. Default account saved by gccli auth login (stored in config.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

Output

  • 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 --json and --plain.

Config File

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"
}

Environment Variables

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

Security

Credential Storage

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.

Commands

Authentication

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

Activities

# 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

Health Data

# 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]

Body Composition

# 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-15

Workouts

gccli 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)

Exercise Catalog

# 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 --json

Courses

gccli 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 confirmation

Devices

gccli 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-30

Gear

gccli 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>

Goals, Badges & Challenges

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 records

Profile

gccli profile
gccli profile settings

Hydration

gccli hydration [date]                 # View hydration data
gccli hydration add 500                # Log 500ml of water
gccli hydration add 500 --date 2024-06-15

Nutrition

gccli nutrition [date]                 # View daily food log
gccli nutrition meals [date]           # View meal summaries
gccli nutrition settings [date]        # View nutrition settings

Training Plans

gccli training plans --locale en
gccli training plan <id>

Events

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 --training

Event 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), --primary or --training (mutually exclusive)

Wellness

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-summary

Data Reload

gccli reload                           # Reload today's data
gccli reload 2024-06-15                # Reload specific date

Shell Completion

Generate completion scripts for your shell:

gccli completion bash
gccli completion zsh
gccli completion fish
gccli completion powershell

To 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 | source

PowerShell ($PROFILE):

gccli completion powershell | Invoke-Expression

Completions cover all commands, subcommands, flags, and enum flag values (e.g. --color auto|always|never).

Output Formats

Table (default)

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-13

JSON

Machine-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")'

Plain (TSV)

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-13

Examples

Export all runs from the last month

gccli --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"
  done

Daily health check script

gccli --json health summary | jq '{
  steps: .totalSteps,
  calories: .totalKilocalories,
  distance_km: (.totalDistanceMeters / 1000),
  active_minutes: .moderateIntensityMinutes + .vigorousIntensityMinutes
}'

Track weight over time

gccli --json body weigh-ins --start 2024-01-01 --end 2024-06-30 | \
  jq -r '.dailyWeightSummaries[] | [.summaryDate, .weight.value] | @tsv'

Download the latest activity

latest=$(gccli --json activities list --limit 1 | jq -r '.[0].activityId')
gccli activity download "$latest" --format fit

Global Flags

All 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

Date Format Reference

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

Development

After cloning, install tools:

make tools

Build, 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/...

E2E Tests (Live Garmin API)

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-e2e

Warning: E2E tests create and delete activities/workouts. Use a dedicated test account.

Architecture

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.

License

MIT

Links

Credits

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.

About

A command-line interface for Garmin Connect — activities, health, courses, workouts, devices, and more — with JSON output and secure credential storage.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors