Skip to content
NewA data check for swims the watch got wrong
Nov 4, 2026·4 MIN READ
A data check for swims the watch got wrong

A data check for swims the watch got wrong

I compared our swim pages with Garmin Connect field by field, then built a small check that flags impossible swims. One lap said 2.5 km in 61 seconds. The hard part was not catching it, it was not flagging good swims.

Today I opened two of my swims in Garmin Connect next to the same swims on the Vimo Swim site and compared every field. The good news first: all 35 laps of a pool swim matched on distance, time, SWOLF, heart rate and strokes. The bad news came from the records page. My "fastest pace" was 0:06 per 100 m, from a swim in November 2022.

That swim says 2.63 km in a session of under nine minutes. One lap reads 2.5 km in 61 seconds, with 100 lengths in it. Nobody swims that. The watch miscounted, and Garmin kept the result as it was.

What else the comparison found

FieldGarmin ConnectOur pageWhy
Open water pace2:13 /100 m2:28 /100 mwe divided by elapsed time, Garmin by the timer
Pool lap pace2:022:01rounding, in 3 of 35 laps
Fastest pace recordbest 400 m 3:070:06 /100 mone broken swim wins every record
Activity titlea real place name"Pool Swim"the summary we stored had the generic name

The pace fix was one line: use the swimming time when the pool lengths give it, else the watch timer, else elapsed time. The records needed more than a fix. They needed a way to know which swims to ignore.

The check

I did not want to fix the data. A swimmer should see what their watch recorded. So the check only writes notes next to the swim, and the records skip any swim that has notes.

flowchart LR
    A[FIT file] --> B["Read laps<br/>and lengths"]
    B --> C{"Faster than<br/>2 m/s?"}
    C -->|yes| D[Note on the swim]
    C -->|no| E[Best times]
    D --> F["Banner, filter,<br/>records skip it"]

The rules are plain numbers. A pool length faster than 2 m/s (12.5 s per 25 m, elite sprint speed with a push-off), a length longer than 15 minutes, a lap faster than 2 m/s, or a swimming time longer than the whole session.

Tuning the limit

The first version used 2.5 m/s, just above the world record. It still let a 100 m best of 0:43 through, close to world class, so I lowered it to 2 m/s. The 100 m best moved to 1:02, which I believe. Then my longest swim, a real 10 km from 2023, disappeared from the records. One length of 12.2 seconds had flagged the whole swim.

RuleSwims flagged (of 1,036)Best 100 m
No check00:00.9
Over 2.5 m/s430:43
Over 2 m/s, any length1111:02
Over 2 m/s, 3+ lengths671:02

One quick length is a missed turn. Three or more means the watch was lost. A single bad length still never makes a best time, because it breaks the run of lengths the best times are built from.

The check runs when the FIT file is read, so old swims need a second read. I added a --reread flag to the backfill command. It read all 1,036 stored files again, with no errors.

The site now shows a yellow box on a flagged swim with the reasons, a "Check data" badge in the list, and a filter that lists only the flagged swims, so I can go through them one by one.

It took an afternoon, most of it spent tuning, not coding. Next time I would start from the false positives: pick a few swims I know are real, make sure they pass, and only then lower the limit.

Share
Mariusz Smenżyk
Written by

Mariusz Smenżyk

Builder for sport. Make Things Live.

Related notes