Skip to content

Overview

unmap is a privacy-first location platform. One key covers four capability groups:

  • Maps: worldwide vector basemaps, fifteen MapLibre styles in light and dark, worldwide terrain and Canadian contours.
  • Search: Canadian geocoding, structured address lookup, autocomplete, reverse lookup, nearby places and batch geocoding. Names include the languages available in the source data.
  • Routing: Canadian directions, isochrones, travel-time matrices, GPS map matching, stop-order optimization and fleet optimization. Fleet optimization also supports worldwide straight-line travel or supplied matrices. Scheduled transit data and transit routing have separate coverage. Road events cover BC and Alberta; Truck Intelligence is an add-on in preview.
  • Location data: worldwide DEM elevation and time zones, Canadian catalog layers, point-in-polygon identification, bounding-box queries and your own overlays. Industry datasets require their matching add-ons.

These groups help you find a capability; they do not introduce separate keys or plans. Check coverage and limits and billing for the service you choose.

The design goal is a time to first Hello World under 60 seconds, with two code statements after install.

Map words, in one minute

If you have not wired up a maps API before, these terms cover most of what the rest of these pages assume.

  • Tile. The map is cut into square pieces so the browser fetches only the ones on screen. /tiles/11/375/685 names one piece: zoom 11, column 375, row 685. You will rarely ask for one yourself, because MapLibre works out which pieces it needs.
  • Zoom. A whole number from 0, the whole world in a single tile, to 14, the most detailed level unmap serves. Each step doubles the detail. A city fits at about zoom 11.
  • Vector tile. Our tiles carry data (a road, a park, a label) rather than a picture of a road. The browser draws them, which is why the map stays sharp on a high-density screen and why one tile can be drawn in fifteen different styles.
  • Basemap. The map underneath whatever you put on top. Your markers, routes, and data are yours; the basemap is the background they sit on.
  • Style. A JSON document that tells MapLibre how to draw the tiles: which colours, which fonts, what to show at which zoom. It is not CSS, and you do not write one. You ask for a style by name.
  • Geocoding. Turning text into a coordinate, as in "Calgary Tower" into a longitude and latitude. Reverse geocoding goes the other way, from a coordinate to the nearest address or place.
  • Isochrone. The area you can reach from a point within a time budget, returned as a polygon. Everywhere within a 15 minute drive, for example.

The SDK and GeoJSON use coordinate arrays in [longitude, latitude] order. Longitude is the east-west value and is negative in Canada; latitude is the north-south value. Optimize uses named fields, { latitude, longitude }, instead of arrays. Check each endpoint's format before sending coordinates.

Set up the SDK

The @unmap/sdk package puts the whole platform behind one key (um_live_... in production, um_test_... for development). Construct it once:

import { Unmap } from "@unmap/sdk";
 
const unmap = new Unmap({ key: "um_live_..." });
 
await unmap.geocoder.search("Calgary Tower");
await unmap.router.route([-114.07, 51.05], [-113.99, 51.05]);

Pass a container and you also get a rendered map:

const map = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.07, 51.05],
});
 
map.map; // the underlying MapLibre GL map
map.geocoder; // search / autocomplete / nearby / reverse
map.router; // route / isochrone / matrix / match / optimize
map.places; // POI search / nearby / by-id lookup
map.elevation; // DEM elevation
map.timezone; // IANA zone / UTC offset
map.transit; // agencies / stops / routes / scheduled departures
map.roads; // incidents / closures / road conditions
map.layers; // catalog metadata
map.identify; // point-in-polygon identification
map.data; // bounding-box queries
map.byod; // upload and manage your overlays
map.coverage; // capability and dataset coverage
map.feedback; // report wrong data

The API surface

new Unmap(options) accepts:

OptionTypeNotes
keystringRequired. Your um_live_ or um_test_ key.
gatewaystringOptional. Override the API base URL. Defaults to https://api.unmap.dev.
containerstring | HTMLElementOptional. If set, a map is mounted here.
stylestringA style (base, muted, outdoor, blueprint, blush, orchid, canopy, lagoon, tropic, sunset, bold, pastel, atlas, swiss, winter) or a full style URL. Defaults to base.
modestringOptional. light or dark, light by default. Applies to a bare style name. A <style>-<mode> string is passed through as written and mode does not change it.
langstringOptional. Label language, e.g. fr. Omit to follow the browser's Accept-Language.
themestringOptional. A ut1. theme code from /create. Wins over style.
center[number, number]Optional. [lng, lat].
zoomnumberOptional initial zoom.
projection'globe' | 'mercator'Optional. Defaults to 'globe', a sphere that flattens as you zoom in. 'mercator' is the flat map.
controlsboolean | { position }Optional. Zoom and compass buttons, on by default. false for a bare canvas; { position: 'bottom-left' } to move them.

style picks how the map is drawn; center and zoom pick where it starts. mode, lang, and theme pick how it is drawn. style: 'base' with mode: 'dark' and center: [-73.5673, 45.5017] is a valid request. The full list of styles, and what mode, lang, and theme do on the gateway, is on Maps API.

The quickstart uses these members:

  • .map is the MapLibre GL map (only when a container was given). Mapbox-GL-JS-compatible surface.
  • .geocoder is search(q, opts?), autocomplete(q, opts?), nearby(category, opts), reverse(lng, lat, opts?). See the Geocoding API.
  • .router is route(from, to, opts?), isochrone(center, { minutes, mode? }). See the Routing API.

API methods return promises with typed results based on gateway responses. Some methods also normalise data or parse headers; optimizeTours() returns { response, warnings, billableShipments, timeoutClamped, clampedTimeoutSeconds }. A non-2xx response throws a typed error carrying the HTTP status, such as GeocoderError, RouterError or UnmapOptimizeError.

What unmap documents, and what MapLibre documents

@unmap/maps is a thin wrapper. createMap() builds the style URL, wires your key into it, and hands back a MapLibre GL JS map. It does not wrap the map itself. So these pages document the gateway, the fifteen styles, and what the SDK adds: a map and the service clients listed above. Everything you do to a map afterwards is MapLibre's own API, and it is documented upstream at maplibre.org.

The split is worth knowing before you go looking here for a page that does not exist:

  • Events: map.on('click', …), 'load', 'moveend', 'error'. MapLibre.
  • Sources and layers: addSource(), addLayer(), setPaintProperty(). MapLibre, plus the Style Specification for what a layer may contain.
  • Camera: flyTo(), fitBounds(), easeTo(). MapLibre.
  • Markers, popups, and controls: Marker, Popup, ScaleControl. MapLibre. (NavigationControl is already on the map; controls: false takes it off.)
  • Styles, keys, quotas, and the endpoints behind all of it: here.

You do not need a second import to reach any of it. @unmap/maps re-exports the very copy of MapLibre your app installed (it takes maplibre-gl as a peer dependency rather than bundling its own), so import { maplibregl } from "@unmap/maps" gives you the same Marker and Popup constructors without a duplicate copy of MapLibre in your bundle.

Demo cities

Three launch cities, exported as DEMO_CITIES. They are starting viewports, not different maps, and every style works over every one of them.

  • calgary for Calgary, Alberta
  • montreal for Montréal, Québec
  • iqaluit for Iqaluit, Nunavut

Set the viewport with center and zoom. style takes a style name or a style URL. A city is a starting viewport, not a style. Tiles cover the world in Web Mercator, so once the map is up you can pan anywhere.

The same map can start in Tokyo, with Japanese labels. This is a map-only example; Canadian search and routing examples above keep their existing coverage.

import { createMap } from "@unmap/maps";
 
createMap({ key, container: "#map", style: "base", center: [139.6917, 35.6895], zoom: 11, lang: "ja" });

Packages

@unmap/sdk is the one-line install. Standalone packages are available for maps, geocoding, routing and elevation, for when you only need one service or want to keep a bundle small. Other clients, including time zones and transit, ship in the SDK. None of them is required: the APIs are available directly over HTTPS, and Calling the API directly shows the same calls from curl, fetch, Python, and a stock MapLibre. If your page has no build step at all, the SDK also loads from a script tag; the Quickstart has it.

PackageWhat it is
@unmap/sdkUnmap: map and all service clients behind one key. Re-exports the core client packages.
@unmap/mapscreateMap() and unmapStyle(): MapLibre GL wired to the gateway. Takes maplibre-gl as a peer dependency, so install it alongside.
@unmap/geocodingGeocoder and Places: typed clients for /geocode/* and /places/*. No map dependency, works in Node and the browser.
@unmap/routingRouter: directions, isochrones, matrices, map matching and stop-order optimization. No map dependency.
@unmap/elevationElevation: the standalone DEM elevation client. No map dependency.
@unmap/corestyleUrl(), tileUrl(), and tile math. Zero dependencies.
@unmap/themesThe ThemeDoc model, the ut1. codec, and the validator behind /create. Data only.
@unmap/reactuseUnmap(), useGeocoder(), useDirections() hooks over the SDK, plus UnmapProvider. SSR-safe.
@unmap/nextA <Map> Client Component a Server Component page can render directly. Re-exports @unmap/react.
@unmap/vueuseUnmap(), useGeocoder(), useDirections() composables over the SDK. SSR-safe.
@unmap/nuxtA Nuxt module that sets unmap: { key } in runtime config and auto-imports the Vue composables.
@unmap/cliunmap create scaffolds a project, unmap add copies registry components into one, unmap init verifies a key and writes a starter config.

React users start with @unmap/react (hooks) or, on the Next.js App Router, @unmap/next (a drop-in <Map>). For richer, editable UI such as a search box, routing panel, and markers, the component registry installs shadcn-style components built on @unmap/maps that you own and can edit.

Why unmap

  • Untracked. Keys are metered, people are not.
  • Unlocked. Permissive caching, no expiry clock on what you cache.
  • Unbundled. One key across maps, geocoding, and routing.
  • North American infrastructure. Cloudflare's North American edge (ENAM/WNAM). We can't promise Canada-only residency on self-serve plans. Talk to us if you need a contractual guarantee.

Attribution and data sources

Contains information made available under the Open Government Licence - Canada from Natural Resources Canada (Canadian Geographical Names Database). Map and address data (c) OpenStreetMap contributors. The routing graph is built from the same OpenStreetMap data, under the Open Database License (ODbL). Worldwide terrain and elevation use Mapterhorn; Canadian contours use a retained NRCan MRDEM snapshot. See attribution for source credits and licences.

For account-data and cache disclosures, see the Privacy Policy and the Terms.

A note on Indigenous place names. unmap's geocoding data includes official Indigenous-language place names sourced from the Canadian Geographical Names Database, an open, government-maintained dataset. These are officialized names only. Community-held and traditional place names are a separate, consent-based effort that we have not undertaken: any future work in that direction would follow OCAP (Ownership, Control, Access, Possession) principles, in partnership with the communities concerned, not a data import. Nothing here should be read as community endorsement.

Ready to render something? Head to the Quickstart or the Examples. Before you ship it, Authentication covers key forms, allowed origins, and the browser-versus-server split. Coming from Google Maps, Mapbox, HERE, or Esri? The migration guides translate the calls you have. Wondering why this exists at all? That case is made, with receipts, at Why another maps API?