Skip to main content
Technology & EngineeringMaps Geolocation Services213 lines

TomTom Maps

TomTom Maps SDK: interactive maps, search, routing, traffic, geofencing, and real-time location services via Maps SDK for Web and REST APIs

Quick Summary19 lines
You are an expert in integrating TomTom Maps SDK and APIs for mapping, search, routing, and traffic.

## Key Points

- **Routing without `traffic: true`** -- Non-traffic ETAs can be 30%+ off during peak hours. Always enable traffic for any routing that affects user-facing ETAs or operational logistics.
- **Forgetting to include the Maps SDK CSS file** -- Without the CSS, markers render without styling, popups are invisible, and map controls do not display correctly.
- Use `traffic: true` in routing requests to get realistic ETAs that account for live traffic conditions — the non-traffic ETA can differ significantly during peak hours.
- Batch multiple geocoding requests using the batch search API (`/search/2/batch.json`) instead of making individual calls, which reduces latency and counts as fewer transactions.
- Set the `language` and `countrySet` parameters in search queries to improve result relevance and reduce ambiguous matches.
- The Maps SDK uses `[lng, lat]` order (GeoJSON convention), not `[lat, lng]`. Swapping these produces a map centered in the wrong location or markers placed in the ocean.
- Forgetting to include the CSS file for the Maps SDK causes markers and popups to render without styling and controls to be invisible.

## Quick Example

```bash
npm install @tomtom-international/web-sdk-maps @tomtom-international/web-sdk-services
```
skilldb get maps-geolocation-services-skills/TomTom MapsFull skill: 213 lines
Paste into your CLAUDE.md or agent config

TomTom Maps — Maps & Geolocation

You are an expert in integrating TomTom Maps SDK and APIs for mapping, search, routing, and traffic.

Core Philosophy

TomTom is a mapping company that builds its own map data from ground truth, not a platform that aggregates third-party data. Its core differentiator is real-time traffic intelligence: TomTom collects billions of GPS measurements from vehicles, phones, and infrastructure sensors to produce traffic flow data with high accuracy and low latency. Choose TomTom when traffic-aware routing, real-time traffic visualization, or EV-specific routing with charge station planning are critical requirements.

Always enable traffic in routing requests. The non-traffic ETA can differ from the traffic-aware ETA by 30% or more during peak hours. TomTom's traffic: true parameter uses real-time and historical traffic data to produce realistic arrival times. Routing without traffic data is a guess; routing with it is a prediction based on actual road conditions. For logistics, delivery, and ride-sharing applications, this difference directly impacts customer experience and operational efficiency.

The Maps SDK uses [lng, lat] coordinate order, following the GeoJSON convention. This is the opposite of the common verbal convention ("lat, lng") and the single most frequent source of bugs in TomTom integrations. Every constructor, method, and data structure in the SDK expects longitude first, latitude second. Getting this wrong places markers in the ocean and centers maps on the wrong continent.

Anti-Patterns

  • Swapping latitude and longitude in SDK calls -- The Maps SDK uses [lng, lat] order (GeoJSON convention). Passing [lat, lng] produces a map centered in the wrong location or markers placed in the ocean.
  • Routing without traffic: true -- Non-traffic ETAs can be 30%+ off during peak hours. Always enable traffic for any routing that affects user-facing ETAs or operational logistics.
  • Making individual geocoding calls that could be batched -- TomTom's batch search API (/search/2/batch.json) processes multiple queries in a single request, reducing latency and counting as fewer transactions against your daily quota.
  • Forgetting to include the Maps SDK CSS file -- Without the CSS, markers render without styling, popups are invisible, and map controls do not display correctly.
  • Not setting language and countrySet in search queries -- Without locale parameters, search results are ambiguous. "Springfield" returns dozens of matches worldwide. Setting countrySet: "US" and language: "en-US" dramatically improves relevance.

Overview

TomTom provides mapping and location services including interactive vector maps, geocoding/search, routing (with traffic-aware ETA), real-time traffic flow and incidents, geofencing, and EV routing with charge-station planning. The Maps SDK for Web renders vector or raster maps in the browser, while REST APIs serve geocoding, routing, and traffic data. The free tier includes 2,500 daily transactions across most APIs.

Setup & Configuration

API Key

Register at developer.tomtom.com to get an API key.

Maps SDK for Web (npm)

npm install @tomtom-international/web-sdk-maps @tomtom-international/web-sdk-services
import tt from "@tomtom-international/web-sdk-maps";
import ttServices from "@tomtom-international/web-sdk-services";
import "@tomtom-international/web-sdk-maps/dist/maps.css";

const map = tt.map({
  key: "YOUR_API_KEY",
  container: "map",
  center: [13.405, 52.52], // [lng, lat]
  zoom: 12,
});

Maps SDK via CDN

<link
  rel="stylesheet"
  href="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.25.1/maps/maps.css"
/>
<script src="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.25.1/maps/maps-web.min.js"></script>
<script src="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.25.1/services/services-web.min.js"></script>

Core Patterns

Fuzzy Search (Geocoding)

TomTom's search endpoint is called "fuzzy search" and handles addresses, POIs, and categories in a single call.

async function fuzzySearch(query, center) {
  const response = await ttServices.services.fuzzySearch({
    key: "YOUR_API_KEY",
    query,
    center,
    limit: 5,
    language: "en-US",
  });
  return response.results.map((r) => ({
    name: r.poi?.name || r.address.freeformAddress,
    position: r.position,
    address: r.address,
    type: r.type,
  }));
}

Reverse Geocoding

async function reverseGeocode(lat, lng) {
  const response = await ttServices.services.reverseGeocode({
    key: "YOUR_API_KEY",
    position: { lat, lng },
  });
  return response.addresses.map((a) => ({
    address: a.address.freeformAddress,
    country: a.address.country,
    position: a.position,
  }));
}

Routing with Traffic

async function calculateRoute(origin, destination) {
  const response = await ttServices.services.calculateRoute({
    key: "YOUR_API_KEY",
    locations: [origin, destination], // each: { lat, lng }
    travelMode: "car",
    traffic: true,
    computeBestOrder: false,
  });

  const route = response.routes[0];
  const summary = route.summary;
  return {
    distanceMeters: summary.lengthInMeters,
    travelTimeSeconds: summary.travelTimeInSeconds,
    trafficDelaySeconds: summary.trafficDelayInSeconds,
    departureTime: summary.departureTime,
    arrivalTime: summary.arrivalTime,
    legs: route.legs,
    geojson: route.toGeoJson(),
  };
}

Displaying a Route on the Map

async function showRoute(map, origin, destination) {
  const routeData = await ttServices.services.calculateRoute({
    key: "YOUR_API_KEY",
    locations: [origin, destination],
    travelMode: "car",
    traffic: true,
  });

  const geojson = routeData.toGeoJson();

  map.addLayer({
    id: "route",
    type: "line",
    source: { type: "geojson", data: geojson },
    paint: {
      "line-color": "#4a90d9",
      "line-width": 6,
    },
  });

  const bounds = new tt.LngLatBounds();
  geojson.features[0].geometry.coordinates.forEach((c) => bounds.extend(c));
  map.fitBounds(bounds, { padding: 50 });
}

Traffic Flow

// Add traffic flow layer to the map
function enableTrafficFlow(map) {
  map.addTier(
    new tt.TrafficFlowTilesTier({
      key: "YOUR_API_KEY",
      style: "relative", // "absolute", "relative", "relative-delay"
    })
  );
}

// REST API for a specific road segment
async function getTrafficFlow(lat, lng) {
  const url = `https://api.tomtom.com/traffic/services/4/flowSegmentData/relative/10/json?point=${lat},${lng}&key=YOUR_API_KEY`;
  const res = await fetch(url);
  const data = await res.json();
  return {
    currentSpeed: data.flowSegmentData.currentSpeed,
    freeFlowSpeed: data.flowSegmentData.freeFlowSpeed,
    confidence: data.flowSegmentData.confidence,
  };
}

Markers and Popups

function addMarkerWithPopup(map, lngLat, popupHtml) {
  const popup = new tt.Popup({ offset: 30 }).setHTML(popupHtml);

  const marker = new tt.Marker()
    .setLngLat(lngLat)
    .setPopup(popup)
    .addTo(map);

  return marker;
}

Best Practices

  • Use traffic: true in routing requests to get realistic ETAs that account for live traffic conditions — the non-traffic ETA can differ significantly during peak hours.
  • Batch multiple geocoding requests using the batch search API (/search/2/batch.json) instead of making individual calls, which reduces latency and counts as fewer transactions.
  • Set the language and countrySet parameters in search queries to improve result relevance and reduce ambiguous matches.

Common Pitfalls

  • The Maps SDK uses [lng, lat] order (GeoJSON convention), not [lat, lng]. Swapping these produces a map centered in the wrong location or markers placed in the ocean.
  • Forgetting to include the CSS file for the Maps SDK causes markers and popups to render without styling and controls to be invisible.

Install this skill directly: skilldb add maps-geolocation-services-skills

Get CLI access →