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.

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 cadenceavg(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)

Comments