Skip to content

Display Vector Tiles in Mapbox GL JS

Mapbox GL JS requires an access token from mapbox.com in addition to your Maptoolkit API key.

Basic Map

const API_KEY = 'YOUR_API_KEY';
    mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';

    const STYLE_URL = `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`;

    // Maptoolkit styles declare `sprite` as an array, which is the MapLibre extension for
    // several sprite sheets. Mapbox GL JS only accepts a string and rejects the whole style
    // with "sprite: string expected, array found", so collapse it before handing it over.
    async function loadStyleForMapbox(url) {
      const style = await fetch(url).then((r) => r.json());
      if (Array.isArray(style.sprite)) style.sprite = style.sprite[0].url;
      return style;
    }

    loadStyleForMapbox(STYLE_URL).then((style) => {
      const map = new mapboxgl.Map({
        container: 'map',
        style,
        center: [12.805988, 47.310897],
        zoom: 11
      });
    });
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js"></script>
  <link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css" />
  <style>
    html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
    #map { width: 100%; height: 100%; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const API_KEY = 'YOUR_API_KEY';
    mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';

    const STYLE_URL = `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`;

    // Maptoolkit styles declare `sprite` as an array, which is the MapLibre extension for
    // several sprite sheets. Mapbox GL JS only accepts a string and rejects the whole style
    // with "sprite: string expected, array found", so collapse it before handing it over.
    async function loadStyleForMapbox(url) {
      const style = await fetch(url).then((r) => r.json());
      if (Array.isArray(style.sprite)) style.sprite = style.sprite[0].url;
      return style;
    }

    loadStyleForMapbox(STYLE_URL).then((style) => {
      const map = new mapboxgl.Map({
        container: 'map',
        style,
        center: [12.805988, 47.310897],
        zoom: 11
      });
    });
  </script>
</body>
</html>

Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.

Use the Maptoolkit Connector. Create an html file of an interactive map using vector tiles and the Mapbox GL JS. Use zoom level 11 and center it around Zell am See. Maptoolkit

How it works

The style has to be patched before Mapbox GL JS will accept it. Maptoolkit styles declare sprite as an array of {id, url} objects, the MapLibre extension for several sprite sheets. Mapbox GL JS implements only the single-string form and rejects the whole style with Error: sprite: string expected, array found, leaving a blank map. Fetching the JSON and collapsing sprite to the first sheet’s URL is the fix, and it is why the map is constructed inside a then.

Summer, Street, Light and Dark ship one sprite, so nothing is lost. Winter, Hiking and Cycling ship several, and icons from the second sheet cannot be drawn in Mapbox GL JS at all. MapLibre GL JS and Maps JS support the array form natively and need none of this.

This example needs two credentials, and they do different jobs. mapboxgl.accessToken is a Mapbox token that unlocks the Mapbox GL JS library itself. The api_key in the style URL is your Maptoolkit key, and it authorizes the style and the tiles it pulls. One without the other fails: no Mapbox token and the library refuses to start, no Maptoolkit key and every tile request returns 403.

Nothing converts between the two systems. Maptoolkit styles are Mapbox Style JSON apart from the sprite field, so Mapbox GL JS follows the sources inside the style to our tile server. You are using Mapbox as a renderer and Maptoolkit as the data.

center is [longitude, latitude], which is the opposite order from Leaflet.

Next steps

With the basemap up, the next move is your own data on top: a GeoJSON source with a circle or line layer, or a symbol layer for icons. Mapbox GL JS handles these exactly as MapLibre does, so examples written for either apply.

It is also worth choosing the style deliberately. The seven in Vector Tiles differ in cartography rather than palette, and the URL takes a language suffix for non-English labelling.