Skip to content
Maptoolkit Maps JS

Add Geocoder Search to a Maptoolkit Maps JS Map

This example adds a search input that calls the Maptoolkit Geocoding API, flies the map to the first result, and places a marker with a popup showing the full place name. No plugin required - the Geocoding API is called directly via fetch.

const API_KEY = 'YOUR_API_KEY';

    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.40037, 47.26816],
        zoom: 12,
        attributionControl: { compact: false }
    });

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

    let marker = null;

    async function search() {
        const q = document.getElementById('query').value.trim();
        if (!q) return;
        const res = await fetch(`https://geocoder.maptoolkit.net/search?q=${encodeURIComponent(q)}&language=en&api_key=${API_KEY}`);
        const results = await res.json();
        if (!results.length) return;
        const { lon, lat, display_name } = results[0];
        map.flyTo({ center: [+lon, +lat], zoom: 14 });
        if (marker) marker.remove();
        marker = new maptoolkit.Marker()
            .setLngLat([+lon, +lat])
            .setPopup(new maptoolkit.Popup().setHTML(`<strong>${display_name}</strong>`))
            .addTo(map);
        marker.togglePopup();
    }

    document.getElementById('btn').addEventListener('click', search);
    document.getElementById('query').addEventListener('keydown', e => { if (e.key === 'Enter') search(); });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Geocoding - Maptoolkit Maps JS</title>
    <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 { width: 100%; height: 100%; }
        #search {
            position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
            z-index: 10; display: flex; gap: 8px;
        }
        #search input {
            width: 260px; padding: 8px 12px; border: none; border-radius: 4px;
            box-shadow: 0 1px 4px rgba(0,0,0,.3); font-size: 14px;
        }
        #search button {
            padding: 8px 14px; border: none; border-radius: 4px;
            background: #2a3561; color: #fff; cursor: pointer; font-size: 14px;
        }
    </style>
</head>
<body>
<div id="map"></div>
<div id="search">
    <input id="query" type="text" placeholder="Search for a place…" value="Innsbruck Sillgasse" />
    <button id="btn">Search</button>
</div>
<script>
    const API_KEY = 'YOUR_API_KEY';

    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.40037, 47.26816],
        zoom: 12,
        attributionControl: { compact: false }
    });

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

    let marker = null;

    async function search() {
        const q = document.getElementById('query').value.trim();
        if (!q) return;
        const res = await fetch(`https://geocoder.maptoolkit.net/search?q=${encodeURIComponent(q)}&language=en&api_key=${API_KEY}`);
        const results = await res.json();
        if (!results.length) return;
        const { lon, lat, display_name } = results[0];
        map.flyTo({ center: [+lon, +lat], zoom: 14 });
        if (marker) marker.remove();
        marker = new maptoolkit.Marker()
            .setLngLat([+lon, +lat])
            .setPopup(new maptoolkit.Popup().setHTML(`<strong>${display_name}</strong>`))
            .addTo(map);
        marker.togglePopup();
    }

    document.getElementById('btn').addEventListener('click', search);
    document.getElementById('query').addEventListener('keydown', e => { if (e.key === 'Enter') search(); });
</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 of Innsbruck with a search box that geocodes the query using the Maptoolkit Geocoding API, flies to the result, and drops a marker.

How it works

There is no geocoder plugin here. The search box is an ordinary input, and the result is placed with a Maps JS marker, which keeps the whole flow visible.

The response is Nominatim-shaped, which explains several details that otherwise look arbitrary. lat and lon come back as strings, not numbers, so they need coercing before a map will accept them. display_name is the full formatted address. boundingbox is [south, north, west, east], also as strings, which is a different order from the [west, south, east, north] that most GeoJSON tooling expects.

The query has to be URL-encoded. encodeURIComponent is not optional: an address with a comma or an ampersand truncates the query without it. Note the unary + in [+lon, +lat], which is what converts those strings to numbers.

The previous marker is removed before a new one is added. Skip that and every search leaves a marker behind.

flyTo animates to the result. jumpTo moves instantly if you would rather not wait for the animation.

Next steps

Two directions from here. Narrowing the search makes it feel better fast: the parameters in the Geocoding API reference restrict results by country or feature type, which matters when a national app keeps returning a same-named town abroad. Reverse geocoding covers the other half, turning a clicked coordinate into an address.

The found coordinate is usually an input rather than an output. The Routing API routes from it and the Isochrone API shows what is reachable around it, both with the key you already have.