Skip to main content

Use Mapbox APIs in MapLibre GL JS

MapLibre GL JS is an open-source fork of Mapbox GL JS that implements the Mapbox Style Specification. Because it shares the same API surface and style format, it integrates with Mapbox raster and vector tile APIs, and with most Mapbox services, using familiar patterns.

For full Mapbox ecosystem support, use Mapbox GL JS

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.

MapLibre does not natively resolve mapbox:// scheme URIs — instead, use direct HTTPS tile URLs in your source definitions. The examples below use the Mapbox APIs' standard HTTPS endpoints.

Vector tiles with custom style

MapLibre natively supports the Mapbox Style Specification, making it the most direct way to consume mapbox.mapbox-streets-v8 vector tiles with a custom style. Pass the full style JSON as the style constructor option — no adapter library required.

The glyphs field points to a font service for rendering text labels. The Mapbox Fonts API provides the same fonts used in Mapbox Studio.

const accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

const map = new maplibregl.Map({
container: 'map',
center: [-74.006, 40.7128],
zoom: 13,
style: {
version: 8,
glyphs: `https://api.mapbox.com/fonts/v1/mapbox/{fontstack}/{range}.pbf?access_token=${accessToken}`,
sources: {
'mapbox-streets': {
type: 'vector',
tiles: [
`https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.mvt?access_token=${accessToken}`
],
maxzoom: 16
}
},
layers: [
{ id: 'background', type: 'background',
paint: { 'background-color': '#1a1a2e' } },
{ id: 'water', type: 'fill',
source: 'mapbox-streets', 'source-layer': 'water',
paint: { 'fill-color': '#16213e' } },
{ id: 'road-major', type: 'line',
source: 'mapbox-streets', 'source-layer': 'road',
filter: ['in', 'class', 'primary', 'secondary', 'trunk'],
paint: { 'line-color': '#445577', 'line-width': 2 } },
{ id: 'road-motorway', type: 'line',
source: 'mapbox-streets', 'source-layer': 'road',
filter: ['==', 'class', 'motorway'],
paint: { 'line-color': '#e94560', 'line-width': 3 } },
{ id: 'place-label', type: 'symbol',
source: 'mapbox-streets', 'source-layer': 'place_label',
layout: {
'text-field': ['get', 'name'],
'text-font': ['Open Sans Regular'],
'text-size': ['interpolate', ['linear'], ['zoom'], 10, 10, 14, 14]
},
paint: { 'text-color': '#a0a0cc', 'text-halo-color': '#1a1a2e', 'text-halo-width': 1 } }
// add more layers to style buildings, parks, minor roads, etc.
]
}
});

Layer definitions reference source-layer names from the streets-v8 schema. You can also add a GeoJSON source alongside the vector tile source to overlay your own data:

map.on('load', () => {
map.addSource('my-data', { type: 'geojson', data: myGeoJson });
map.addLayer({ id: 'my-layer', type: 'fill', source: 'my-data', paint: { 'fill-color': '#ff7800' } });
});

Raster basemap tiles

MapLibre's style system manages all map sources and layers. Define a raster source in the style object with the Static Tiles API URL, then add a raster layer to display it.

const map = new maplibregl.Map({
container: 'map',
center: [-74.006, 40.7128],
zoom: 12,
style: {
version: 8,
sources: {
'mapbox-raster': {
type: 'raster',
tiles: [
'https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=YOUR_MAPBOX_ACCESS_TOKEN'
],
tileSize: 512,
maxzoom: 22
}
},
layers: [
{ id: 'basemap', type: 'raster', source: 'mapbox-raster' }
]
}
});

Swap streets-v12 for any classic Mapbox style or your own custom style ID from Mapbox Studio.

Satellite imagery

Use the Raster Tiles API to add the mapbox.satellite imagery tileset. These are 256px tiles served as JPEG.

style: {
version: 8,
sources: {
'mapbox-satellite': {
type: 'raster',
tiles: [
'https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.jpg90?access_token=YOUR_MAPBOX_ACCESS_TOKEN'
],
tileSize: 256,
maxzoom: 22
}
},
layers: [
{ id: 'satellite-layer', type: 'raster', source: 'mapbox-satellite' }
]
}

MapLibre handles GeoJSON data through named sources added to the map after the load event. This follows the same pattern as Mapbox GL JS — fetch the API responses, add them as geojson sources, and configure layers to render them.

map.on('load', async () => {
const origin = [-73.9855, 40.7580];
const destination = [-73.9969, 40.7061];

// Isochrones
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();

map.addSource('isochrone', { type: 'geojson', data: isoData });
map.addLayer({
id: 'isochrone-fill',
type: 'fill',
source: 'isochrone',
paint: {
// Data-driven color based on the 'contour' property of each polygon
'fill-color': [
'case',
['==', ['get', 'contour'], 5], '#1d4ed8',
['==', ['get', 'contour'], 10], '#3b82f6',
'#93c5fd'
],
'fill-opacity': 0.25
}
});

// Route
const routeRes = await fetch(
`https://api.mapbox.com/directions/v5/mapbox/driving/` +
`${origin.join(',')};${destination.join(',')}` +
`?geometries=geojson&access_token=YOUR_MAPBOX_ACCESS_TOKEN`
);
const routeData = await routeRes.json();

map.addSource('route', {
type: 'geojson',
data: { type: 'Feature', geometry: routeData.routes[0].geometry }
});
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
layout: { 'line-join': 'round', 'line-cap': 'round' },
paint: { 'line-color': '#1d4ed8', 'line-width': 4 }
});
});

Mapbox Search JS provides MapboxSearchBox, a web component that fires a retrieve event when a user selects a result. Position it as an absolutely-placed overlay on the map and handle the event to fly to the result and place a marker.

<head>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css" />
<script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.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%; }

#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 = new maplibregl.Map({
container: 'map',
center: [-74.006, 40.7128],
zoom: 12,
style: {
version: 8,
sources: {
'mapbox-raster': {
type: 'raster',
tiles: [
`https://api.mapbox.com/styles/v1/mapbox/streets-v12/tiles/512/{z}/{x}/{y}@2x?access_token=${ACCESS_TOKEN}`
],
tileSize: 512,
attribution: '© Mapbox © OpenStreetMap'
}
},
layers: [{ id: 'basemap', type: 'raster', source: 'mapbox-raster' }]
}
});

let resultMarker = null;

window.addEventListener('load', () => {
const searchBox = new MapboxSearchBox();
searchBox.accessToken = ACCESS_TOKEN;
searchBox.options = { types: 'address,poi', proximity: [-74.006, 40.7128] };
document.getElementById('search-container').appendChild(searchBox);

searchBox.addEventListener('retrieve', (event) => {
const feature = event.detail.features[0];
const [lng, lat] = feature.geometry.coordinates;

map.flyTo({ center: [lng, lat], zoom: 15 });

if (resultMarker) resultMarker.remove();
resultMarker = new maplibregl.Marker()
.setLngLat([lng, lat])
.setPopup(
new maplibregl.Popup().setText(
feature.properties.name || feature.properties.full_address
)
)
.addTo(map)
.togglePopup();
});
});
</script>
</body>

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.

ServicePricing details
Maps (raster and vector tiles)Maps pricing
Directions APINavigation pricing
Isochrone APINavigation pricing
Search / GeocodingSearch 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.

Was this page helpful?