Getting started with the Mapbox Directions API
The Mapbox Directions API makes it possible to provide users with routes, turn instructions, and trip durations. This tutorial walks you through the process of requesting directions, adding a single bike route between a fixed location and a clicked location, and displaying the route's turn-by-turn instructions.
Getting started
Here are a few resources you'll need before getting started:
- An access token from your account. You will use an access token to associate a map with your account and you can find it on the Account page.
- Mapbox Directions API documentation. A reference for all options available when making requests and how to interpret responses.
- Mapbox GL JS. The Mapbox JavaScript library that uses WebGL to render interactive maps from Mapbox GL styles.
- A text editor. You'll be writing HTML, CSS, and JavaScript.
Build a Directions API request
When making a request to any Mapbox web service, the general structure of the request URL will start like this:
https://api.mapbox.com/{service}/
In this case, the {service}
will be directions
, but you can also make requests of styles
, geocoding
, and other Mapbox APIs.
The next part will be the version number. The version number is helpful to know since the API may change over time and provide you with greater capabilities or change how the requests may work. The current version for directions is v5
:
https://api.mapbox.com/directions/v5/
Parameters
If you tried to paste this into your browser's address bar, the request would not return anything. You still need to pass in some parameters that will narrow the scope of your request. In the case of the Mapbox Directions API, you are required to supply a profile (a mode of travel) and coordinates (the origin and the destination) for your request:
- In this case, use the
cycling
profile to generate a bike route. - Use
-84.518641, 39.134270
as your starting coordinate and-84.512023, 39.102779
as your destination. Note that these coordinates must be separated by a semi-colon;
. - Use the optional parameter
geometries=geojson
to specify that you would like it to return the route as a GeoJSON feature.
https://api.mapbox.com/directions/v5/mapbox/cycling/-84.518641,39.134270;-84.512023,39.102779?geometries=geojson
Access token
The only required item left is your access token. The access token is required to track the requests you make from your account for this particular service. You can create specific tokens for your requests or use your default token.
When adding this token, use an ampersand (the &
symbol) before the token to append this to the request:
https://api.mapbox.com/directions/v5/mapbox/cycling/-84.518641,39.134270;-84.512023,39.102779?geometries=geojson&access_token=YOUR_MAPBOX_ACCESS_TOKEN
Now that you have a request, paste the full URL into your browser's address bar to get a response.
Review the response
When you make your request, a JSON object will be returned with the following information:
- waypoints: This is an array of Waypoint objects. In this case, this array will include your starting and ending points.
- routes: This is an array of Route objects ordered by descending recommendation rank. In this case, you have not requested alternative routes, so only one route will be returned. You will use the
geometry
property to display the route on a map in the next step. - code: This string indicates the state of the response. On normal valid responses, the value will be
Ok
.
{
"waypoints": [
{
"location": [-84.518399, 39.134126],
"name": ""
},
{
"location": [-84.511987, 39.102638],
"name": "East 6th Street"
}
],
"routes": [
{
"legs": [
{
"steps": [],
"weight": 1332.6,
"distance": 4205,
"summary": "",
"duration": 1126
}
],
"weight_name": "cyclability",
"geometry": {
"coordinates": [
[-84.518399, 39.134126],
[-84.51841, 39.133781],
[-84.520024, 39.133456],
[-84.520321, 39.132597],
[-84.52085, 39.128019],
[-84.52036, 39.127901],
[-84.52094, 39.122783],
[-84.52022, 39.122713],
[-84.520768, 39.120841],
[-84.519639, 39.120268],
[-84.51233, 39.114141],
[-84.512652, 39.11311],
[-84.512399, 39.112216],
[-84.513232, 39.112084],
[-84.512127, 39.107599],
[-84.512904, 39.107489],
[-84.511692, 39.102682],
[-84.511987, 39.102638]
],
"type": "LineString"
},
"weight": 1332.6,
"distance": 4205,
"duration": 1126
}
],
"code": "Ok"
}
Build the map
Now that you understand how Mapbox Directions API requests and responses both work, you can use this API request to add a route to a web map.
Set up your HTML file
Create a new HTML file called index.html
and initialize a Mapbox GL JS map using the code below.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Getting started with the Mapbox Directions API</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js"></script>
<link
href="https://api.tiles.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css"
rel="stylesheet"
/>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// add the JavaScript here
</script>
</body>
</html>
Next, add the following script to the block of code within the <script>
tags to initialize your map, the style, and starting position:
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN ';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [-122.662323, 45.523751], // starting position
zoom: 12
});
// set the bounds of the map
const bounds = [
[-123.069003, 45.395273],
[-122.303707, 45.612333]
];
map.setMaxBounds(bounds);
// an arbitrary start will always be the same
// only the end or destination will change
const start = [-122.662323, 45.523751];
// this is where the code for the next step will go
Add your route request function
Next, you'll build a function called getRoute
to make the API request and add the resulting route as a new layer. You'll then call that function when the map loads.
Within the getRoute
function, specify the start
and end
coordinates. The start was defined outside of this function and the end will be passed in as an argument. Use an XHR object to make the API request. You can then use the response to get all the relevant objects and use the geometry to add the response as a layer to the map. You can end this part of the code by executing it with a request after the map loads so that it makes a route that begins and ends at the start location.
Add the following code right after the start constant that you declared earlier:
// create a function to make a directions request
async function getRoute(end) {
// make a directions request using cycling profile
// an arbitrary start will always be the same
// only the end or destination will change
const query = await fetch(
`https://api.mapbox.com/directions/v5/mapbox/cycling/${start[0]},${start[1]};${end[0]},${end[1]}?steps=true&geometries=geojson&access_token=${mapboxgl.accessToken}`,
{ method: 'GET' }
);
const json = await query.json();
const data = json.routes[0];
const route = data.geometry.coordinates;
const geojson = {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: route
}
};
// if the route already exists on the map, we'll reset it using setData
if (map.getSource('route')) {
map.getSource('route').setData(geojson);
}
// otherwise, we'll make a new request
else {
map.addLayer({
id: 'route',
type: 'line',
source: {
type: 'geojson',
data: geojson
},
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#3887be',
'line-width': 5,
'line-opacity': 0.75
}
});
}
// add turn instructions here at the end
}
map.on('load', () => {
// make an initial directions request that
// starts and ends at the same location
getRoute(start);
// Add starting point to the map
map.addLayer({
id: 'point',
type: 'circle',
source: {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: start
}
}
]
}
},
paint: {
'circle-radius': 10,
'circle-color': '#3887be'
}
});
// this is where the code from the next step will go
});
Mapbox also offers a JavaScript SDK, a node.js and browser JavaScript client, to interact with our web services directly in your web applications. You can use the JavaScript SDK to make the Directions API request directly. For more information on the Mapbox JavaScript SDK see the documentation on GitHub.
Now that you've constructed the function that makes the requests and draws the routes, you'll want to load in an initial route from our starting point.
To see if this is working, open your browser's console (Command+Alt+J
on a Mac, Ctrl+Alt+J
on Windows) where you can interact with the application you've written so far. In the console, type getRoute([-122.677738,45.522458])
to execute your function and pass in coordinates for a location in downtown Portland, OR. If everything is working, you should see a line drawn from the east side of the river to the west.
Add your origin and destination
Now that you've created the start point (getRoute(start)
) you'll provide a way to let the user select a destination. Add the next bit of code that allows the user to click the map and update the location of the destination:
map.on('click', (event) => {
const coords = Object.keys(event.lngLat).map((key) => event.lngLat[key]);
const end = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: coords
}
}
]
};
if (map.getLayer('end')) {
map.getSource('end').setData(end);
} else {
map.addLayer({
id: 'end',
type: 'circle',
source: {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: coords
}
}
]
}
},
paint: {
'circle-radius': 10,
'circle-color': '#f30'
}
});
}
getRoute(coords);
});
Add turn instructions
In your HTML, add a new div element after the map
div. This is where you will display turn-by-turn instructions.
<div id="instructions"></div>
Because you added the steps=true
parameter to the initial request, all the instructions for navigating the route are available to parse. Now add these steps to the sidebar in the div element called instructions
.
// get the sidebar and add the instructions
const instructions = document.getElementById('instructions');
const steps = data.legs[0].steps;
let tripInstructions = '';
for (const step of steps) {
tripInstructions += `<li>${step.maneuver.instruction}</li>`;
}
instructions.innerHTML = `<p><strong>Trip duration: ${Math.floor(
data.duration / 60
)} min 🚴 </strong></p><ol>${tripInstructions}</ol>`;
In the directions response object, turn instructions are stored in the routes
property. You can find instructions
inside routes
> legs
> steps
> maneuver
. Each instruction
is a string that describes what the bicycle rider should do next along a route.
Next, add some CSS to style the div
to move it to the left side of your map and give it a white background.
#instructions {
position: absolute;
margin: 20px;
width: 25%;
top: 0;
bottom: 20%;
padding: 20px;
background-color: #fff;
overflow-y: scroll;
font-family: sans-serif;
}
Finished product
You've used the Mapbox Directions API and Mapbox GL JS to add a bicycle route to a map.
Next steps
Now that you have practiced using the Mapbox Directions API, read about additional options in the Directions API documentation. You can also try adding more details to your application:
- Style the origin and destination uniquely.
- Use the Mapbox Geocoding API to assign the start and end points based on user input.
- Add more details, like distance and duration, to the turn instructions.
- Explore other ways to integrate directions services, including turn-by-turn instructions, into your applications including the Mapbox GL directions plugin, the JavaScript SDK, and the Mapbox Navigation SDKs for iOS and Android.
Don't forget to explore other directions-related services like the Mapbox Matrix API and Optimization API.