Cookies for analytics and advertising
We use cookies for analytics and advertising, both sent to Google. Refusing changes nothing you can see.Read the privacy page
Converting GPX to TCX wraps a recorded track in the structure a training platform expects: an activity, a lap, and a declared distance and duration. A GPX stores none of those, so they are computed from the trackpoints, and this page names every value the conversion synthesises rather than reads.
Up to 100 files at once. Mixed formats are fine.
They convert one after another and download together as a ZIP.
GPX to TCX
Plenty of software records a ride perfectly well and exports only GPX: phone apps, older head units, open-source loggers, anything that treats a route as geography rather than as training. The platforms on the other side — Garmin Connect, TrainingPeaks, a coach's dashboard — are built around activities, and an activity has a start, a duration, a distance and a discipline before it has a shape.
This conversion bridges that. It takes the geometry the GPX holds and puts the structural declarations around it that a TCX reader requires, so the file imports as a session rather than being rejected or landing in a route library. What it cannot do is put information into the file that the GPX never contained, and the difference between those two things is most of what follows.
Training Center XML is strict where GPX is permissive. Every `<Lap>` must declare a `StartTime`, a `TotalTimeSeconds`, a `DistanceMeters`, an `<Intensity>` and a `<TriggerMethod>`, and every `<Activity>` must declare a `Sport` from a fixed list. A file missing any of them is not read leniently; Garmin Connect refuses it, which is the usual reason a hand-assembled TCX fails to import.
So all five are written. Intensity is set to `Active` and TriggerMethod to `Manual`, which are the neutral values and the honest ones for a file that was never lapped by a device. The activity Id is set to the start timestamp, as the schema intends. The remaining three — start, duration and distance — are derived from the trackpoints, and each has a way of going wrong that the next sections are about.
A GPX does not store distance anywhere. The number written into `DistanceMeters` is produced by walking the trackpoints in order and summing the great-circle distance between each consecutive pair, using a spherical Earth of radius 6,371,000 metres. Against a proper ellipsoidal calculation that is accurate to a few parts in a thousand, which is far below the noise in the input.
Two properties of that sum are worth knowing. It ignores elevation change, and that matters less than instinct suggests: a route climbing 1,000 metres over 40 kilometres is 40,012 metres along the slope rather than 40,000, a difference of three hundredths of a percent. What does matter is receiver jitter — every wobble between two samples is added rather than cancelled, so a densely recorded track measures slightly long, and a device's own figure, filtered or taken from a wheel sensor, is usually the smaller and better number.
TotalTimeSeconds is the difference between the first and last trackpoint times, in seconds, rounded to a whole number. For a recorded ride that is elapsed time rather than moving time: a forty-minute café stop in the middle is inside the total, because the file records when the receiver was somewhere and not whether it was moving.
The trap is a GPX with no timestamps at all, which is what a planned route exported from a route planner looks like. There is nothing to subtract, so the duration comes out as zero, and since a lap must still declare a start time the epoch is written instead — the activity appears dated 1 January 1970 with a duration of nothing. It is schema-valid and it is nonsense as a workout. If your GPX is a plan rather than a recording, convert it to a route format and load it as a course.
The Sport attribute is written as `Other` on every activity. TCX restricts the value to a short enumeration, a GPX has no field that says what the recording was, and guessing from average speed would be a fabrication that happens to be right most of the time — which is the worst kind, because it is wrong invisibly.
The practical effect is a few seconds of work after importing. Garmin Connect, Strava and TrainingPeaks all let you change an activity's type after the fact, and doing so recalculates whatever depends on it. It is worth doing rather than leaving: training-load models, pace zones and personal-best detection are all keyed off the discipline, and a session filed as `Other` is quietly excluded from most of them.
A TCX can hold heart rate, cadence, power and per-point distance, and a converted one holds none of them. Where a GPX carried heart rate in a `<extensions>` block — which many watches do, using Garmin's own TrackPointExtension namespace — those values are not read, so they do not reappear in the TCX even though the destination format has a place for them.
That is a genuine limitation of this conversion and worth stating plainly, because the format change makes it look as though training data should have arrived. It did not. If sensor data exists in your GPX and you need it in the TCX, the conversion to reach for is not this one: export the session again from whatever recorded it, choosing TCX or FIT at the source, and the streams come out attached to the points the first time.
Each track becomes an activity containing exactly one lap, which spans the whole recording. GPX has no lap concept — a `<trkseg>` boundary marks a signal dropout, not a button press — so there is nothing in the source to map onto lap divisions and none are invented.
For a steady ride that is a faithful representation. For an interval session it flattens the thing you did: twelve repetitions come across as one continuous effort, and the lap splits, per-lap averages and rest intervals that a coach reads first are absent. Most platforms let you split an activity manually after upload, which reconstructs the boundaries but not the per-lap heart rate the original device would have summarised.
A workout has no notion of a waypoint. Where a GPX contains tracks, the waypoints are simply left out of the TCX, because there is no element that would hold them and a fabricated one would break the schema for every reader.
A GPX containing nothing but waypoints is handled differently rather than rejected: the points are treated as one track, in the order the file listed them, so the result is a valid activity describing "these positions, in this sequence". Whether that is meaningful depends entirely on the file. A series of survey marks converts into an activity that claims a distance nobody travelled, and for that source the CSV or GPX route is the honest one.
A GPX holding more than one `<trk>` produces more than one `<Activity>` in the TCX, each with its own lap, its own computed distance and its own start time taken from its first point. Routes stored as `<rte>` are treated as tracks too and get the same treatment, which is why a merged file of a week's riding converts into a week of separate sessions rather than one implausible one.
Not every importer handles a multi-activity TCX the same way. Some split it into separate entries automatically, some take the first and ignore the rest. If the upload comes back with one session when you expected five, splitting the GPX before converting is the reliable fix, and it also lets you name and label each one properly on the way in.
Reading the GPX and writing the TCX both happen in this browser tab, with no request carrying the file to a server — checkable in the network panel while a conversion runs. You will upload the result somewhere by design, which is the point of the conversion, but that is one destination you chose rather than two.
The distinction is worth drawing because training files are health and location data together. A converted TCX names where somebody was, minute by minute, for as long as the session lasted, and it is about to be handed to a platform with its own retention terms. Adding a free web converter in front of that is a second processor with no agreement behind it, which is precisely the step doing the conversion locally removes.
| GPX | TCX | |
|---|---|---|
| Full name | GPS Exchange Format | Training Center XML |
| File extension | .gpx | .tcx |
| Media type | application/gpx+xml | application/vnd.garmin.tcx+xml |
| First published | 2002 | 2007 |
| Published by | Topografix | Garmin |
| Specification | GPX 1.1 | Training Center XML |
| Licensing | Open standard | Published, not standardised |
| Standing today | Current | Current |
| Opens in a browser | No browser | No browser |
| Considered instead | KML | FIT |
Strava reads both GPX and TCX, so there is a way to check the result against the original without a second tool.
GPX is Topografix's format, published in 2002. The specification is GPX 1.1, and it is worth reading if the file has to outlive the tool that wrote it.
TCX comes from Garmin and dates from 2007, specified as Training Center XML. Garmin Connect, Strava and TrainingPeaks all read it.
No. This conversion runs entirely inside your browser, so the file never leaves your device. You can confirm it yourself: open the network tab of your browser's developer tools and convert something. You will see the page load, plus the analytics and advertising the site is paid for with — and nothing carrying your file.
No, and nothing can. Heart rate that a GPX stored in its `
It is computed by summing the great-circle distance between consecutive trackpoints, because a TCX lap is required to declare one and a GPX does not store it.
`Other`. The TCX schema restricts the Sport attribute to a short list and a GPX carries no equivalent, so the neutral value is written and you relabel the activity after importing it.
Because the GPX had no timestamps — a planned route rather than a recording. TCX requires a start time on every lap, so the epoch is written as a placeholder and the duration comes out as zero.
There were none to preserve. A GPX has no lap concept, so each track becomes one activity with a single lap covering the whole thing.
It is written to satisfy the schema — Sport, Intensity, TriggerMethod, TotalTimeSeconds and DistanceMeters are all present rather than omitted, which is the usual reason a hand-made TCX is rejected.