Skip to content

FIT File Faker

Fit File Faker Logo

PyPI License Tests Codecov Ko-fi

This application allows you to easily modify FIT files to make them appear to come from a Garmin device (70+ modern devices supported, including Edge 1050, Fenix 8, Forerunner 965, and more) and upload them to Garmin Connect using the garth library. The FIT editing is done using Stages Cycling's fit_tool library.

Support This Project

If FIT File Faker saves you time or enhances your training workflow, consider buying me a coffee ☕. Your support helps maintain and improve this project!

Additionally, it can be run in a "monitor" mode that will watch a folder for new FIT files and will automatically edit/upload them as they are produced. One potential application of this mode is to have the tool auto-start on the computer that you use for indoor training, so rides are automatically uploaded to Garmin Connect when you finish.

Feature walkthrough

Overview of FIT File Faker features and commands

Overview

The primary motivation for this tool came from the fact that that TrainingPeaks Virtual (previously indieVelo) does/did not support automatic uploading to Garmin Connect. The files can be manually uploaded after the fact, but since they are not "from Garmin", they will not be used to calculate Garmin's Training Effect, which is used for suggested workouts and other features, especially if you have a watch or cycling computer that uses these features.

By changing the FIT file to appear to come from a Garmin device, those features are enabled.

Use Cases

Other users have reported using this tool to edit FIT files produced by:

Contributors

  • jat255: Primary author
  • benjmarshall: bug fixes, monitor mode, and other improvements
  • Kellett: support for Zwift FIT files
  • lrybak: support for Hammerhead Karoo files
  • dermarzel: support for MyWhoosh files

Installation

Requirements

Python 3.12 or higher is required. If your system Python is older, use pyenv or uv to manage locally installed versions.

This tool works cross-platform on Windows, macOS, and Linux (primarily developed on Linux).

If you have uv installed:

uv tool install fit-file-faker

This installs the tool and makes fit-file-faker available on your PATH.

If you have pipx installed:

pipx install fit-file-faker

This installs the tool and makes fit-file-faker available on your PATH.

Install manually using pip in a virtual environment:

python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install fit-file-faker

The pip package installs a script named fit-file-faker that should be available on your path when the virtual environment is activated.

For development, clone the repo and use uv:

git clone https://github.com/jat255/Fit-File-Faker.git
cd Fit-File-Faker
uv sync  # Installs all dependencies

Pre-commit hooks:

The project uses pre-commit to run code quality checks. After cloning and running uv sync:

uv run pre-commit install

This automatically runs ruff check and ruff format on staged files before each commit.

Run hooks manually on all files:

uv run pre-commit run --all-files

Configuration

As of version 2.0.0, FIT File Faker now supports multi-profile configuration, allowing you to manage multiple Garmin accounts and trainer apps. See the Multi-Profile Guide for comprehensive documentation.

Multi-Profile Format

{
  "profiles": [
    {
      "name": "tpv",
      "app_type": "tp_virtual",
      "garmin_username": "user@work.com",
      "garmin_password": "secret123",
      "fitfiles_path": "/Users/josh/TPVirtual/abc123/FITFiles",
      "manufacturer": 1,
      "device": 3122,
      "serial_number": 1234567890,
      "software_version": 975
    },
    {
      "name": "zwift",
      "app_type": "zwift",
      "garmin_username": "personal@gmail.com",
      "garmin_password": "secret456",
      "fitfiles_path": "/Users/josh/Documents/Zwift/Activities",
      "manufacturer": 1,
      "device": 4061,
      "serial_number": 2362467083,
      "software_version": 2922
    }
  ],
  "default_profile": "tpv"
}

Profile Management

Use the interactive profile manager to create and manage profiles:

fit-file-faker --config-menu

Creating a new profile with the interactive menu

This supports:

  • Multiple Garmin accounts with isolated credentials
  • Multiple trainer apps (TPV, Zwift, MyWhoosh)
  • Auto-detection of FIT file directories
  • Customizable device simulation (Edge 830, Edge 1030, Tacx, etc.)
  • Profile-specific monitoring and uploads

Single Profile (Legacy Format)

For backward compatibility, the tool still supports the legacy single-profile format:

{
  "garmin_username": "username",
  "garmin_password": "password",
  "fitfiles_path": "C:\\Users\\username\\Documents\\TPVirtual\\0123456789ABCDEF\\FITFiles"
}

Automatic Migration

When you first run v2.0.0+, legacy configs are automatically migrated to the multi-profile format with a "default" profile.

Device Simulation

By default, FIT File Faker modifies files to appear as if they came from a Garmin Edge 830. However, each profile can be configured to simulate a different Garmin device.

Supported Target Devices

The tool supports simulating activities from 70+ modern Garmin GPS devices, including bike computers like the Edge 840, 1050, etc., multisport watches like the ForeRunner and Fenix series, and others.

Two-Level Device Selection

During profile creation or editing, the tool uses a curated two-level menu system:

Level 1: Shows 11 common devices grouped by category (bike computers, watches)

Level 2: Access 70+ devices via "View all devices" option

This makes the most common devices easily accessible while maintaining access to the full device catalog if you want to simulate a particular device.

Customizing Device Simulation

When creating or editing a profile via --config-menu, you'll be prompted:

? Customize device simulation? (default: Garmin Edge 830) (y/N)

If you select Yes, you can:

  1. Choose from common devices - Curated list of 11 popular devices
  2. View all devices - Access full catalog of 70+ devices organized by category
  3. Enter a custom numeric device ID - Allows you to specify a custom "device id" in the resulting FIT file; this can allow you to match your FIT files to a real Garmin device that you may already have on your account
  4. Enter a custom serial number/Unit ID - Allows you to specify the unique device that the FIT file will appear to have been written by. This is important for enabling certain features on Garmin Connect (see next section).

Custom Device IDs

If you enter a numeric device ID that's not in the registry, the tool will show a warning but still create/update the profile. This allows using newer Garmin devices or less common models.

⚠️ Important: Device Serial Numbers/Unit IDs

For Garmin Connect to correctly recognize an activity as coming from a specific device (which affects Training Status, challenges, badges, and other features), both the device ID and serial number (Unit ID) must match a valid Garmin device. This is a bit confusing on Garmin's implementation, since they call the value "serial number" in the FIT file, but it actually needs to be your device's Unit ID, not the serial number. To find the Unit ID, you can look either on your device (may vary depending on your device) or in the Garmin Connect app:

Garmin Connect app

Finding Unit ID on Garmin Connect

Finding your device's Unit ID in the Garmin Connect Android app

Go to "Devices → [Your Device] → System → About" to see the Unit ID

On an Edge device

Finding Unit ID on Garmin Device

Finding your device's Unit ID on an Edge 1040 device

Go to "Menu → System → About → Copyright Info" to see the Unit ID

Why This Matters

Garmin Connect uses server-side validation to ensure that (so far as we know):

  • The device product ID (e.g., Edge 1050, Fenix 8) is legitimate
  • The Unit ID is valid for that specific device type
  • The combination of device ID + Unit ID represents a real device

If the Unit ID doesn't match the device type, Garmin Connect may:

  • Not apply Training Effect calculations correctly
  • Not count the activity toward challenges or badges
  • Not update Training Status or training load metrics
  • Display the activity with incorrect device information

Recommendations

Option 1: Use Your Real Garmin Device Unit ID (Recommended)

If you own a Garmin device and want your activities to count properly for all Garmin Connect features:

  1. Find your device's Unit ID:
    • On the device: Settings → About → Copyright Info → Unit ID
    • On Garmin Connect: Device settings page
    • On the device packaging or receipt
  2. During profile setup, choose to customize the serial number
  3. Enter your actual device's Unit ID as the serial number
  4. Select the matching device model (e.g., if you have an Edge 830, select Edge 830)

Option 2: Accept Limited Functionality

If you don't own a Garmin device or don't need full Garmin Connect integration:

  • The tool will generate a random serial number automatically
  • Activities will upload successfully to Garmin Connect
  • Basic activity data (distance, time, power, heart rate) will display correctly
  • However, advanced features may not work as expected

What We Don't Know

The mapping of Unit ID ranges to specific device models is proprietary Garmin information and not publicly documented. This means:

  • We cannot automatically generate valid Unit IDs/serial numbers for specific devices
  • Random Unit IDs/serial numbers may or may not be accepted by Garmin Connect
  • The only guaranteed way to ensure full functionality is to use a real device's Unit ID

Usage

Command-line Options

To see all available options:

fit-file-faker -h
usage: fit-file-faker [-h] [--profile PROFILE] [--list-profiles] [--config-menu] [--show-dirs] [-u] [-ua] [-p] [-m] [-d] [-v] [input_path]

Tool to add Garmin device information to FIT files and upload them to Garmin Connect. Currently, only FIT files produced by TrainingPeaks Virtual (https://www.trainingpeaks.com/virtual/) and Zwift
(https://www.zwift.com/) are supported, but it's possible others may work.

positional arguments:
  input_path           the FIT file or directory to process. This argument can be omitted if the 'fitfiles_path' config value is set (that directory will be used instead). By default, files will just be
                       edited. Specify the "-u" flag to also upload them to Garmin Connect.

options:
  -h, --help           show this help message and exit
  --profile PROFILE    specify which profile to use (if not specified, uses default profile)
  --list-profiles      list all available profiles and exit
  --config-menu        launch the interactive profile management menu
  --show-dirs          show the directories used by Fit File Faker for configuration and cache
  -u, --upload         upload FIT file (after editing) to Garmin Connect
  -ua, --upload-all    upload all FIT files in directory (if they are not in "already processed" list)
  -p, --preinitialize  preinitialize the list of processed FIT files (mark all existing files in directory as already uploaded)
  -m, --monitor        monitor a directory and upload all newly created FIT files as they are found
  -d, --dryrun         perform a dry run, meaning any files processed will not be saved nor uploaded
  -v, --verbose        increase verbosity of log output

Basic Usage

The default behavior loads a given FIT file and outputs a file named path_to_file_modified.fit that has been edited and can be manually imported to Garmin Connect:

fit-file-faker path_to_file.fit

If a directory is supplied rather than a single file, all FIT files in that directory will be processed in the same way.

Upload to Garmin Connect

Multi-Profile Usage

FIT File Faker v2.0.0+ supports multiple profiles for different Garmin accounts and trainer apps.

Profile Selection

# Use a specific profile
fit-file-faker --profile zwift -ua
fit-file-faker -p tpv -u ride.fit

# List all profiles
fit-file-faker --list-profiles

# Launch interactive profile manager
fit-file-faker --config-menu

# Show directories used by FIT File Faker
fit-file-faker --show-dirs

Editing an existing profile configuration

Profile Selection Priority

  1. Explicit --profile argument
  2. Default profile (marked with ⭐)
  3. Interactive prompt (if multiple profiles exist)
  4. Error if no profiles configured

Credential Isolation

Each profile has isolated Garmin credentials stored in profile-specific directories: - .garth_tpv/ for TPV profile - .garth_zwift/ for Zwift profile - etc.

Verbose Output

The -v flag can be used (with any of the other options) to provide more debugging output:

fit-file-faker -u path_to_file.fit -v

Example output:

[12:38:33] INFO     Activity timestamp is "2024-05-21T17:15:48"                              app.py:84
           DEBUG    Record: 1 - manufacturer: 255 ("DEVELOPMENT") - product: 0 - garmin      app.py:55
                    product: None ("BLANK")
           DEBUG        Modifying values                                                     app.py:87
           DEBUG        New Record: 1 - manufacturer: 1 ("GARMIN") - product: 3122 - garmin  app.py:55
                    product: 3122 ("GarminProduct.EDGE_830")
           DEBUG    Record: 14 - manufacturer: 32 ("WAHOO_FITNESS") - product: 40 - garmin   app.py:55
                    product: None ("BLANK")
           DEBUG        Modifying values                                                     app.py:97
           DEBUG        New Record: 14 - manufacturer: 1 ("GARMIN") - product: 3122 - garmin app.py:55
                    product: 3122 ("GarminProduct.EDGE_830")
[12:38:34] DEBUG    Using stored Garmin credentials from ".garth" directory                 app.py:118
[12:38:35] INFO     ✅ Successfully uploaded "path_to_file.fit"                             app.py:137

"Upload All" and "Monitor" Modes

Upload All

The --upload-all option will search for all FIT files either in the directory given on the command line, or in the one specified in the fitfiles_path config option. The script will:

  1. Compare the files found to a list of files already seen (stored in that directory's .uploaded_files.json file)
  2. Edit them
  3. Upload each to Garmin Connect

The edited files will be written into a temporary file and discarded when the script finishes running, and the filenames will be stored into a JSON file so they are skipped the next time the script is run.

Monitor Mode

The --monitor option automates the upload all function by watching the filesystem in the specified directory for any new FIT files. It will continue running until the user interrupts the process by pressing ctrl-c.

Example output when a new file named new_fit_file.fit is detected:

$ fit-file-faker --monitor /home/user/Documents/TPVirtual/0123456789ABCEDF/FITFiles

[14:03:32] INFO     Using path "/home/user/Documents/TPVirtual/                    app.py:561
                    0123456789ABCEDF/FITFiles" from command line input
           INFO     Monitoring directory: "/home/user/Documents/TPVirtual/         app.py:367
                    0123456789ABCEDF/FITFiles"
[14:03:44] INFO     New file detected - "/home/user/Documents/TPVirtual/           app.py:94
                    0123456789ABCEDF/FITFiles/new_fit_file.fit"; sleeping for
                    5 seconds to ensure TPV finishes writing file
[14:03:50] INFO     Found 1 files to edit/upload                                   app.py:333
           INFO     Processing "new_fit_file.fit"                                  app.py:340
           INFO     Processing "/home/user/Documents/TPVirtual                     app.py:202
                    sync/0123456789ABCEDF/FITFiles/new_fit_file.fit"
[14:03:58] INFO     Activity timestamp is "2025-01-03T17:01:45"                    app.py:223
[14:03:59] INFO     Saving modified data to "/tmp/tmpsn4gvpkh"                     app.py:250
[14:04:00] INFO     Uploading modified file to Garmin Connect                      app.py:346
[14:04:01] INFO     Uploading "/tmp/tmpsn4gvpkh" using garth                       app.py:295
^C[14:04:46] INFO     Received keyboard interrupt, shutting down monitor           app.py:372

Pre-initializing Uploaded Files

If your TrainingPeaks Virtual user data folder already contains FIT files which you have previously uploaded to Garmin Connect using a different method, you can pre-initialize the list of uploaded files to avoid any possibility of uploading duplicates.

Use the --preinitialize option to process a directory (defaults to the configured TrainingPeaks Virtual user data directory) and add all files to the list of previously uploaded files:

fit-file-faker --preinitialize

After this, any use of the --upload-all or --monitor options will ignore these pre-existing files.

Already Uploaded Files

Duplicate Detection

If a file with the same timestamp already exists on the Garmin Connect account, Garmin will reject the upload. This script will detect that and output:

[13:32:48] INFO     Activity timestamp is "2024-05-10T17:17:34"                              app.py:85
           INFO     Saving modified data to "path_to_file_modified.fit"                      app.py:107
[13:32:49] WARNING  ❌ Received HTTP conflict (activity already exists) for                  app.py:143
                    "path_to_file.fit"

Troubleshooting

If you run into problems, please create an issue on the GitHub repo.

Viewing Configuration Directories

Use fit-file-faker --show-dirs to see:

  • Configuration file location
  • Cache directory location
  • Garmin credential directories for each profile
  • Executable paths

This can be helpful when troubleshooting configuration or credential issues.

Note

As this is a side-project provided for free (as in speech and beer), support times may vary 😅.

Next Steps

Disclaimer

The use of any registered or unregistered trademarks owned by third-parties are used only for informational purposes and no endorsement of this software by the owners of such trademarks are implied, explicitly or otherwise. The terms/trademarks Garmin, indieVelo, TrainingPeaks, TrainingPeaks Virtual, Garmin Connect, Stages Cycling, MyWhoosh, Hammerhead Karoo, COROS Dura, Zwift, and any others are used under fair use doctrine solely to facilitate understanding.

Likewise, the software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.

The application logo was generated primarily using AI tools. If you would like to contribute a better, custom-designed logo, we would welcome pull requests! Please feel free to open a GitHub issue or submit a PR with logo design suggestions.