Skip to content
Display Map Performance Metrics

Display Map Performance Metrics in Maptoolkit Maps JS

Maptoolkit Maps JS emits load, idle, and render events that you can use to measure how quickly the map initializes and how smoothly it runs on the user’s device. Load time is measured from the start of initialization to the load event, time to idle adds the tile loading phase, and FPS is sampled by counting render events per second. Use this data to identify performance regressions, set benchmarks for new map configurations, or build a real-time performance overlay during development.

const API_KEY = 'YOUR_API_KEY';
    const createdAt = performance.now();

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [11.39085, 47.27574],
        zoom: 12,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        document.getElementById('load').textContent = (performance.now() - createdAt).toFixed(0) + ' ms';
    });

    map.once('idle', () => {
        document.getElementById('idle').textContent = (performance.now() - createdAt).toFixed(0) + ' ms';
    });

    let frameCount = 0;
    let fpsStart = performance.now();
    map.on('render', () => {
        frameCount++;
        const elapsed = performance.now() - fpsStart;
        if (elapsed >= 1000) {
            document.getElementById('fps').textContent = Math.round(frameCount * 1000 / elapsed);
            frameCount = 0;
            fpsStart = performance.now();
        }
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Display Map Performance Metrics - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Measure map performance using built-in events." />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
    <style>
        html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
        #metrics {
            position: absolute;
            top: 10px;
            left: 10px;
            background: white;
            padding: 10px 14px;
            border-radius: .4rem;
            font-family: sans-serif;
            font-size: 14px;
            z-index: 100;
        }
        #metrics div { margin: 4px 0; }
        #metrics span { font-weight: bold; }
    </style>
</head>
<body>
<div id="map"></div>
<div id="metrics">
    <div>Load: <span id="load">-</span></div>
    <div>Idle: <span id="idle">-</span></div>
    <div>FPS: <span id="fps">-</span></div>
</div>
<script>
    const API_KEY = 'YOUR_API_KEY';
    const createdAt = performance.now();

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [11.39085, 47.27574],
        zoom: 12,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        document.getElementById('load').textContent = (performance.now() - createdAt).toFixed(0) + ' ms';
    });

    map.once('idle', () => {
        document.getElementById('idle').textContent = (performance.now() - createdAt).toFixed(0) + ' ms';
    });

    let frameCount = 0;
    let fpsStart = performance.now();
    map.on('render', () => {
        frameCount++;
        const elapsed = performance.now() - fpsStart;
        if (elapsed >= 1000) {
            document.getElementById('fps').textContent = Math.round(frameCount * 1000 / elapsed);
            frameCount = 0;
            fpsStart = performance.now();
        }
    });
</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 interactive map with zoom level 12, centered around [11.39085, 47.27574]. Display a performance metrics overlay showing load time, idle time, and FPS.

How it works

Three events describe the lifecycle, and they mean different things. load fires when the style and the first tiles are ready, so it is the “something is visible” moment. idle fires when every tile has arrived and no animation is running, which is the “finished” moment and usually much later. render fires on every frame, which is what a frame-rate counter counts.

Timing from page start to load measures perceived speed; timing to idle measures the full cost. Reporting only one of them tells half the story.

Counting render events over a second gives an approximate frame rate. It is approximate because the renderer skips frames when nothing changes, so an idle map legitimately reports a very low number. Measure during a movement, not at rest.

Frame rate is dominated by what is on the map: terrain, extrusions, tilted views and large GeoJSON sources all cost, and a tilted view pulls tiles from much further away.

Next steps

Numbers on your own machine are the least useful ones. The next step is collecting them from real sessions, where the interesting cases are old phones and weak GPUs rather than the laptop you built on.

When something is slow, the causes are usually few: too many DOM markers, a large GeoJSON source re-uploaded too often, terrain, or a tilted view pulling distant tiles. Each has a known fix, clustering being the most common, so measuring which one it is matters more than micro-optimising.