Live Race Stats is a free app (a Connect IQ data field) for Garmin Edge bike computers and watches (Fenix, Forerunner, Venu, Instinct and more). During a race timed by our system it shows your place, gaps to rivals and laps right on the device screen -- by race id and your bib number. In the store the app is called Live Race Stats; in the device's field list it is RaceStats. Developer: DenisChernykh.

What you need

  • A compatible Garmin device (an Edge, or a watch with Connect IQ).
  • A phone with internet, connected to the device over Bluetooth -- it must be with you during the race. The data field cannot reach the network directly; the request goes through the phone.
  • The race must be timed by our system, and the protocol generator must be sending live stats to the site (the organizer does this).

Install (from the phone)

  1. Install the Connect IQ Store app on your phone (or open the Connect IQ section in the Garmin Connect app). Sign in with the same Garmin account your device is paired to.
  2. Find Live Race Stats (search by name, or by the developer DenisChernykh).
  3. Tap Install and pick your device. The app is pushed to the device over Bluetooth (the device must be connected to the phone).

Add the field to a screen (on the device)

On the device open: activity profile (e.g. "Bike") → Data Screens → pick or add a screen → Layout → in the cell you want choose Connect IQ → RaceStats.

Tip: for a nice table with all metrics use the "1 Field" layout (full screen) -- the app then draws a two-column grid, like a native Garmin data screen.

Configure (in the Connect IQ app on the phone)

Garmin data fields are configured from the phone only: Connect IQ → your device → Connect IQ Apps → Live Race Stats → Settings.

  • Site URL: defaults to https://universalbicycle.team. Leave it if your race is there; change it only if the organizer runs the system on their own server.
  • Competition ID: the numeric id from the race page URL. Example: a race at .../calendar/259/ has ID = 259.
  • Bib number: your start number.
  • Rows: how many metrics to show at once (1 to 10).
  • Row 1 … Row 10: which metric to show in each row.

Try it without a race (demo): leave Site URL at the default, set Competition ID 259, Bib number 1, Rows 10 -- the field shows a demo "test race". The numbers are static; it just confirms everything works.

Which metrics you can show

There are 15 metrics to choose from. Labels are short so they fit on screen:

  • Place / total: overall -- "Place abs"; in the group -- "Place gr".
  • Gaps (overall): to the rider ahead "Gap ahd abs", behind "Gap bhd abs", to the leader "Gap ldr abs".
  • Gap dynamics (overall): ahead "Dynam ah abs", behind "Dynam bh abs", to the leader "Dynam ld abs".
  • Gaps (group): "Gap ahd gr", "Gap bhd gr", to the group leader "Gap ldr gr".
  • Gap dynamics (group): "Dynam ah gr", "Dynam bh gr", "Dynam ld gr".
  • Laps (done / total): "Laps".

Abbreviations: ahd -- the rider one place above you; bhd -- one place below; ldr -- the classification leader; abs -- the overall classification; gr -- your group (category).

How to read the values

  • Place: "3/4" -- you are third of four.
  • Gap: a signed time, "+M:SS" or "+H:MM:SS". "+" means you are losing to that rider (they are faster on time), "−" means you are ahead of them. Examples: "Gap ahd abs +0:22" -- you trail the rider ahead by 22 s; "Gap bhd abs −0:11" -- the rider behind trails you by 11 s; "Gap ldr abs +0:36" -- you trail the leader by 36 s.
  • Dynamics (Dynam): how this gap changed over your last lap. "+" -- the gap grew, "−" -- it shrank. It tells you whether you are catching up or dropping back.
  • Laps: "3/10" -- 3 of 10 laps done.
  • DSQ: if a competitor is disqualified, the place shows "DSQ".
  • "--" (two dashes): no data yet -- not an error. Happens when the race id or bib is unset, no phone/internet is nearby, the race hasn't started, or the first data hasn't arrived.

Important about the delay

  • Data refreshes about every 5 minutes -- a Garmin limit on background requests for data fields that cannot be bypassed.
  • Data changes only when a competitor crosses a lap finish and the info reaches the site. Intermediate points are not used, for reliability.
  • So the first numbers appear within ~5 minutes after the start, not instantly, and then update at the same interval.
  • The phone must be connected to the device and have internet. If the link drops, the field holds the last value.

How it works

The data chain: (1) timekeepers record lap-finish crossings; (2) the protocol generator computes each bib's place, gaps, laps and dynamics from those and posts a snapshot to the site on every regeneration; (3) the site stores the snapshot per bib and serves it publicly; (4) the Garmin field requests its bib's data about every 5 minutes and draws it.

Technical details:

  • A Garmin data field cannot reach the internet directly. A background process makes the request, only through the phone over Bluetooth; Garmin's minimum interval for such requests is 5 minutes.
  • The public request (no auth, the stats are open): GET https://universalbicycle.team/api/v1/live-stats/{competition_id}/{bib}. The response is the place, gaps, etc. for that bib (all values are strings).
  • If there is no snapshot yet for the race/bib pair, the site returns 404 and the field shows "--" while it keeps polling.
  • The field caches the last snapshot and draws from the cache. When you stop the activity, the background polling stops -- to spare the battery and network after the race.
  • Gaps are computed from the time at the last lap both riders finished, using each rider's own elapsed time (correct for individual and group starts), not the watch clock.

Supported devices

The app supports 142 Garmin devices: Edge bike computers and many watches (Fenix, Forerunner, Venu, Instinct and more). It is localized into 10 languages. Free, no ads; it collects no personal data -- it only sends the race id and your bib to fetch the open stats.

FAQ

  • The field is empty / shows "--". Check in order: are Competition ID and Bib set; is the phone connected to the device; does the phone have internet; has ~5 minutes passed since the start; does your race have live stats (ask the organizer).
  • Data isn't real-time. By design: it updates about every 5 minutes and only on lap finishes.
  • Can I configure it on the device? No, Garmin data fields are configured from the phone only.
  • How many metrics can I show? Up to 10 in one field. The field takes one layout cell; how many rows actually fit depends on the cell size.
  • Does it work on watches? Yes -- the field is available on watches (Fenix, Forerunner, etc.), not only on Edge.

For organizers

For the stats to work at your race: the competition on the site must be published (approved), not hidden and not deleted; the protocol generator must have stats sending enabled (overall and/or per group) -- the "abs" metrics appear with absolute stats on, "gr" with group stats on. If you run the system yourself, point the app at your server via the Site URL setting. Site sources: github.com/dchernykh1984/cycling-site.

For owners of other devices

If your device is not a Garmin but can run apps, you can write your own client: the data is served by our site's open API, no authentication required.

Request: GET https://universalbicycle.team/api/v1/live-stats/{competition_id}/{bib}, where competition_id is the numeric race id from the competition page URL and bib is the start number (a string).

Response is JSON like {"competition_id": 259, "bib": "1", "updated_at": "…", "stats": {…}}. The stats field is a key -> string dictionary; a key may be absent (meaning there is no data for that metric yet). If there is no snapshot for the race/bib pair yet, the site returns 404 -- just retry later. The site updates data as laps are completed, so polling more often than every ~30-60 seconds is pointless.

Keys in stats (all values are strings):

  • place_abs / place_group -- place overall / in the group (e.g. "3"), or "DSQ" for a disqualified rider.
  • qty_abs / qty_group -- number of competitors (overall / group).
  • gap_prev_abs / gap_prev_group -- gap to the rider ahead (with "+": you are behind).
  • gap_next_abs / gap_next_group -- gap to the rider behind (with "-": they trail you).
  • gap_leader_abs / gap_leader_group -- gap to the leader.
  • gap_prev_*_delta, gap_next_*_delta, gap_leader_*_delta -- how that gap changed over the last lap ("+" grew, "-" shrank).
  • laps -- laps "done/total" (e.g. "3/10").

Formats: a gap is "+M:SS" or "+H:MM:SS", with as many decimal seconds as the generator's "Digits after decimal" setting (usually 1, e.g. "+0:36.1"); place and counts are an integer as a string. Every value is computed from lap finishes only (intermediate points are not used). Details are in the site sources: github.com/dchernykh1984/cycling-site.

Built such an app? Let us know! Leave a comment under this article, send a suggestion via the "Submit article" form (to the knowledge base or as news), or write to us through the contact-owners form in your personal account on the site. We would be happy to tell other participants about it.