From Mapbox
MapLibre GL JS is a fork of Mapbox GL JS. The map you have (markers, popups, sources, layers, map.on) keeps working. What changes is the token, the style URL, and the geocoding and directions hosts.
This is the shortest of the four guides. Stay on Mapbox if you need coverage outside Canada, Mapbox Search Box, the Matrix API, or a Studio style you are not ready to leave. unmap has its own styles and a theme builder; it does not load a mapbox://styles/... document.
Coming from a <script> tag? unmap loads from one too, no build step required: see the Quickstart.
The map
A Mapbox map is a token plus a style URL. An unmap map is a key plus a style name. The constructor looks the same because it is the same constructor, one fork later.
mapboxgl.accessToken = "pk.eyJ...";
const map = new mapboxgl.Map({
container: "map",
center: [-114.0719, 51.0447],
zoom: 11,
});import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({
key: "um_live_...",
container: "map",
center: [-114.0719, 51.0447],
zoom: 11,
});import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({
key: "um_live_...",
container: "map",
center: [-114.0719, 51.0447],
zoom: 11,
});Coordinates stay [lng, lat]. You do not flip them. unmap.map is the MapLibre GL map, so flyTo, addSource, addLayer, and on("click") are unchanged.
streets becomes style: "base". outdoors becomes outdoor. light / dark are a mode, not a style: style: "base", mode: "dark". There is no Standard style and no 3D landmarks. The twelve styles are on Maps API.
If you already import maplibre-gl and only wanted Mapbox tiles, skip the SDK and pass the style URL into the MapLibre constructor you have. Calling the API directly shows that page.
Markers and popups
The Mapbox Marker and Popup constructors are the MapLibre ones. Swap the import and keep the chain.
new mapboxgl.Marker()
.setLngLat([-114.0719, 51.0447])
.setPopup(new mapboxgl.Popup().setHTML("<p>Calgary Tower</p>"))
.addTo(map);import { maplibregl } from "@unmap/sdk";
new maplibregl.Marker()
.setLngLat([-114.0719, 51.0447])
.setPopup(new maplibregl.Popup().setHTML("<p>Calgary Tower</p>"))
.addTo(unmap.map!);import { Unmap, maplibregl } from "@unmap/sdk";
const unmap = new Unmap({
key: "um_live_...",
container: "map",
center: [-114.0719, 51.0447],
zoom: 11,
});
const [place] = await unmap.geocoder.search("Calgary Tower");
new maplibregl.Marker({ color: "#FF3E9A" })
.setLngLat([place.lng, place.lat])
.setPopup(new maplibregl.Popup().setText(place.name))
.addTo(unmap.map!);mapboxgl.NavigationControl is already on the map (controls: false takes it off). GeolocateControl and ScaleControl come from the same maplibregl export. Clustering is still a GeoJSON source with cluster: true; that is MapLibre, not a Mapbox feature you are leaving behind.
Geocoding
Mapbox Geocoding API v6 (and the mapbox-gl-geocoder plugin) become unmap.geocoder. Forward, reverse, and autocomplete are four endpoints with one result shape. There is no Search Box UI to drop in: you render the list.
const url = new URL("https://api.mapbox.com/search/geocode/v6/forward");
url.searchParams.set("q", "Calgary Tower");
url.searchParams.set("access_token", mapboxgl.accessToken);
const data = await (await fetch(url)).json();
const [lng, lat] = data.features[0].geometry.coordinates;
map.setCenter([lng, lat]);const results = await unmap.geocoder.search("Calgary Tower");
const [first] = results;
if (first) unmap.map!.setCenter([first.lng, first.lat]);const hints = await unmap.geocoder.autocomplete("calgary tow", { limit: 5 });
const here = await unmap.geocoder.reverse(-114.07, 51.05);import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({ key: "um_live_..." });
const results = await unmap.geocoder.search("Calgary Tower", { limit: 3 });Mapbox returns a GeoJSON FeatureCollection. unmap returns a JSON array of { id, name, layer, lng, lat }. There is no mapbox_id, no Search Box suggest, and no persistent place data. Category search is geocoder.nearby("pharmacy", { near: [-114.07, 51.05] }), not a Mapbox category filter on forward geocoding. The Geocoding API is the contract.
Permanent geocodes and the Mapbox terms about storing coordinates do not apply. Cache what you like; the Plans page is the limit that does.
Directions
Mapbox Directions v5 becomes router.route. The geometry is already a GeoJSON LineString, so the layer you drew for Mapbox keeps working.
const origin = [-114.0719, 51.0447];
const dest = [-113.9871, 51.0899];
const url = new URL(`https://api.mapbox.com/directions/v5/mapbox/driving/${origin.join(",")};${dest.join(",")}`);
url.searchParams.set("geometries", "geojson");
url.searchParams.set("access_token", mapboxgl.accessToken);
const data = await (await fetch(url)).json();
const line = data.routes[0].geometry;const route = await unmap.router.route([-114.0719, 51.0447], [-113.9871, 51.0899], {
mode: "auto",
});
const line = route.geometry;import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({
key: "um_live_...",
container: "map",
center: [-114.03, 51.07],
zoom: 11,
});
const route = await unmap.router.route([-114.0719, 51.0447], [-113.9871, 51.0899], { mode: "auto" });
unmap.map!.on("load", () => {
unmap.map!.addSource("route", {
type: "geojson",
data: { type: "Feature", properties: {}, geometry: route.geometry },
});
unmap.map!.addLayer({
id: "route-line",
type: "line",
source: "route",
layout: { "line-cap": "round", "line-join": "round" },
paint: { "line-color": "#FF3E9A", "line-width": 3 },
});
});mapbox/driving is auto. mapbox/walking is pedestrian. mapbox/cycling is bicycle. There is no driving-traffic profile and no congestion annotations. There are no waypoints. Isochrone is first-class:
const bands = await unmap.router.isochrone([-114.07, 51.05], { minutes: [10, 20] });The Mapbox Isochrone, Matrix, and Optimization APIs have no unmap twin except isochrone. A many-to-many matrix is work you do with repeated route calls, and you will feel the meter. The Routing API documents the rest, including truck.
What has no equivalent
- Coverage outside Canada. A style still loads; the tiles are empty past the border. A route that leaves the country is a 400.
- Mapbox Studio styles. Pass a theme code from /create, or pick one of the twelve styles. You cannot point MapLibre at a
mapbox://style and an unmap key at once. - Search Box, Matrix, Optimization, Map Matching.
- Mapbox Standard, 3D landmarks, and indoor maps.
- The Mapbox GL draw, geocoder, and directions plugins. Use MapLibre Draw, your own search UI, and
unmap.router.
Checklist
-
pk.eyJ...replaced withum_live_.../um_test_... - Style URL replaced with a style name (
base,outdoor, …) or ahttps://api.unmap.dev/styles/...URL -
mapbox-glimport swapped for@unmap/sdk(ormaplibre-glplus the style URL) - Geocoding host moved to
unmap.geocoder; FeatureCollection handling rewritten as an array - Directions host moved to
unmap.router - Studio-only layers, Search Box, and Matrix either dropped or left on Mapbox
- Origin configured for production traffic (Plans & Limits)
The Quickstart is the same map built from scratch. If the renderer was already MapLibre, Calling the API directly is the shorter path.