Skip to content

Add a Temperature Layer in MapLibre GL JS

This example adds the current temperature data as a fill layer to a MapLibre GL map using the Weather API vector tile source.

const API_KEY = "YOUR_API_KEY";
    const map = new maplibregl.Map({
      container: "map",
      style: "https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=" + API_KEY,
      center: [13.0, 47.5],
      zoom: 5,
    });
    map.on("load", () => {
      map.addSource("weather", { type: "vector", url: `https://weather.maptoolkit.net/vector/icon.0.json?api_key=${API_KEY}` });
      const firstSymbolId = (map.getStyle().layers.find((l) => l.type === "symbol") || {}).id;

      map.addLayer({
        id: "weather-temperature", type: "fill", source: "weather", "source-layer": "temperature",
        paint: {
          "fill-color": ["interpolate", ["linear"], ["get", "degree"], -20, "#313695", 0, "#74add1", 10, "#fee090", 20, "#f46d43", 35, "#a50026"],
          "fill-opacity": 0.6,
        },
      }, firstSymbolId);
    });
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://cdn.jsdelivr.net/npm/maplibre-gl@5.6.1/dist/maplibre-gl.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@5.6.1/dist/maplibre-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";
    const map = new maplibregl.Map({
      container: "map",
      style: "https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=" + API_KEY,
      center: [13.0, 47.5],
      zoom: 5,
    });
    map.on("load", () => {
      map.addSource("weather", { type: "vector", url: `https://weather.maptoolkit.net/vector/icon.0.json?api_key=${API_KEY}` });
      const firstSymbolId = (map.getStyle().layers.find((l) => l.type === "symbol") || {}).id;

      map.addLayer({
        id: "weather-temperature", type: "fill", source: "weather", "source-layer": "temperature",
        paint: {
          "fill-color": ["interpolate", ["linear"], ["get", "degree"], -20, "#313695", 0, "#74add1", 10, "#fee090", 20, "#f46d43", 35, "#a50026"],
          "fill-opacity": 0.6,
        },
      }, firstSymbolId);
    });
  </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 a map centered on Austria with MapLibre GL and put a heat map of the current temperature of Europe on top.

How it works

Weather here is not a REST call. It is a vector tile source, added with type: 'vector' and a TileJSON URL, so the renderer streams tiles as you pan instead of you fetching and redrawing a payload.

source-layer: 'temperature' selects one layer inside those tiles. A vector source can hold several, and naming the wrong one produces an empty map with no error.

The fill colour is data-driven: ['get', 'degree'] reads the temperature off each feature and the interpolate expression blends between the stops, so the gradient is computed by the renderer rather than baked into the tiles.

firstSymbolId is the detail worth copying. Passing it as the third argument to addLayer inserts the weather fill below the first symbol layer, so place names and road labels stay readable on top of it. Without it the fill covers every label on the map.

Coverage is not global: the ICON model covers Germany and its neighbours at high resolution and Europe more broadly. Outside that area the tiles are simply empty.

Next steps

Temperature is one layer of several. The Weather API reference lists the others and the forecast steps, and stepping through those steps on a timer is what turns a static overlay into the forecast animation people expect from a weather map.

A colour ramp also needs a legend to mean anything. The stops in the expression are the values to label, and a fixed scale is usually better than one that adapts, since a map whose colours shift between loads cannot be compared with itself.