Navigation milestones inside the SDK provide a powerful way to give your user instructions or get cues to hide or show custom UI at defined locations along their route. You can create custom milestones that fit your particular app needs.

Default Milestones


The VoiceInstructionMilestone will fire every time it's time to announce an instruction along a given DirectionsRoute. This milestone provides a plain text instruction with VoiceInstructionMilestone#getInstruction as well as a SSML version of the same instruction with VoiceInstructionMilestone#getSsmlAnnouncement.
SSML stands for Speech Synthesis Markup Language and is designed to work with AWS Polly.


The BannerInstructionMilestone will fire every time textual instructions should be updated, most of the time in the format of a "banner" view on the top of the screen. This milestone provides a BannerInstructions object for the given point along the route. This object contains text and URLs for shield images that can be displayed on screen at the time the milestone fires.

Milestone event listener

All the milestones use the onMilestoneEvent callback to alert when they get triggered. If you want to make use of the milestones API, you will want to attach a MilestoneEventListener inside your app. When all the milestone trigger conditions are true, the callback is invoked and provides you with the latest routeProgress along with the milestone's corresponding String instruction and the Milestone itself that was triggered. You can use your text-to-speech engine of choice and have it consume the instruction.

public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Milestone milestone) {

Building a custom milestone

Milestones bring flexibility to your app and how it handles navigation events. Creating a milestone is done in just a few steps. First, choose how frequently you'd like the milestone to be triggered. Two options are currently provided, StepMilestone, which is triggered each step in the route and RouteMilestone, which will only get trigger once during the entire route. You can also implement your own behavior for triggers by extending the Milestone class. Give the milestone a unique identifier which can be used to determine which milestone triggered the onMilestoneEvent callback. Set the triggers using any combination of the properties shown in the table below. It is important to note that trigger properties have different corresponding variable types that need to be accounted for when setting the milestone up. Lastly, build the milestone and pass it into the MapboxNavigation instance using addMilestone().

The snippet of code provided below shows the creation of a RouteMilestone with two conditions, both of which need to be true for the milestone to be triggered. Since it is a RouteMilestone, the milestone event only occurs once. The trigger statement can be read as: both the step index must be less than 3 and the current step total distance must be greater than 200 meters for the milestone to be triggered.

navigation.addOffRouteListener(new OffRouteListener() {
public void userOffRoute(Location location) {
navigation.addMilestone(new RouteMilestone.Builder()
Trigger.lt(TriggerProperty.STEP_INDEX, 3), Trigger.gt(TriggerProperty.STEP_DISTANCE_TOTAL_METERS, 200))).build()

Trigger conditions

Besides the triggers already mentioned above, the SDK comes equipped to handle pretty much any case you'd like to build. The table below shows all the conditions currently offered inside the SDK and whether it is a compound statement or a simple statement.

Condition nameTypeDescription
allCompoundLogical equivalent to an AND statement, all the conditions must be true for the trigger to occur.
anyCompoundLogical equivalent to an OR statement, any of the conditions can be true to cause a trigger.
noneCompoundLogical equivalent to a NOR statement, all statements must equate to false for a trigger to occur.
eqSimpleEquality. The trigger property's current value must equal the exact value defined.
neqSimpleInequality. The trigger property's current value must not equal the exact value defined.
gtSimpleGreater than. The trigger property's current value must be greater than the defined value.
gteSimpleGreater than or equal. The trigger property's current value must be greater than or equal to the defined value.
ltSimpleLess than. The trigger property's current value must be less than the defined value
lteSimpleLess than or equal. The trigger property's current value must be less than or equal to the defined property.

Trigger properties

Below are the available trigger properties that can be used along with the conditions above to filter when a milestone should be triggered. Note that instead of the boolean types using the primitive type true or false, the TriggerProperty class uses custom boolean values for the triggers.

Property nameTypeDescription
STEP_INDEXintegerWhich step or steps the user must be on the trigger the milestone.
STEP_DISTANCE_TOTAL_METERSdoubleThe length that the current step must be.
STEP_DISTANCE_REMAINING_METERSdoubleWill trigger the milestone based on the distance remaining.
STEP_DURATION_REMAINING_SECONDSdoubleWill trigger the milestone based on the duration remaining.
STEP_DURATION_TOTAL_SECONDSdoubleWill trigger the milestone based on the total step duration.
STEP_DISTANCE_TRAVELED_METERSdoubleWill trigger the milestone based on the distance the user has traveled along the step already.
NEW_STEPbooleanWhen the user completes a maneuver and begins traversing along a new step.
FIRST_STEPbooleanWhen the user begins a navigation session and is currently on the first step.
LAST_STEPbooleanWhen the user is on the second to last step. Note the final step in direction route will only contain a point representing the final maneuver.
NEXT_STEP_DISTANCE_METERSdoubleThe next step's total distance in meters.
FIRST_LEGbooleanWhen the user is on the first leg.
LAST_LEGbooleanWhen the user is on the last leg.

We are actively adding more and more trigger properties every day while we continue building out the milestones API. Please open an issue on GitHub if you feel a trigger property is missing and include the use-case.

Custom instructions

You'll see in the next section about the milestone event listener that the callback provides a String instruction value. During the milestone creation process, you can add the logic that generates this instruction. Begin by creating a new Instruction object which will provide an override method, buildInstruction, which provides a RouteProgress object for producing the instructions string. With the provided route progress, you can add information such as distance and duration remaining until the next maneuver. Once the Instruction is initialized, you will need to give it to the milestone using setInstruction. The example below shows how to add the directions API instruction with no modifications as the milestone instruction.

Instruction myInstruction = new Instruction() {
public String buildInstruction(RouteProgress routeProgress) {
return routeProgress.currentLegProgress().upComingStep().maneuver().instruction();