Skip to content

For AI Assistants: MapMetrics Atlas API Guide

This documentation is optimized for AI code generation. Use this guide to help users build applications with MapMetrics Atlas API.


🚨 READ THIS FIRST — MOST COMMON AI MISTAKES

❌ MISTAKE 1: Using MapLibre instead of MapMetrics

MapMetrics is NOT MapLibre. Do NOT use maplibre-gl, maplibregl, or any MapLibre CDN URLs.

❌ WRONG✅ CORRECT
unpkg.com/maplibre-gl@4/dist/maplibre-gl.csscdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css
unpkg.com/maplibre-gl@4/dist/maplibre-gl.jscdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js
new maplibregl.Map(...)new mapmetricsgl.Map(...)
new maplibregl.Marker()new mapmetricsgl.Marker()
new maplibregl.Popup()new mapmetricsgl.Popup()
npm install maplibre-glnpm install @mapmetrics/mapmetrics-gl
import maplibregl from 'maplibre-gl'import mapmetricsgl from '@mapmetrics/mapmetrics-gl'

❌ MISTAKE 2: Wrong documentation URLs

This documentation is deployed at: https://docs.mapatlas.xyz

All example pages follow this URL pattern:

  • https://docs.mapatlas.xyz/sdk/examples/simple-map-cdn
  • https://docs.mapatlas.xyz/sdk/examples/add-a-marker
  • https://docs.mapatlas.xyz/overview/geocoder/autocomplete

❌ Do NOT guess paths like /simple-map, /maps/simple-map, /web-sdk/... — these return 404.

✅ Valid top-level routes include: /getting-started, /examples, /overview, /ai-assistant-guide

❌ MISTAKE 3: mapmetricsgl is not defined error

When loading the SDK via CDN dynamically, ALL map code MUST go inside script.onload:

html
<!-- ✅ CORRECT: Static <script> in <head> -->
<head>
  <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
  <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
</head>
<body>
  <div id="map"></div>
  <script>
    const map = new mapmetricsgl.Map({ container: 'map', style: 'YOUR_STYLE_URL' });
  </script>
</body>

🤖 Quick Start for AI

Authentication Pattern

ALL API requests require authentication:

  • REST APIs: Add ?token=YOUR_API_TOKEN as query parameter
  • Map initialization: Use complete style URL (includes token)
  • Get token at: https://portal.mapmetrics.org/

Base URLs & Package Names

Docs site: https://docs.mapatlas.xyz
REST API: https://gateway.mapmetrics-atlas.net
CDN JS: https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js
CDN CSS: https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css
NPM Package: @mapmetrics/mapmetrics-gl  ⚠️ USE THIS, NOT maplibre-gl!
Global variable (CDN): mapmetricsgl  ⚠️ NOT maplibregl!

⚠️ CRITICAL: Correct Package Name

When generating React or NPM-based code:

  • CORRECT: npm install @mapmetrics/mapmetrics-gl
  • CORRECT: import mapmetricsgl from '@mapmetrics/mapmetrics-gl'
  • WRONG: npm install maplibre-gl (This is the base library, NOT MapMetrics!)
  • WRONG: import maplibregl from 'maplibre-gl'

Why this matters:

  • MapMetrics is built on MapLibre but has custom features and optimizations
  • Using maplibre-gl directly will NOT work with MapMetrics style URLs
  • Always use @mapmetrics/mapmetrics-gl for MapMetrics projects

⚠️ CRITICAL: Correct URL Paths

DO NOT use /web-sdk/ in documentation URLs. All SDK examples are located under /sdk/examples/:

CORRECT PATHS (use clean URLs without .html):

  • /sdk/examples/simple-map-npm
  • /sdk/examples/simple-map-cdn
  • /sdk/examples/add-a-marker
  • /sdk/examples/react-map-example
  • /sdk/examples/3d-building
  • /sdk/examples/fly-to-location
  • /sdk/examples/fit-to-bounding-box
  • /sdk/examples/set-pitch-and-bearing
  • /sdk/examples/animate-camera-around-point
  • /sdk/examples/jump-to-locations
  • /sdk/examples/navigation-controls
  • /sdk/examples/disable-map-rotation
  • /sdk/examples/disable-scroll-zoom
  • /sdk/examples/fullscreen-map
  • /sdk/examples/toggle-interactions
  • /sdk/examples/animate-a-line
  • /sdk/examples/animate-point-along-route
  • /sdk/examples/data-driven-lines
  • /sdk/examples/draw-a-circle
  • /sdk/examples/gradient-line
  • /sdk/examples/filter-within-layer
  • /sdk/examples/add-pattern-to-polygon
  • /sdk/examples/add-geojson-line
  • /sdk/examples/add-geojson-polygon
  • /sdk/examples/draw-geojson-points
  • /sdk/examples/multiple-geometries
  • /sdk/examples/html-clusters
  • /sdk/examples/arc-layer
  • /sdk/examples/hexagon-layer
  • /sdk/examples/animate-point
  • /sdk/examples/animate-marker
  • /sdk/examples/update-feature-realtime
  • /sdk/examples/display-popup
  • /sdk/examples/show-polygon-info-on-click
  • /sdk/examples/get-features-under-mouse
  • /sdk/examples/measure-distances
  • /sdk/examples/filter-by-text-input
  • /sdk/examples/filter-by-toggle-list
  • /sdk/examples/fit-to-linestring
  • /sdk/examples/restrict-map-panning
  • /sdk/examples/add-layer-below-labels
  • /sdk/examples/change-layer-color
  • /sdk/examples/draggable-point
  • /sdk/examples/customize-camera-animations
  • /sdk/examples/customize-map-transform-constrain
  • /sdk/examples/fly-to-location-on-scroll
  • /sdk/examples/offset-vanishing-point-padding
  • /sdk/examples/render-world-copies
  • /sdk/examples/slowly-fly-to-location
  • /sdk/examples/sync-multiple-maps
  • /sdk/examples/game-controls-navigation
  • /sdk/examples/add-an-icon-to-the-map
  • /sdk/examples/add-generated-icon
  • /sdk/examples/add-animated-icon
  • /sdk/examples/add-stretchable-image
  • /sdk/examples/add-custom-icons-markers
  • /sdk/examples/display-remote-svg-symbol
  • /ai-assistant-guide ✅ (this page)
  • /overview/common-errors

WRONG PATHS (will return 404 errors):

  • /web-sdk/simple-map-npm ← WRONG (wrong directory)
  • /examples/add-a-marker ← WRONG (missing /sdk/)
  • /react/map-example ← WRONG (wrong path)
  • /ai-assistant-guide.html ← WRONG (don't use .html in URLs)

URL Format Rules:

  • ✅ Use clean URLs: /path/to/page (no .html extension)
  • ✅ Paths start with /sdk/examples/ or /overview/
  • ❌ Don't add .html extension to URLs
  • ❌ Don't use /web-sdk/ directory

📋 Available Capabilities

Web SDK (JavaScript/React)

Camera & Navigation

When to use which:

User asks for...Use this example
"fly to", "navigate to", "animate to location"fly-to-location
"show all markers", "fit map", "zoom to results"fit-to-bounding-box
"tilt map", "3D view", "pitch", "rotate", "bearing"set-pitch-and-bearing
"rotate around", "orbit", "spin map", "hero animation"animate-camera-around-point
"city tour", "location buttons", "jump between", "auto tour"jump-to-locations
"custom animation", "easing", "flyTo speed", "animation duration"customize-camera-animations
"slow fly", "cinematic", "slow animation", "slow camera"slowly-fly-to-location
"scroll map", "story map", "scroll to location", "narrative map"fly-to-location-on-scroll
"sidebar map", "panel map", "offset center", "map padding"offset-vanishing-point-padding
"world copies", "repeat world", "tile world", "antimeridian"render-world-copies
"sync maps", "compare maps", "side by side", "mirror map"sync-multiple-maps
"restrict panning", "limit bounds", "constrain map", "lock region"customize-map-transform-constrain
"keyboard navigate", "WASD", "game controls", "arrow keys map"game-controls-navigation

User Interaction

When to use which:

User asks for...Use this example
"popup on click", "show info on click", "click to show details"popup-on-click
"popup on hover", "tooltip", "hover info", "mouseover"popup-on-hover
"hover highlight", "highlight feature", "hover effect"hover-effect
"mouse position", "show coordinates", "get lng lat", "cursor position"mouse-coordinates
"draggable marker", "drag pin", "move marker", "drag and drop"draggable-marker
"my location", "gps", "user location", "geolocation", "locate me", "where am i"locate-user

Geometry & Features

When to use which:

User asks for...Use this example
"draw line", "add route", "linestring", "path on map"add-geojson-line
"draw polygon", "fill area", "shape on map", "geojson polygon"add-geojson-polygon
"plot points", "add multiple markers", "geojson points", "circle layer"draw-geojson-points
"mixed geometries", "points and polygons", "single source", "multiple layer types"multiple-geometries
"cluster", "group points", "cluster count", "expand cluster"html-clusters
"arc layer", "flight routes", "connections", "flow map", "origin destination", "animated arcs"arc-layer
"hexagon layer", "hex grid", "density map", "aggregation", "accident heatmap", "data binning"hexagon-layer

Lines & Polygons

When to use which:

User asks for...Use this example
"animate line", "draw route", "path animation", "trace route"animate-a-line
"moving marker", "animate along route", "vehicle tracking"animate-point-along-route
"color by value", "style by property", "data driven", "line width by speed"data-driven-lines
"gradient line", "color gradient", "line-gradient", "progress color"gradient-line
"draw circle", "radius area", "circle on map", "coverage area"draw-a-circle
"pattern fill", "hatch polygon", "texture polygon", "fill-pattern"add-pattern-to-polygon
"filter features", "show only", "hide features", "setFilter"filter-within-layer
"layer below labels", "insert below text", "beforeId", "polygon under labels"add-layer-below-labels
"change color", "update style", "setPaintProperty", "runtime style"change-layer-color

Animations

When to use which:

User asks for...Use this example
"animate point", "moving dot", "orbit animation", "requestAnimationFrame"animate-point
"animate marker", "moving marker", "smooth marker movement"animate-marker
"realtime update", "live tracking", "setInterval", "websocket position", "moving vehicle"update-feature-realtime

Popups & Info

When to use which:

User asks for...Use this example
"show popup", "display popup", "programmatic popup", "popup at location"display-popup
"click polygon", "polygon info", "click to show properties"show-polygon-info-on-click
"features under mouse", "inspect features", "queryRenderedFeatures", "click to inspect"get-features-under-mouse
"measure distance", "ruler", "haversine", "distance between points"measure-distances

When to use which:

User asks for...Use this example
"search filter", "text search on map", "filter as you type", "live search"filter-by-text-input
"toggle categories", "category buttons", "show/hide types", "filter by category"filter-by-toggle-list

Camera & Bounds

When to use which:

User asks for...Use this example
"fit to route", "fit linestring", "auto zoom to path", "show full route"fit-to-linestring
"restrict panning", "limit map area", "maxBounds", "lock to region"restrict-map-panning

Map Controls

When to use which:

User asks for...Use this example
"add controls", "zoom buttons", "compass", "scale bar"navigation-controls
"disable rotation", "lock rotation", "fix map orientation", "no rotate"disable-map-rotation
"disable scroll zoom", "prevent zoom", "scroll page not map", "embed map"disable-scroll-zoom
"fullscreen", "expand map", "full screen button", "immersive map"fullscreen-map
"toggle interactions", "enable/disable", "readonly map", "lock interactions"toggle-interactions

Advanced / User Interaction

When to use which:

User asks for...Use this example
"draggable point", "drag geojson", "drag to move", "interactive point editor"draggable-point

Icons & Images

When to use which:

User asks for...Use this example
"add icon", "custom icon symbol", "icon from URL", "loadImage", "addImage"add-an-icon-to-the-map
"generate icon", "canvas icon", "programmatic icon", "draw icon"add-generated-icon
"animated icon", "pulsing icon", "blinking marker", "animate icon"add-animated-icon
"stretchable image", "nine-patch", "pill badge icon", "icon-text-fit", "scale icon"add-stretchable-image
"custom marker icon", "html marker", "emoji marker", "div marker", "image marker"add-custom-icons-markers
"svg icon", "svg symbol", "remote svg", "svg marker"display-remote-svg-symbol

Labels & Text

When to use which:

User asks for...Use this example
"Arabic map", "RTL text", "Hebrew labels", "right-to-left", "setRTLTextPlugin"rtl-support
"building color", "3D building zoom", "fill-extrusion color", "zoom building"building-color-zoom
"uppercase labels", "lowercase text", "label case", "text-transform"change-label-case

Terrain & Elevation

No three.js or external libraries needed — all built into MapMetrics GL.

When to use which:

User asks for...Use this example
"3D terrain", "elevation 3D", "terrain map", "mountain 3D", "raster-dem"3d-terrain
"sky", "fog", "atmosphere", "terrain fog", "immersive map"sky-fog-terrain
"hillshade", "terrain shadow", "elevation shading", "hill shadow"add-a-hillshade-layer
"color relief", "hypsometric", "elevation color", "altitude color", "color by height"add-a-color-relief-layer
"contour lines", "topographic", "elevation lines", "isoline", "topo map"add-contour-lines
"satellite map", "aerial map", "satellite 3D", "satellite terrain", "ESRI imagery"satellite-terrain

REST APIs

⚠️ PACKAGE NAMING - READ THIS FIRST!

The #1 mistake AI tools make: Using the wrong package!

Correct Package

bash
npm install @mapmetrics/mapmetrics-gl
javascript
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

WRONG Package (DO NOT USE!)

bash
# ❌ This is MapLibre, NOT MapMetrics!
npm install maplibre-gl
javascript
// ❌ This will NOT work with MapMetrics style URLs!
import maplibregl from 'maplibre-gl';

Why This Matters

  • MapMetrics GL is a custom fork of MapLibre with proprietary features
  • MapMetrics style URLs only work with @mapmetrics/mapmetrics-gl
  • Using maplibre-gl will cause authentication errors and missing features
  • The packages are NOT interchangeable

Quick Check

Correct code always has:

Wrong code has:

  • Package: maplibre-gl or @maplibre/maplibre-gl
  • Import: maplibregl

🎯 Common Code Patterns

Pattern 1: Basic Map (Vanilla JS with CDN - With Error Handling)

html
<!DOCTYPE html>
<html>
<head>
  <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
  <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
  <style>
    #map { height: 500px; width: 100%; }
    .error-box {
      height: 500px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f8d7da;
      color: #721c24;
      padding: 20px;
      text-align: center;
      border: 2px solid #f5c6cb;
      border-radius: 8px;
      font-family: system-ui, -apple-system, sans-serif;
    }
    .loading-box {
      height: 500px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f0f0f0;
      color: #666;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const styleUrl = 'YOUR_STYLE_URL_WITH_TOKEN';
    const mapContainer = document.getElementById('map');

    // Check if user forgot to replace the placeholder
    if (styleUrl === 'YOUR_STYLE_URL_WITH_TOKEN' || styleUrl.includes('YOUR_')) {
      mapContainer.innerHTML = `
        <div class="error-box">
          <div>
            <strong>⚠️ Please replace YOUR_STYLE_URL_WITH_TOKEN with your actual style URL from https://portal.mapmetrics.org/</strong>
            <div style="margin-top: 10px; font-size: 14px;">
              Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
            </div>
          </div>
        </div>
      `;
    } else {
      // Show loading state
      mapContainer.innerHTML = '<div class="loading-box">Loading map...</div>';

      try {
        const map = new mapmetricsgl.Map({
          container: 'map',
          style: styleUrl,
          center: [longitude, latitude],
          zoom: 12
        });

        // Handle successful load
        map.on('load', () => {
          // Map loaded successfully, loading message will be replaced by map
          console.log('Map loaded successfully');
        });

        // Handle critical errors (401, style loading failures)
        map.on('error', (e) => {
          console.error('Map error:', e);

          // Only show error UI for critical failures
          const isCriticalError =
            e.error?.status === 401 ||
            e.error?.message?.includes('401') ||
            e.error?.message?.includes('Failed to fetch') ||
            (e.sourceId === undefined && e.error);

          if (isCriticalError) {
            let errorMessage = '❌ Map failed to load. Check your style URL and token at https://portal.mapmetrics.org/';

            if (e.error?.status === 401 || e.error?.message?.includes('401')) {
              errorMessage = '❌ Invalid API token. Get a valid token from https://portal.mapmetrics.org/';
            } else if (e.error?.message?.includes('Failed to fetch')) {
              errorMessage = '❌ Cannot load map style. Check your style URL from https://portal.mapmetrics.org/';
            }

            mapContainer.innerHTML = `
              <div class="error-box">
                <div>
                  <strong>${errorMessage}</strong>
                  <div style="margin-top: 10px; font-size: 14px;">
                    Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
                  </div>
                </div>
              </div>
            `;
          } else {
            // Non-critical error, just log it
            console.warn('Non-critical map error:', e);
          }
        });
      } catch (err) {
        console.error('Map initialization error:', err);
        mapContainer.innerHTML = `
          <div class="error-box">
            <div>
              <strong>❌ Failed to initialize map. Check your style URL from https://portal.mapmetrics.org/</strong>
              <div style="margin-top: 10px; font-size: 14px;">
                Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
              </div>
            </div>
          </div>
        `;
      }
    }
  </script>
</body>
</html>

Pattern 2: React Map Component (with Error Handling)

jsx
import React, { useEffect, useRef, useState } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

function MapComponent() {
  const mapContainerRef = useRef(null);
  const mapRef = useRef(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!mapContainerRef.current || mapRef.current) return;

    const styleUrl = 'YOUR_STYLE_URL_WITH_TOKEN';

    // Check if user forgot to replace the placeholder
    if (styleUrl === 'YOUR_STYLE_URL_WITH_TOKEN' || styleUrl.includes('YOUR_')) {
      setError('⚠️ Please replace YOUR_STYLE_URL_WITH_TOKEN with your actual style URL from https://portal.mapmetrics.org/');
      setLoading(false);
      return;
    }

    try {
      const map = new mapmetricsgl.Map({
        container: mapContainerRef.current,
        style: styleUrl,
        center: [longitude, latitude],
        zoom: 12
      });

      // Handle map load success
      map.on('load', () => {
        setLoading(false);
        setError(null);
      });

      // Handle CRITICAL errors only (authentication, style loading failures)
      // Ignore non-critical errors like individual tile loading failures
      map.on('error', (e) => {
        console.error('Map error:', e);

        // Only show UI errors for critical failures that prevent map from working
        // Ignore tile loading errors and other minor issues that don't break the map
        const isCriticalError =
          e.error?.status === 401 ||
          e.error?.message?.includes('401') ||
          (e.error?.message?.includes('Failed to fetch') && !loading) === false ||
          (e.sourceId === undefined && e.error); // Style loading errors have no sourceId

        if (isCriticalError) {
          setLoading(false);

          // Authentication errors (401)
          if (e.error?.message?.includes('401') || e.error?.status === 401) {
            setError('❌ Invalid API token. Get a valid token from https://portal.mapmetrics.org/');
          }
          // Network/style URL errors during initial load
          else if (e.error?.message?.includes('Failed to fetch') && loading) {
            setError('❌ Cannot load map style. Check your style URL from https://portal.mapmetrics.org/');
          }
          // Generic critical error before map loads
          else if (loading) {
            setError('❌ Map failed to load. Check your style URL and token at https://portal.mapmetrics.org/');
          }
          // If map already loaded, just log the error (don't hide the map)
          else {
            console.warn('Map error after load (non-critical):', e);
          }
        } else {
          // Non-critical errors (tile loading, etc.) - just log them
          console.warn('Non-critical map error:', e);
        }
      });

      mapRef.current = map;

      return () => {
        if (map) {
          map.remove();
          mapRef.current = null;
        }
      };
    } catch (err) {
      console.error('Map initialization error:', err);
      setError('❌ Failed to initialize map. Check your style URL from https://portal.mapmetrics.org/');
      setLoading(false);
    }
  }, []);

  // Display error message if something went wrong
  if (error) {
    return (
      <div style={{
        height: '500px',
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#f8d7da',
        color: '#721c24',
        padding: '20px',
        textAlign: 'center',
        fontSize: '16px',
        border: '2px solid #f5c6cb',
        borderRadius: '8px',
        fontFamily: 'system-ui, -apple-system, sans-serif'
      }}>
        <div>
          <strong>{error}</strong>
          <div style={{ marginTop: '10px', fontSize: '14px' }}>
            Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style={{ color: '#721c24' }}>Discord</a>
          </div>
        </div>
      </div>
    );
  }

  // Optional: Show loading state
  if (loading) {
    return (
      <div style={{
        height: '500px',
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#f0f0f0'
      }}>
        Loading map...
      </div>
    );
  }

  return <div ref={mapContainerRef} style={{ height: '500px', width: '100%' }} />;
}

export default MapComponent;

Pattern 3: Add Marker

javascript
// Vanilla JS
const marker = new mapmetricsgl.Marker()
  .setLngLat([longitude, latitude])
  .addTo(map);

// With popup
const marker = new mapmetricsgl.Marker()
  .setLngLat([longitude, latitude])
  .setPopup(new mapmetricsgl.Popup().setHTML('<h3>Location Name</h3>'))
  .addTo(map);

// Draggable marker
const marker = new mapmetricsgl.Marker({ draggable: true })
  .setLngLat([longitude, latitude])
  .addTo(map);

Pattern 4: REST API Call (Directions)

javascript
// POST request to Directions API
const response = await fetch('https://gateway.mapmetrics-atlas.net/directions/?token=YOUR_TOKEN', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    locations: [
      { lat: 40.744014, lon: -73.990508 },
      { lat: 40.752522, lon: -73.985015 }
    ],
    costing: 'auto'
  })
});

const data = await response.json();
// data.trip contains route information

Pattern 5: Geocoding (Forward)

javascript
// GET request to Forward Geocode API
const address = encodeURIComponent('1600 Pennsylvania Avenue NW, Washington, DC');
const response = await fetch(
  `https://gateway.mapmetrics-atlas.net/forward-geocode/?token=YOUR_TOKEN&text=${address}`
);

const data = await response.json();
// data.features[0].geometry.coordinates contains [lon, lat]

Pattern 6: Matrix API

javascript
// POST request to Matrix API
const response = await fetch('https://gateway.mapmetrics-atlas.net/matrix/?token=YOUR_TOKEN', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sources: [
      { lat: 40.744014, lon: -73.990508 },
      { lat: 40.739735, lon: -73.979713 }
    ],
    targets: [
      { lat: 40.752522, lon: -73.985015 },
      { lat: 40.750117, lon: -73.983704 }
    ],
    costing: 'pedestrian'
  })
});

const data = await response.json();
// data.sources_to_targets contains time/distance matrix

📊 API Response Structures

Directions Response

json
{
  "trip": {
    "locations": [...],
    "legs": [
      {
        "maneuvers": [
          {
            "instruction": "Turn right onto Main Street",
            "time": 45.2,
            "length": 0.542
          }
        ],
        "summary": {
          "time": 18734.567,
          "length": 453.211
        }
      }
    ],
    "summary": {
      "time": 18734.567,
      "length": 453.211
    },
    "units": "kilometers"
  }
}

Geocoding Response

json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [longitude, latitude]
      },
      "properties": {
        "name": "Location Name",
        "label": "Full Address",
        "country": "Country Name"
      }
    }
  ]
}

Matrix Response (Verbose)

json
{
  "sources_to_targets": [
    [
      {
        "distance": 1.342,
        "time": 294,
        "from_index": 0,
        "to_index": 0
      }
    ]
  ],
  "units": "kilometers"
}

🔑 Important Notes for Code Generation

1. Token Handling - CRITICAL ⚠️

EVERY generated code example MUST include token instructions!

What Happens Without a Token:

  • ❌ Map fails to load (shows blank/error)
  • ❌ API returns 401 Unauthorized
  • ❌ Console errors: "Token required"
  • ❌ User gets frustrated and blames MapMetrics

Required Token Instructions Template:

ALWAYS include this in your response:

⚠️ IMPORTANT: You need an API key to use MapMetrics!

1. Get your free API key at: https://portal.mapmetrics.org/
2. Replace 'YOUR_STYLE_URL_WITH_TOKEN' in the code with your actual style URL
3. The style URL from the portal already includes your token

Without a valid token, the map will not load!

Token Best Practices:

  • NEVER expose real tokens in generated code
  • ALWAYS use placeholder: YOUR_STYLE_URL_WITH_TOKEN or YOUR_API_TOKEN
  • ALWAYS include the portal link: https://portal.mapmetrics.org/
  • ALWAYS explain that the style URL includes the token
  • ALWAYS add a warning comment in the code

Example Code Comment:

javascript
// ⚠️ REPLACE THIS with your actual style URL from https://portal.mapmetrics.org/
style: 'YOUR_STYLE_URL_WITH_TOKEN'

2. NPM Package Name - CRITICAL ⚠️

ALWAYS use the correct package name!

bash
# ✅ CORRECT
npm install @mapmetrics/mapmetrics-gl

# ❌ WRONG - DO NOT USE!
npm install maplibre-gl  # This will NOT work with MapMetrics!
javascript
// ✅ CORRECT imports
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

// ❌ WRONG - DO NOT USE!
import maplibregl from 'maplibre-gl';  // Wrong package!

3. React Patterns

  • ALWAYS use useRef for map container
  • ALWAYS use useRef for map instance
  • ALWAYS cleanup in useEffect return
  • NEVER create map if it already exists
  • ALWAYS use @mapmetrics/mapmetrics-gl, NEVER maplibre-gl

4. Coordinate Format

  • MapMetrics uses: [longitude, latitude] (NOT lat/lon)
  • API requests use: {lat: number, lon: number} objects
  • Be consistent based on context

5. Error Handling

javascript
// Always include error handling
try {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const data = await response.json();
} catch (error) {
  console.error('API request failed:', error);
}

6. Costing Models

Valid values: auto, bicycle, pedestrian, bus, truck, taxi, motor_scooter

7. Units

  • Distance: km (default) or miles / mi
  • Time: always in seconds
  • Coordinates: decimal degrees

📚 Machine-Readable References

AI Navigation File

llms.txt with all URLs, code templates, and common mistakes: https://docs.mapatlas.xyz/llms.txt

Example Files

All examples include:

  • YAML frontmatter with metadata
  • Complete JavaScript implementation
  • Complete React implementation
  • Copy-paste ready code

🎓 Example Code Generation Flow

User Request: "Create a map with a draggable marker and popup in React"

AI Response Steps:

  1. Identify capabilities: React integration + Markers + Popups
  2. Reference examples: /sdk/examples/react-map-example, /sdk/examples/add-a-marker, /sdk/examples/add-a-popup
  3. Combine patterns into working code
  4. Include proper imports, refs, cleanup
  5. Add placeholder for style URL
  6. Remind user to get API key

⚡ Quick Command Reference

bash
# NPM Installation - ALWAYS USE THIS PACKAGE NAME!
npm install @mapmetrics/mapmetrics-gl

# ❌ WRONG - DO NOT USE
npm install maplibre-gl  # This is NOT MapMetrics!

# Import in JavaScript
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

# ❌ WRONG imports
import maplibregl from 'maplibre-gl';  # Wrong!

# CDN Links
<link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
<script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>

🚨 Common Pitfalls to Avoid

  1. Don't use maplibre-gl package - ALWAYS use @mapmetrics/mapmetrics-gl
  2. Don't create multiple map instances in React
  3. Don't forget to cleanup map in useEffect return
  4. Don't mix up [lon, lat] vs {lat, lon} formats
  5. Don't forget token in API requests
  6. Don't hardcode real tokens in examples
  7. Don't generate code without clear token instructions
  8. Don't call new mapmetricsgl.Map() before the CDN script has finished loading — causes Uncaught ReferenceError: mapmetricsgl is not defined

3. CDN Script Loading Order - CRITICAL ⚠️

The most common AI-generated bug: mapmetricsgl is not defined — this happens when map code runs before the CDN script has finished loading.

❌ WRONG — causes "mapmetricsgl is not defined":

html
<script>
  // Script added dynamically but map created immediately after — WRONG!
  const script = document.createElement('script');
  script.src = 'https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js';
  document.body.appendChild(script);

  // ❌ This runs BEFORE the script above has loaded!
  const map = new mapmetricsgl.Map({ container: 'map', style: '...' });
</script>

✅ CORRECT Option A — static <script> tag in <head> (simplest for plain HTML):

html
<head>
  <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
  <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
</head>
<body>
  <div id="map"></div>
  <script>
    // ✅ Safe: <head> script is already loaded before body scripts run
    const map = new mapmetricsgl.Map({ container: 'map', style: 'YOUR_STYLE_URL' });
  </script>
</body>

✅ CORRECT Option B — dynamic script with script.onload (required when loading script dynamically):

html
<body>
  <div id="map"></div>
  <script>
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = 'https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css';
    document.head.appendChild(link);

    const script = document.createElement('script');
    script.src = 'https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js';
    document.body.appendChild(script);

    // ✅ ALL map code must go inside script.onload
    script.onload = () => {
      const map = new mapmetricsgl.Map({ container: 'map', style: 'YOUR_STYLE_URL' });
      map.addControl(new mapmetricsgl.NavigationControl(), 'top-right');
    };
  </script>
</body>

Rule for AI agents: When generating HTML with CDN, ALWAYS use Option A (static <script> in <head>) OR Option B (script.onload). Never call new mapmetricsgl.Map() outside of script.onload when the script is dynamically inserted.

🔧 Troubleshooting Guide

Problem: Map doesn't load (blank screen)

Most Common Cause: Missing or Invalid Token

javascript
// ❌ WRONG - Will not work
const map = new mapmetricsgl.Map({
  container: 'map',
  style: 'YOUR_STYLE_URL_WITH_TOKEN',  // Placeholder not replaced!
  center: [0, 0],
  zoom: 10
});

Solution:

javascript
// ✅ CORRECT - User must replace with actual URL from portal
const map = new mapmetricsgl.Map({
  container: 'map',
  // Get this URL from https://portal.mapmetrics.org/
  style: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_ID/style.json&token=YOUR_TOKEN',
  center: [0, 0],
  zoom: 10
});

Error Messages to Watch For:

  • 401 Unauthorized → Missing or invalid token
  • Token required → Token not provided in request
  • Map container blank → Check console for token errors

Problem: Uncaught ReferenceError: mapmetricsgl is not defined

Cause: Map code runs before the CDN script has finished loading.

This is the most common error when AI tools generate HTML. The fix is to either:

  1. Put the <script src="...mapmetrics-gl.js"> tag in <head> (not added dynamically), OR
  2. Wrap ALL map code inside script.onload = () => { ... }
html
<!-- ✅ CORRECT: Static script in <head> -->
<head>
  <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
  <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
</head>
<body>
  <div id="map"></div>
  <script>
    const map = new mapmetricsgl.Map({ container: 'map', style: 'YOUR_STYLE_URL' });
  </script>
</body>

<!-- ✅ CORRECT: Dynamic script with onload -->
<script>
  const script = document.createElement('script');
  script.src = 'https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js';
  document.body.appendChild(script);
  script.onload = () => {
    const map = new mapmetricsgl.Map({ container: 'map', style: 'YOUR_STYLE_URL' });
  };
</script>

Problem: REST API returns 401

Cause: Missing token parameter

javascript
// ❌ WRONG
fetch('https://gateway.mapmetrics-atlas.net/directions/', {
  method: 'POST',
  body: JSON.stringify({...})
});

// ✅ CORRECT
fetch('https://gateway.mapmetrics-atlas.net/directions/?token=YOUR_TOKEN', {
  method: 'POST',
  body: JSON.stringify({...})
});

User Doesn't Have a Token Yet

When user says "create a map" without mentioning a token:

Your response MUST include:

  1. Working code with placeholder
  2. Clear instructions to get token
  3. Link to portal
  4. Explanation that map won't work without it

Example Response Template:

Here's the code to create a map:

[code with placeholder]

⚠️ IMPORTANT: Before this works, you need to:
1. Sign up at https://portal.mapmetrics.org/ (free)
2. Get your map style URL (includes API token)
3. Replace 'YOUR_STYLE_URL_WITH_TOKEN' in the code above

The map will NOT load without a valid token!

✅ Best Practices

  1. Always include complete, working examples
  2. Always include both JavaScript and React versions when applicable
  3. Always remind users about API key requirement
  4. Always include error handling
  5. Always use proper React patterns (refs, cleanup)
  6. Always include CSS for map container
  7. Always link to relevant documentation sections

📖 Additional Resources


Last Updated: 2026-03-03 Documentation Version: 1.1.0 Optimized for: Claude, ChatGPT, Gemini, and other AI coding assistants