#!/usr/bin/env python3 """ Download GPX files for your Garmin Connect activities. Setup: pip install garminconnect Usage: python garmin_gpx_export.py You'll be prompted for your Garmin Connect email and password (the same ones you use to log into connect.garmin.com). Credentials are only used locally to authenticate with Garmin's servers and are never stored or sent anywhere else. """ import getpass import os from datetime import datetime from garminconnect import Garmin, GarminConnectAuthenticationError def get_mfa_code(): """Called automatically by garminconnect if Garmin requests an MFA code.""" return input("Enter the MFA code sent to you by Garmin: ").strip() def main(): # --- Login --- email = input("Garmin Connect email: ").strip() password = getpass.getpass("Garmin Connect password: ") try: client = Garmin(email=email, password=password, prompt_mfa=get_mfa_code) client.login() except GarminConnectAuthenticationError: print("Login failed. Check your email/password/MFA code.") return print(f"Logged in as {client.get_full_name()}") # --- Config --- output_dir = "garmin_gpx_exports" os.makedirs(output_dir, exist_ok=True) # How many recent activities to check (increase if you want more history) limit = 50 # Only export activities matching this type, or set to None for all types. # Common values: "cycling", "running", "walking", "hiking", "swimming" activity_type_filter = "cycling" # --- Fetch activity list --- activities = client.get_activities(0, limit) print(f"Found {len(activities)} recent activities (checking up to {limit}).") exported = 0 for act in activities: act_type = act.get("activityType", {}).get("typeKey", "") if activity_type_filter and activity_type_filter not in act_type: continue activity_id = act["activityId"] start_time = act.get("startTimeLocal", "unknown_time") name = act.get("activityName", "activity") # Sanitize filename safe_time = start_time.replace(":", "-").replace(" ", "_") safe_name = "".join(c for c in name if c.isalnum() or c in (" ", "_", "-")).strip() filename = f"{safe_time}_{safe_name}_{activity_id}.gpx" filepath = os.path.join(output_dir, filename) if os.path.exists(filepath): print(f" Skipping (already downloaded): {filename}") continue try: gpx_data = client.download_activity( activity_id, dl_fmt=client.ActivityDownloadFormat.GPX ) with open(filepath, "wb") as f: f.write(gpx_data) print(f" Saved: {filename}") exported += 1 except Exception as e: print(f" Failed to export activity {activity_id}: {e}") print(f"\nDone. Exported {exported} new GPX file(s) to ./{output_dir}/") if __name__ == "__main__": main()