Use Mapbox APIs in Leaflet.js
Leaflet.js is a lightweight JavaScript mapping library that renders raster tile layers and GeoJSON data. Because Mapbox APIs return standard raster tile URLs and GeoJSON geometries, they integrate with Leaflet's native layer types without any additional adapters.
Mapbox GL JS is the recommended library for building web maps with Mapbox. It provides first-class support for the full Mapbox ecosystem — including vector tile rendering, Mapbox Standard styles, Search JS, and Navigation SDKs — and is actively developed alongside Mapbox APIs.
That said, Mapbox's core Maps services use open standards: raster tile URLs follow the XYZ/TMS convention, vector tiles use the Mapbox Vector Tile specification, and Navigation and Search APIs return standard GeoJSON. This makes them interoperable with third-party mapping libraries and GIS software that support these formats.
Access tokens
All Mapbox APIs require an access token for authentication. Your token is passed as the access_token query parameter on every request.
You can find your default public token — or create a new one with specific scopes — on the Access tokens page in the Mapbox Developer Console. Public tokens start with pk..
https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=YOUR_ACCESS_TOKEN
When using Mapbox APIs in a client-side web application, use a public token with URL restrictions configured to your domain, so the token can't be used by other sites. See How to use Mapbox securely for guidance on restricting tokens and avoiding exposure.
Leaflet does not support vector tile rendering, so Mapbox basemaps are consumed as raster tiles via the Static Tiles API. The Directions and Isochrone APIs return GeoJSON that L.geoJSON() can render directly. Mapbox Search JS provides a web component that works alongside Leaflet through its retrieve event.
Raster basemap tiles
The Static Tiles API renders any Mapbox style as 512×512 raster PNG tiles. Use L.tileLayer with tileSize: 512 and zoomOffset: -1 to align Mapbox's native tile size with Leaflet's 256px default.
L.tileLayer(
'https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=YOUR_MAPBOX_ACCESS_TOKEN',
{
tileSize: 512,
zoomOffset: -1,
maxZoom: 22,
attribution:
'© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> ' +
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}
).addTo(map);
Swap streets-v12 for any classic Mapbox style or a custom style ID from your Mapbox Studio account.
Satellite imagery
The Raster Tiles API serves the mapbox.satellite imagery tileset as standard XYZ tiles. These are 256px tiles with no labels or road overlays.
L.tileLayer(
'https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.jpg90?access_token=YOUR_MAPBOX_ACCESS_TOKEN',
{
maxZoom: 22,
attribution:
'© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> ' +
'© <a href="https://www.maxar.com/">Maxar</a>'
}
).addTo(map);
To display satellite imagery with road and label overlays, use the satellite-streets-v12 style through the Static Tiles API instead:
https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=YOUR_MAPBOX_ACCESS_TOKEN
Directions and Isochrone API
The Directions API and Isochrone API return standard GeoJSON. Use L.geoJSON() to render route lines and reachability polygons on your map.
const origin = [-73.9855, 40.7580]; // Times Square
const destination = [-73.9969, 40.7061]; // Brooklyn Bridge
// Render driving isochrones (5, 10, 15 minutes)
const isoRes = await fetch(
`https://api.mapbox.com/isochrone/v1/mapbox/driving/${origin[0]},${origin[1]}` +
`?contours_minutes=5,10,15&polygons=true&access_token=YOUR_MAPBOX_ACCESS_TOKEN`
);
const isoData = await isoRes.json();
// Render outermost polygon first so smaller ones appear on top
isoData.features.reverse().forEach((feature, i) => {
L.geoJSON(feature, {
style: {
fillColor: ['#1d4ed8', '#3b82f6', '#93c5fd'][i],
color: ['#1d4ed8', '#3b82f6', '#93c5fd'][i],
fillOpacity: 0.25,
weight: 1.5
}
}).addTo(map);
});
// Render a driving route
const routeRes = await fetch(
`https://api.mapbox.com/directions/v5/mapbox/driving/` +
`${origin[0]},${origin[1]};${destination[0]},${destination[1]}` +
`?geometries=geojson&access_token=YOUR_MAPBOX_ACCESS_TOKEN`
);
const routeData = await routeRes.json();
L.geoJSON(routeData.routes[0].geometry, {
style: { color: '#1d4ed8', weight: 4, opacity: 0.9 }
}).addTo(map);
L.geoJSON() handles the WGS84 coordinate order from the API automatically. Note that Leaflet's own API methods (L.marker, map.flyTo) expect [latitude, longitude] order — the opposite of GeoJSON.
Search JS
Mapbox Search JS provides MapboxSearchBox, a web component that renders a search input backed by the Mapbox Search API. In Leaflet, position it as an overlay on the map and handle the retrieve event to fly to selected results.
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script id="search-js" defer
src="https://api.mapbox.com/search-js/v1.2.0/web.js">
</script>
<style>
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
/* Position the search box as a centered overlay — MapboxSearchBox
cannot be added via map.addControl() in Leaflet like it can in
Mapbox GL JS, so it must be placed manually with CSS. */
#search-container {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
width: 320px;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="search-container"></div>
<script>
const ACCESS_TOKEN = 'YOUR_MAPBOX_ACCESS_TOKEN';
const map = L.map('map').setView([40.7128, -74.006], 12);
L.tileLayer(
'https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=' +
ACCESS_TOKEN,
{ tileSize: 512, zoomOffset: -1, maxZoom: 22 }
).addTo(map);
let resultMarker = null;
window.addEventListener('load', () => {
const searchBox = new MapboxSearchBox();
searchBox.accessToken = ACCESS_TOKEN;
searchBox.options = {
types: 'address,poi',
proximity: [-74.006, 40.7128] // bias results toward the map center
};
document.getElementById('search-container').appendChild(searchBox);
searchBox.addEventListener('retrieve', (event) => {
const feature = event.detail.features[0];
const [lng, lat] = feature.geometry.coordinates; // GeoJSON: [lng, lat]
map.flyTo([lat, lng], 15); // Leaflet: [lat, lng]
if (resultMarker) resultMarker.remove();
resultMarker = L.marker([lat, lng])
.bindPopup(feature.properties.name || feature.properties.full_address)
.addTo(map)
.openPopup();
});
});
</script>
</body>
Related guides
- Use Mapbox APIs in OpenLayers
- Use Mapbox APIs in MapLibre GL JS
- Add a Mapbox map as a basemap in QGIS and ArcMap Pro with WMTS
Pricing
Most Mapbox services include a free tier that covers a generous volume of monthly usage — enough for development and many production use cases. Beyond the free tier, pricing is usage-based and varies by product.
| Service | Pricing details |
|---|---|
| Maps (raster and vector tiles) | Maps pricing |
| Directions API | Navigation pricing |
| Isochrone API | Navigation pricing |
| Search / Geocoding | Search pricing |
See the Mapbox pricing page for current free tier limits and rates. When consuming tiles through a third-party library (rather than Mapbox GL JS), tile requests are billed individually under the Maps API rather than being bundled into a map load.