### Examples

AppBuilder can do a lot of different things, so here's a couple of example formulas to get you started.

Tap or click to copy a formula to the clipboard.

AppBuilder 5 avg functions consider zeros. To ignore zeros in AppBuilder 5, use avg(nonzero(x))

Any reference to

Tap or click to copy a formula to the clipboard.

### Notes

**[LargeMemory]**This appears next to any examples that only work on devices with large memory: All Edges (except 130 and 520), 645 Music, Fenix 5X and Fenix 5+ (all variants)**[CIQ2]**This appears next to any examples that only work on modern devices. Older CIQ1 devices are not supported: FR230/235, FR630, FR920XT, Vivoactive, Fenix 3 (hr), D2 Bravo**[CIQ1]**Appears next to examples that only apply to CIQ1, because there's an easier or better way to do it with CIQ2.**[AppBuilder5]**This appears next to any examples that only apply to AppBuilder 5, and not AppBuilder Classic**[AppBuilderClassic]**Appears next to examples that only apply to AppBuilder Classic**[avg]**For AppBuilder Classic**only**: avg, lapavg and timeavg functions ignore zeros. Use avg0, lapavg0 and timeavg0 to consider zeros.AppBuilder 5 avg functions consider zeros. To ignore zeros in AppBuilder 5, use avg(nonzero(x))

Any reference to

**Power**only works with multisport watches (e.g. 935, Fenix 5) or Edge cycling computers**Power**works with Stryd running pods**if you connect to the Stryd as a generic power meter, on a multisport watch**.**Power**does not work with Garmin Running Power (which requires its own app), or a Stryd not connected as a generic power meter.- 1 foot cadence
`cadence / 2`

- [AppBuilderClassic] speed (5 second average)

(including zeroes)`timeavg0(speed, 5)`

(not including zeroes)`timeavg(speed, 5)`

- [AppBuilder5] speed (5 second average)

(including zeroes)`timeavg(speed, 5)`

(not including zeroes)`timeavg(nonzero(speed), 5)`

- Pace (5 second avg) [avg]
`timeavg(speed, 5)`

(Set Display Format to "Pace") - Power (5 second avg) [avg]
`timeavg(power, 5)`

- Displays the last time the activity was unpaused
`max(if (prev(timer) eq null, timer, null))`

- Display 20-minute countdown that resets on pause
`max(if (prev(timer) eq null, timer, null)) + 1200 - timer`

- Display text [AppBuilder5] [CIQ2]
`'Run Happy'`

- Display a suffix [AppBuilder5] [CIQ2]
`hr + ' bpm'`

- Display two values [AppBuilder5] [CIQ2]

`hr + ':' + max(hr)`

- Display two values, record one [AppBuilder5] [CIQ2]

`record(hr) + ':' + max(hr)`

- Record different data to lap, summary and activity [AppBuilder5] [CIQ2]

`recordlap( lapavg(hr) ) ; recordsummary( max(hr) ) ; record(hr)`

(Displays current hr) - Display three values (current, average, max hr) [AppBuilder5] [CIQ2]

`hr + '/' + avg(hr) + '/' + max(hr)`

- Display three values (current, average, max hr); Record current, lap and average to fit [AppBuilder5] [CIQ2]

`recordlap(lapavg(hr)) ; record(hr) + '/' + recordsummary(avg(hr)) + '/' + max(hr)`

- Display Pace and hr and the same field [AppBuilder5] [CIQ2]

`formatpace(speed) + ':' + formatnumber(hr)`

- Freely format numbers (one decimal place) [AppBuilder5] [CIQ2]

`format(avg(hr), '%.1f')`

- Record number, and format it freely [AppBuilder5] [CIQ2]

`format(record(avg(hr)), '%.1f')`

- Yacht race timer [CIQ2]

(five minute pre-race: display pre-race countdown, alert every minute, and alert with 10, 5 and 1 second left)

(during race: display speed in knots)`alert(timer gte 60); alert(timer gte 120); alert(timer gte 180); alert(timer gte 240); alert(timer gte 290); alert(timer gte 295); alert(timer gte 299); if (timer lte 300, 300 - timer, timeavg(speed_raw, 10) * 1.94384)`

- Elevation/altitude change
`totalascent - totaldescent`

- Distance to next milestone (every 5 km/mi)
`5 - distance mod 5`

- Distance (km or miles, depending on device settings)
`distance`

- Distance (metres)
`distance_raw`

- Distance (km)
`distance_raw / 1000`

- Distance (miles)
`distance_raw / 1000 / kmPerMile`

- Speed (in km/h or miles/h, depending on device settings)
`speed`

- Speed (metres/s)
`speed_raw`

- Speed (km/h)
`speed_raw * 3.6`

(Use Pace display format for mm:ss per km) - Speed (miles/h)
`speed_raw * 3.6 / kmPerMile`

(Use Pace display format for mm:ss per mile) - Max altitude/elevation
`max(altitude)`

- Minimum hr
`min(hr)`

- Lap max hr
`lapmax(hr)`

- # of phone notifications
`notificationCount`

- Max pace
`maxspeed`

Display format: Pace (converts speed to pace) - Time spent waiting at red lights, with watch paused
`elapsedTime - timer`

- Average stride length (in metres)
`avgspeed_raw / cadence * 60`

- Avg stride length (in feet)
`avgspeed_raw / cadence * 60 / metresPerFoot`

- Alternate between min hr (displayed with a "-" prefix) and max hr, every 5 seconds

`if (timer mod 10 lt 5, -min(hr), maxHR)`

- Distance to next aid station at 5, 12.5, 17, (km or miles, per device settings)

`findlte(distance, 5, 12.5, 17) - distance`

- Display speed only if gps fix is good

`if(locationAccuracy eq 4, speed, null)`

- Stride length (based 10 second average speed) (in metres) [avg]

`timeavg(speed_raw, 10) / cadence * 60`

- Vertical speed (instantaneous)

`(altitude - prev(altitude)) / (timer - prev(timer))`

- Vertical speed (15 second avg) [avg]

`timeavg((altitude - prev(altitude)) / (timer - prev(timer)),15)`

- Moving time (faster than 2 mph = 0.89408 m/s)

`sum(speed_raw gt 0.89408)`

Display Format: Time - 10 minute countdown
`if (timer gt 10*60, 0, 10*60 - timer)`

(Display format: Time) - Alert at aid stations and show distance to next aid station [CIQ2]

`alert(distance gte 5); alert(distance gte 12.5); alert(distance gte 17); findlte(distance, 5, 12.5, 17) - distance`

- Alert every 5 km/mi [CIQ2]

`alert(distance gte 5 and distance mod 5 lte 0.1)`

- Alert every 1k, for the first 5k [CIQ2]

`alert(distance gte 1 and distance lte 5.1 and distance mod 1 lte 0.1)`

- Show 10 min countdown and beep/vibrate when it's over [CIQ2]

`alert(timer gte 10*60); 10*60 - timer`

- Show 10 min countdown; beep/vibrate and display 0 when it's over [CIQ2]

`alert(timer gte 10*60); if (timer gt 10*60, 0, 10*60 - timer)`

- Distance to start [CIQ2]
`distanceToStart`

- Estimated time to start [CIQ2]
`distanceToStart_raw / avgspeed_raw`

- Workout pace: Average speed/pace for even numbered laps [avg]

`avg(if (lapCount mod 2 eq 0, speed, null))`

- Time spent sprinting (faster than 16 km/h), assuming device speed units = km

`sum(speed gt 16)`

(Set Display Format to "Time") - Time spent sprinting (faster than 5 m/s)

`sum(speed_raw gt 5)`

(Set Display Format to "Time") - Count sprints [CIQ2]

`sum(when(speed_raw gt 5))`

- Count sprints longer than 30 seconds. [CIQ2]
`sum(when(speed_raw gt 5, 30))`

- Count sprints. Beep and vibrate when starting/stopping [CIQ2]

`sum(when(speed_raw gt 5, 0, 0, 1, 1))`

- Count sprints. Vibrate when starting [CIQ2]

`sum(when(speed_raw gt 5, 0, 0, 3))`

- Lap ascent
`totalascent - lapmin(totalascent)`

- Lap descent
`totaldescent - lapmin(totaldescent)`

- Lap Elevation Change I

`totalascent - lapmin(totalascent) - (totaldescent - lapmin(totaldescent))`

(based on Total ascent and Total descent, which are filtered by Garmin) - Lap Elevation Change II [AppBuilder5] [CIQ1]

`setv(if (prev(timer_raw, 2) eq 0 or prev(lapCount,2) lt lapCount, 1, null), altitude) ; getv(1) - altitude`

(based on altitude change) - Lap Elevation Change II [AppBuilder5] [CIQ2]

`lapstart(altitude) - altitude`

(based on altitude change) - Rest timer (count up from 0:00 every time activity paused; e.g. workout rest intervals)

`elapsedtime - max(elapsedtime)`

Display Format: Time

(max only considers data while activity not paused.) - Work timer (count up from 0:00 every time the activity is unpaused; e.g. workout active intervals)

`timer - max(if (prev(timer) eq null, timer, null)) plus 1`

Display Format: Time

(prev(x): returns previous sample of x (from 1 second ago), but only if watch is not paused

max(if (prev(timer) eq null, timer, null)): The timer at first second after watch is unpaused) - Time of day (24-hour clock)
`timeofday`

Display Format: Time - Time of day (24-hour clock), no seconds
`timeofday div 60`

Display Format: Time - ETA for marathon, based on 60s average speed (distance/speed units = any)

`timeofday plus (42195 - distance_raw) / timeavg(speed_raw, 60)`

Display Format: Time - ETA for marathon, based on 60s average speed (distance/speed units = any), omit seconds

`(timeofday plus (42195 - distance_raw) / timeavg(speed_raw, 60)) div 60`

Display Format: Time - Pace in seconds per km
`1 / speed_raw * 1000`

- Pace in s per km/mi, as per device speed settings
`1 / speed * 3600`

Note: with Pace in s per km/mi, use Time display format for mm:ss. With speed in km/h or mi/h, use Pace format for mm:ss. - [avg] Average cadence
`avg(cadence)`

- avg cadence, not including any values below 10
`avg(if(cadence gte 10, cadence, null))`

- 5 second countdown with beep/vibration alert. Repeats indefinitely. [CIQ2]

`alert(timer gte 5 and round(timer) mod 5 gte 0 and round(timer) mod 5 lte 2) ; 5 - (round(timer) mod 5)`

Display Format: Time

(Normally rounding of intermediate results is unnecessary, but for a short countdown, it makes sense.) - distance faster than 7:30 pace (per km/mi, per settings)

`sum( if ( 1 / speed * 3600 lte 7 * 60 + 30, distance - prev(distance), 0 ) )`

- Remaining distance to 5 mi/km target above 7:30 pace per mi/km, per settings

`5 - sum( if ( 1 / speed * 3600 lte 7 * 60 + 30, distance - prev(distance), 0 ) )`

- Remaining distance to 5 mi/km target above 7:30 pace per mi/km, and alert when target is reached: [AppBuilder5] [CIQ2]

`setv(1, 5 - sum(if (1 / speed * 3600 lte 7 * 60 + 30, distance - prev(distance), 0))) ; alert(getv(1) lte 0) ; getv(1)`

- Normalized Power [AppBuilder5] [CIQ2]

Normalized Power (native): Activity average

`avg(timeavg(power,30,1)^4)^0.25`

Lap np (native): Carries the rolling average over from previous lap

`lapavg(timeavg(power,30,1)^4)^0.25`

Lap np: Resets at start of each lap

`lapavg(ifs(lapTime gte 30,timeavg(power,30,1)^4))^0.25`

- Normalized Power [AppBuilder5] [CIQ1]

Normalized Power (native): Activity average

`avg(ifs(timer gte 30 and (timer - max(ifs (prev(timer) eq null, timer)) plus 1) gte 30, timeavg(power,30)^4))^0.25`

Lap np (native): Carries the rolling average over from previous lap

`lapavg(ifs(timer gte 30 and (timer - max(ifs (prev(timer) eq null, timer)) plus 1) gte 30, timeavg(power,30)^4))^0.25`

Lap np: Resets at start of each lap

`lapavg(ifs(lapTime gte 30 and (timer - max(ifs (prev(timer) eq null, timer)) plus 1) gte 30, timeavg(power,30)^4))^0.25`

These behave like native fields, except in the case of when the activity is paused and unpaused. With these formulas, when the activity is unpaused, the np or Lap np will not be updated until a full 30 seconds has passed (to obtain enough samples for a rolling average)

Explanation:

**timer gte 30**: Wait 30 seconds from the start of the activity before considering data for the overall average

**LapTime gte 30**: Wait 30 seconds from the start of the lap before considering data

**max(ifs (prev(timer) eq null, timer)) plus 1) gte 30**: Wait 30 seconds from the last time the activity was unpaused before considering data - Intensity Factor [AppBuilder5] [CIQ2]

Substitute your FTP for*YOUR_FTP*

`avg(timeavg(power,30,1)^4)^0.25 /`

*YOUR_FTP* - Intensity Factor [AppBuilder5] [CIQ1]

Substitute your FTP for*YOUR_FTP*

`avg(ifs(timer gte 30 and (timer - max(ifs (prev(timer) eq null, timer)) plus 1) gte 30, timeavg(power,30)^4))^0.25 /`

*YOUR_FTP* - HR Zone (whole number/integer)

`findlteindex(hr+1, UserHRZone1Min, UserHRZone1max, UserHRZone2max, UserHRZone3max, UserHRZone4max, UserHRZone5max+1, 220+1)`

- Heart Rate Zone (fractional) [AppBuilder5]

`setv(1, findgte(hr, UserHRZone5max+1, UserHRZone4max, UserHRZone3max, UserHRZone2max, UserHRZone1max, UserHRZone1Min, 35)) ; findltindex(hr, UserHRZone1Min, UserHRZone1max, UserHRZone2max, UserHRZone3max, UserHRZone4max, UserHRZone5max+1, 220+1) + (hr - getv(1)) / (findlt(hr, UserHRZone1Min, UserHRZone1max, UserHRZone2max, UserHRZone3max, UserHRZone4max, UserHRZone5max+1, 220+1) - getv(1))`

**This example is too complex for ciq 1 devices, although all the functions are technically supported** - Heart Rate Zone (fractional) [AppBuilderClassic]

`findlteindex(hr+1, UserHRZone1Min, UserHRZone1max, UserHRZone2max, UserHRZone3max, UserHRZone4max, UserHRZone5max+1, 220+1) + (hr - findgte(hr, UserHRZone5max+1, UserHRZone4max, UserHRZone3max, UserHRZone2max, UserHRZone1max, UserHRZone1Min, 35)) / (findlte(hr+1, UserHRZone1Min, UserHRZone1max, UserHRZone2max, UserHRZone3max, UserHRZone4max, UserHRZone5max+1, 220+1) - findgte(hr, UserHRZone5max+1, UserHRZone4max, UserHRZone3max, UserHRZone2max, UserHRZone1max, UserHRZone1Min, 35))`

Basically: HR_fractional_zone = HR_integer_zone + (hr - HR_zone_min) / (Hr_zone_max - HR_zone_min)

Garmin seems to use 35 as the minimum for "zone 0"

More detailed explanation**This example is too complex for ciq 1 devices, although all the functions are technically supported** - Approximate rolling average (good for large samples) [AppBuilder5]

`setv(1, if (getv(1) eq null, 0, getv(1) - getv(1) /`

*n*+ alt(*x*, 0) /*n*))

*x*: quantity/formula to average

*n*: number of samples (seconds)

This is an exponentially weighted average (not quite the same as a moving average), but it doesn't need to store all the data, so it works with large samples (e.g. 20 minute power)**alt(x, 0)**: Has the effect of treating a null/blank x as 0, so the formula doesn't reset the average if x is null.

Source - Approximate 20 minute power [AppBuilder5]

`setv(1, if (getv(1) eq null, 0, getv(1) - getv(1) / 1200 + alt(power, 0) / 1200))`

- Approximate FTP [AppBuilder5]

`setv(1, if (getv(1) eq null, 0, getv(1) - getv(1) / 1200 + alt(power, 0) / 1200)) ; max(getv(1)) * 0.95`

- 20 minute power (newer Edges and Fenix 5+) [AppBuilder5]

`timeavg(power,1200,1)`

1200 samples takes a lot of memory, so this won't work on most devices. Note that nothing will be displayed until 20 minutes have passed. - 20 minute power (show average even before 20 minutes) (newer Edges and Fenix 5+) [AppBuilder5]

`timeavg(power,1200,0)`

- FTP (newer Edges and Fenix 5+) [AppBuilder5]

`max(timeavg(power,1200,1)) * 0.95`

- FTP (display 20-minute countdown) (newer Edges and Fenix 5+) [AppBuilder5]

`alt(max(timeavg(power,1200,1)) * 0.95, formattime(max(if (prev(timer) eq null, timer, null)) + 1200 - timer))`

The countdown (and the ftp calculations) reset whenever you pause the activity. - Save/Display elevation at beginning of activity [AppBuilder5] [CIQ1]

`setv(if (prev(timer_raw, 2) eq 0, 1, null), altitude) ; getv(1)`

- Save/Display elevation at beginning of activity [AppBuilder5] [CIQ2]

`start(altitude)`

- Save/Display elevation at beginning of lap [AppBuilder5] [CIQ1]

`setv(if (prev(timer_raw, 2) eq 0 or prev(lapCount, 2) lt lapcount, 1, null), altitude) ; getv(1)`

- Save/Display elevation at beginning of lap [AppBuilder5] [CIQ2]

`lapstart(altitude)`

- Power Zone [AppBuilder5]

`setv(1, findgte(power, 240, 210, 180, 150, 110, 50, 0)) ; findltindex(power, 50, 110, 150, 180, 210, 240, 300) + (Power - getv(1)) / (findlt(power, 50, 110, 150, 180, 210, 240, 300) - getv(1))`

Assuming your zones are:

**0**to 50

**50**to 110

**110**to 150

**150**to 180

**180**to 210

**210**to 240

**240**to**300**

Adjust as necessary for your actual power zones.

iow: Fractional Power Zone = Integer Power Zone + (Power - Zone Min) / (Zone max - Zone Min) - Strength activity set counter

`lapcount div 2 + 1`

- Lap calories [Appbuilder5] [CIQ1]

`setv(if (prev(timer_raw, 2) eq 0 or prev(lapcount, 2) lt lapcount, 1, null), calories) ; calories - getv(1)`

- Last Lap Average hr [AppBuilder5] [CIQ1]

`setv(if (prev(lapCount, 2) lt lapcount, 1, null), prev(lapavg(hr), 2)) ; getv(1)`

- Lap calories [Appbuilder5] [CIQ2]

`calories - lapstart(calories)`

- Last Lap Average HR [Appbuilder5] [CIQ2]

`lastlap(lapavg(hr))`

- Last Lap calories [Appbuilder5] [CIQ2]

`lastlap(calories - lapstart(calories))`

- Last Lap Time [Appbuilder5] [CIQ2]

`lastlap(laptime)`

- Last Lap Total Time [Appbuilder5] [CIQ2]

`lastlap(timer)`

- Lap Speed (in km/h or miles/h, as per device unit settings)
`lapdistance / laptime * 3600`

Speed = distance / time

lapDistance is in km or miles (as per settings)

lapTime is in seconds

There are 3600 seconds in one hour, which is why you multiply by 3600. - Lap Pace
`lapdistance / laptime * 3600`

Set Display Format to Pace - Last Lap Speed [Appbuilder5] [CIQ2]
`lastlap(lapdistance / laptime * 3600)`

- Last Lap Pace [Appbuilder5] [CIQ2]
`lastlap(lapdistance / laptime * 3600)`

Set Display Format to Pace - Lap Speed (in metres/second)
`lapdistance_raw / laptime`

- Average power, 3 decimal places [Appbuilder5] [CIQ2]

`formatdecimal(avg(power), 3)`

- Moving speed (miles or km/h, per device unit settings)

`distance / sum(speed_raw gt 0.89408) * 3600`

- Moving pace (minutes per mile/km)

`distance / sum(speed_raw gt 0.89408) * 3600`

Display Format: Pace - Elevation grade (rough estimate over last 50 metres) [AppBuilderClassic] [CIQ2]

`(altitude_raw - prevd(altitude_raw, 50)) / (distance_raw - prevd(distance_raw, 50)) * 100`

- Elevation grade (much better estimate) [AppBuilder5] [CIQ2]

`IF(Speed_raw GTE 1, TIMEAVG((Altitude_raw - PREVN(Altitude_raw, 14)) / (Distance_raw - PREVN(Distance_raw, 14)) *100, 3), 0)`

- Record Power so sites like Training Peaks, Stryd and Smashrun recognize it [AppBuilder5] [CIQ2]

`record(power, 7, "Power")`

- Time for last 5K [AppBuilder5] [LargeMemory]

`timer - prevd(timer, 5000, 5000, 1)`

Cant seem to get this to work at all, have installed via connect iq and set formula, but wont work. I am trying to get mph in cycling mode. Do you need to do running mode as well?

ReplyDeleteHey, you don't need to do running mode, it will work in any mode. Not sure why it isn't working for you. Could you try a simple formula like Timer or Cadence / 2? Thanks.

DeleteIs there any formula for total rpm? There was the total pedaling strokes on Garmin Connect

ReplyDeleteIs there a way to display the time in the current interval, where the interval is defined by the speed being above some threshold (e.g. 4mph). In other words, I'd like to know how long ago the speed last was below 4mph.

ReplyDeleteA follow-on question is whether there is a way to display the pace in the current interval. In other words, time-in-interval divided by distance-in-interval.

Very cool and helpful app overall, plus good docs! Hats off! Thanks much!