@maptiler/sdk · GitHub · Docs
MapTiler SDK JS extends MapLibre GL JS with opinionated defaults for MapTiler Cloud. It is 100 % compatible with vanilla MapLibre sources and layers.
1. Why MapTiler SDK (not raw MapLibre)
Always import from @maptiler/sdk, never from maplibre-gl directly. The SDK re-exports everything from MapLibre and adds:
config.apiKey— single place for the API key; enables session-based billing (lower cost than per-request)MapStyleenum — always up-to-date map styles without hardcoded URLshelpers.*— one-liner polyline, polygon, point, heatmap, screenshot (with clustering, color ramps, GPX/KML)- Built-in geocoding, geolocation, elevation, static maps — no extra packages needed
terrain: true— 3D terrain in one constructor flagprojection: 'globe'— globe view withhaloandspaceatmosphere- Constructor-level controls —
navigationControl: true,geolocateControl: true, etc. - Full TypeScript types — extended beyond MapLibre with SDK-specific options
MapLibre plugins remain fully compatible — the SDK's Map inherits from MapLibre's Map.
2. Setup
Install
npm install @maptiler/sdk
CSS — must be imported separately:
import '@maptiler/sdk/dist/maptiler-sdk.css';
CDN (quick demos)
<script src="https://cdn.maptiler.com/maptiler-sdk-js/latest/maptiler-sdk.umd.min.js"></script>
<link href="https://cdn.maptiler.com/maptiler-sdk-js/latest/maptiler-sdk.css" rel="stylesheet" />
API Key
Do NOT hardcode a fake API key. Ask the user for theirs, or instruct them to get one at https://cloud.maptiler.com/account/keys/
Framework-specific env variable names:
- Vite:
VITE_MAPTILER_API_KEY - Next.js:
NEXT_PUBLIC_MAPTILER_API_KEY - CRA:
REACT_APP_MAPTILER_API_KEY
import * as maptilersdk from '@maptiler/sdk';
maptilersdk.config.apiKey = import.meta.env.VITE_MAPTILER_API_KEY;
Minimal Map
const map = new maptilersdk.Map({
container: 'map', // DOM element or ID
style: maptilersdk.MapStyle.STREETS, // enum — always latest
center: [14.4178, 50.1167], // [lng, lat] — NOT [lat, lng]!
zoom: 12,
});
Critical: The container element must have explicit dimensions (e.g.,
height: 100vh), otherwise the map is invisible.
3. Core Concepts
Map Constructor Options
const map = new maptilersdk.Map({
container: 'map',
style: maptilersdk.MapStyle.STREETS,
center: [lng, lat],
zoom: 12,
pitch: 0, // 0-85 degrees
bearing: 0, // rotation
projection: 'mercator', // or 'globe'
terrain: false, // true = 3D terrain
terrainExaggeration: 1,
hash: true, // sync viewport with URL hash
language: maptilersdk.Language.AUTO,
cooperativeGestures: true, // Cmd+scroll to zoom
geolocate: maptilersdk.GeolocationType.POINT, // auto-center on visitor IP
// Controls (boolean or position string):
navigationControl: true,
geolocateControl: true,
scaleControl: true,
terrainControl: false,
fullscreenControl: false,
projectionControl: false,
});
Map Styles
| Style | Variants |
|---|---|
MapStyle.STREETS |
.DARK, .LIGHT, .PASTEL |
MapStyle.SATELLITE |
— |
MapStyle.HYBRID |
— |
MapStyle.OUTDOOR |
.DARK |
MapStyle.TOPO |
.SHINY, .PASTEL, .TOPOGRAPHIQUE |
MapStyle.DATAVIZ |
.DARK, .LIGHT |
MapStyle.BASIC |
.DARK, .LIGHT |
MapStyle.OCEAN |
— |
Full list with all 16 styles and variants:
references/map-styles.md
Language
maptilersdk.config.primaryLanguage = maptilersdk.Language.ENGLISH;
map.setLanguage(maptilersdk.Language.FRENCH); // runtime change
Special: Language.AUTO (browser), Language.LOCAL, Language.VISITOR
4. Common Recipes
Markers and Popups
new maptilersdk.Marker({ color: '#FF0000' })
.setLngLat([14.4178, 50.1167])
.setPopup(new maptilersdk.Popup().setHTML('<h3>Prague</h3>'))
.addTo(map);
Forward Geocoding (search places)
const result = await maptilersdk.geocoding.forward('Prague', {
language: [maptilersdk.Language.ENGLISH],
limit: 5,
proximity: [14.4178, 50.1167],
});
const coords = result.features[0].geometry.coordinates; // [lng, lat]
Reverse Geocoding (coordinates to address)
const result = await maptilersdk.geocoding.reverse([14.4178, 50.1167]);
console.log(result.features[0].place_name);
Display GeoJSON with Helpers
// Polyline (also accepts GPX/KML URLs or MapTiler dataset UUIDs)
maptilersdk.helpers.addPolyline(map, {
data: routeGeoJSON,
lineColor: '#0066FF',
lineWidth: 4,
outline: true,
beforeId: 'waterway-label',
});
// Polygon
maptilersdk.helpers.addPolygon(map, {
data: zonesGeoJSON,
fillColor: '#FF0000',
fillOpacity: 0.5,
beforeId: 'waterway-label',
});
Clustered Points
maptilersdk.helpers.addPoint(map, {
data: pointsGeoJSON,
pointColor: '#FF0000',
pointRadius: 8,
cluster: true,
showLabel: true,
beforeId: 'waterway-label',
});
Heatmap
maptilersdk.helpers.addHeatmap(map, {
data: pointsGeoJSON,
colorRamp: maptilersdk.ColorRamp.TURBO,
property: 'magnitude',
radius: 25,
opacity: 0.8,
});
3D Terrain
const map = new maptilersdk.Map({
container: 'map',
style: maptilersdk.MapStyle.OUTDOOR,
terrain: true,
terrainExaggeration: 1.5,
terrainControl: true,
pitch: 60,
});
Globe Projection
const map = new maptilersdk.Map({
container: 'map',
style: maptilersdk.MapStyle.SATELLITE,
projection: 'globe',
halo: true,
space: true,
center: [0, 20],
zoom: 1.5,
});
Camera Animation
map.flyTo({
center: [14.4178, 50.1167],
zoom: 15,
pitch: 60,
bearing: 30,
duration: 3000,
essential: true,
});
Static Map Image URL
const url = maptilersdk.staticMaps.centered(
[14.4178, 50.1167], 12,
{ hiDPI: true, width: 800, height: 600, style: maptilersdk.MapStyle.OUTDOOR }
);
Full helpers API with all options:
references/helpers-api.mdWorking HTML examples (complete, copy-paste ready):
scripts/basic-map.html,scripts/geocoding-search.html,scripts/3d-terrain.html,scripts/globe-projection.html,scripts/clustering.html,scripts/heatmap.html,scripts/interactive-layers.html,scripts/helpers-dataviz.html
5. Framework Integration
React / Next.js
import { useEffect, useRef } from 'react';
import * as maptilersdk from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
maptilersdk.config.apiKey = import.meta.env.VITE_MAPTILER_API_KEY;
function MapComponent() {
const containerRef = useRef(null);
const mapRef = useRef(null);
useEffect(() => {
if (mapRef.current) return; // Strict Mode guard
mapRef.current = new maptilersdk.Map({
container: containerRef.current,
style: maptilersdk.MapStyle.STREETS,
center: [14.4178, 50.1167],
zoom: 12,
});
return () => { mapRef.current?.remove(); mapRef.current = null; };
}, []);
return <div ref={containerRef} style={{ width: '100%', height: '400px' }} />;
}
Next.js App Router: Add "use client"; at the top. Use NEXT_PUBLIC_MAPTILER_API_KEY. For SSR: dynamic(() => import('./Map'), { ssr: false }).
Vue 3
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as maptilersdk from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
maptilersdk.config.apiKey = import.meta.env.VITE_MAPTILER_API_KEY;
const container = ref(null);
let map = null;
onMounted(() => {
map = new maptilersdk.Map({
container: container.value,
style: maptilersdk.MapStyle.STREETS,
center: [14.4178, 50.1167], zoom: 12,
});
});
onUnmounted(() => { map?.remove(); map = null; });
</script>
<template><div ref="container" style="width:100%;height:400px" /></template>
Svelte, Angular, and advanced patterns:
references/frameworks.md
6. Cloud APIs
All APIs use config.apiKey automatically. No extra packages needed.
| Module | Purpose | Key Methods |
|---|---|---|
geocoding |
Place search | forward(), reverse(), batch() |
geolocation |
IP-based visitor location | info() → city, country, coords |
elevation |
Altitude lookup | at(), batch(), fromLineString() |
staticMaps |
Map image URLs | centered(), bounded(), automatic() |
coordinates |
CRS transform (10k+ EPSG) | search(), transform() |
data |
MapTiler Cloud datasets | get(uuid) |
math |
Geo calculations (local) | haversineDistanceWgs84() |
// IP geolocation
const loc = await maptilersdk.geolocation.info();
// Elevation
const point = await maptilersdk.elevation.at([14.4178, 50.1167]);
// Returns [lng, lat, elevationMeters]
SDK wrappers for all APIs:
references/cloud-apis.md· REST API docs: docs.maptiler.com/cloud/api
7. Critical Gotchas
| Problem | Fix |
|---|---|
| Map invisible | Container needs explicit height (height: 100vh or position: absolute; inset: 0) |
| Wrong location | Coordinates are [lng, lat] not [lat, lng] |
Layers vanish after setStyle() |
Re-add in map.once('styledata', ...) |
| Data covers labels | Use beforeId: 'waterway-label' |
| Slow with many points | Enable cluster: true in source or helpers |
| Memory leaks in SPA | Always call map.remove() on unmount |
Importing maplibre-gl separately |
Use @maptiler/sdk — it includes and extends MapLibre |
All 13 gotchas + reusable patterns:
references/patterns-gotchas.md
8. Ecosystem Packages
| Package | Purpose |
|---|---|
@maptiler/geocoding-control |
Search bar UI for address lookup |
@maptiler/weather |
Wind, temperature, pressure, radar layers (60fps animation) |
@maptiler/3d |
glTF/GLB 3D model placement on map |
@maptiler/elevation-profile |
Elevation profile chart for routes |
@maptiler/marker-layout |
Non-colliding DOM marker overlays |
@maptiler/ar |
Augmented reality 3D terrain view |
@maptiler/client |
Headless API client (Node.js / browser, no map needed) |
Detailed usage for each module:
references/ecosystem.md
9. Resources
- SDK Documentation
- SDK Examples
- MapTiler Cloud Console
- GitHub — SDK JS
- NPM — @maptiler/sdk
- Framework starters: React · Vue · Svelte · Angular · Next.js
Reference Files
references/helpers-api.md— Complete helpers API with option tables and typesreferences/patterns-gotchas.md— 13 gotchas + 13 reusable code patternsreferences/map-styles.md— All MapStyle variants and Language enum valuesreferences/events.md— Lifecycle, camera, interaction, data eventsreferences/cloud-apis.md— MapTiler Cloud REST API endpointsreferences/frameworks.md— React, Vue, Svelte, Angular, Next.js patternsreferences/ecosystem.md— Weather, 3D, AR, elevation-profile, geocoding-control modules