Skip to main content

Route progress

When turn-by-turn navigation starts, your project must track the user's progress along the route to provide relevant information appropriately and prompt. The RouteProgress object in the Navigation SDK contains this essential information, and this page will guide you on how to use it effectively.

Levels of route progress

The Mapbox Navigation SDK's model for tracking route progress has three pieces with different levels of granularity: the route, the leg, and the step.

Route: The blue line is a route. A route stretches between the origin and the final destination.

Leg: The larger circles with a pink stroke represent waypoints, or stops, along the route. A leg is the part of the route between two waypoints.

Step: The smaller circles with a green stroke represent maneuvers. A step is the part of the leg between two maneuvers.

The Navigation SDK uses three classes to communicate information on the user's progress at these three different levels: RouteProgress, RouteLegProgress, and RouteStepProgress.


The RouteProgress class contains all the progress information at any time during a navigation session. A new RouteProgress object is generated whenever there's a new valid Location update or if no new Location update is received in the past second.

RouteProgress information includes distance measurements, the percentage of the route that's been completed, the current step index, the remaining number of route legs, and much more. For further information on data encapsulated in RouteProgress, you can view the API reference docs here.


The RouteLegProgress class is specific to the current leg the user is on. For further information on data encapsulated in RouteLegProgress, you can view the API reference docs here.


The RouteStepProgress class is a progress object specific to the current step the user is on. For further information on data encapsulated in RouteStepProgress, you can view the API reference docs here.

Route progress and UI components

Several of the Navigation SDK's default UI components use route progress data to present guidance information to your users. Here's how each component uses route progress data:

  • Maneuvers: Invoke the Maneuver API when route progress changes to receive updated banner instruction data any time the route progress changes. Read more in the Maneuver instructions guide.
  • Trip progress: Invoke the Trip Progress API when route progress changes to keep the estimated arrival time, distance remaining, and time remaining up to date as the user progresses along the route. Read more in the Trip progress guide.
  • Route line: Invoke the Route Line API to render a route line on a map.
  • Route arrow: Invoke the Route Arrow API when route progress changes to determine when to show an arrow on the route line.
  • Buildings: Invoke the Buildings API when route progress changes to highlight the building upon arrival at a waypoint or final destination.
  • Notifications: Invoke the MapboxNavigation#updateNotification when route progress changes to receive updated maneuver instructions when the app is running in background. Read more in the Notifications guide.

Apart from leveraging route progress to drive the user interface elements offered by the SDK, you have the flexibility to tailor your application's behavior in response to the user's movement along the route. This can be achieved by monitoring progress changes, assessing the state of route progress, and executing customized code based on these factors.

Listen to progress change

Tracking a user's progress along a route is key to providing helpful and prompt navigation instructions. Implement the Navigation SDK's RouteProgressObserver interface to receive a RouteProgress object every time the user's location changes.

The RouteProgressObserver is commonly utilized to update your application's user interface in response to changes in route progress. For instance, if you are showing the user's current progress up to their next maneuver, you can refresh your display whenever the onRouteProgressChanged() method of this interface is triggered. Each time this occurs, you can update your view with the latest information contained in the RouteProgress object.

private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {


If you've created your own RouteProgressObserver object, you'll need to:

  1. Register the RouteProgressObserver with your already-instantiated MapboxNavigation object.
  1. Don’t forget to unregister the observer with mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver).


The Navigation SDK's RouteProgressState is an enum that contains various states that can occur while navigating. Using RouteProgressState helps you gain a better understanding of what's happening in the navigation experience.

The RouteProgressObserver returns a RouteProgress object. Check the current state with the RouteProgressState object inside the returned RouteProgress object:

private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
routeProgress.currentState()?.let { currentState ->
val state = currentState

There are five possible states: INITIALIZED, TRACKING, COMPLETE, OFF_ROUTE, and UNCERTAIN.


When a new route is first loaded and the DirectionsRoute JSON is valid, route-following will start in the RouteProgressState.INITIALIZED state. From there, route-following will try to gain confidence that the Location objects being passed to the device are the user's location. To show this trust, at least a few location updates need to be delivered, and they must be consecutively coherent in both time and space. While it is establishing this trust, the route-following logic will report that it's still in the RouteProgressState.INITIALIZED state.


Once MapboxNavigation is confidently tracking the Location updates and processing them against the DirectionsRoute. The state will change to RouteProgressState.TRACKING.


When the user has arrived at the destination of the given RouteLeg, the state will be RouteProgressState.COMPLETE.

Off Route

The RouteProgressState.OFF_ROUTE occurs when the navigation system determines the user has deviated from the established route.


The RouteProgressState.UNCERTAIN state occurs when the Navigation SDK has already been tracking location updates (RouteProgressState.TRACKING), but the route-snapping algorithm has temporarily lost confidence. For example, due to a rerouting when the device strays off the turn-by-turn directions route. After a couple of Location updates after the rerouting, RouteProgressState would return back to RouteProgressState.TRACKING.

Visualizing the route progress state

The route progress state can be communicated to users by updating the style of the puck during navigation. In your RouteProgressObserver check the state and update the drawable used for the puck. You can design your own custom drawables and use them as shown below.

private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
routeProgress.currentState.let { currentState ->
val puckDrawable = when (currentState) {
RouteProgressState.INITIALIZED -> R.drawable.your_drawable_for_initialized_state
RouteProgressState.TRACKING -> R.drawable.your_drawable_for_tracking_state
RouteProgressState.COMPLETE -> R.drawable.your_drawable_for_complete_state
RouteProgressState.OFF_ROUTE -> R.drawable.your_drawable_for_off_route_state
RouteProgressState.UNCERTAIN -> R.drawable.your_drawable_for_uncertain_state
mapView.location.apply {
this.locationPuck = LocationPuck2D(
bearingImage = ContextCompat.getDrawable(context, puckDrawable)
Was this page helpful?