How to Create a Drive-Time Map and Service Area

API or service
Isoline API + MapLibre GL
Task
Origin and time limit → reachable area on a map
Examples
URLMapLibre GL
Difficulty
Beginner
Time
10 min

Create a drive-time service area

You have a facility, store, or starting point and need to show the area reachable by car within a time limit. The Geoapify Isoline API calculates that road-network reachability area as a GeoJSON Polygon or MultiPolygon.

This guide uses an origin in central Berlin and a 15-minute limit. The result can support delivery zones, store catchments, dispatch rules, and location planning.

Task flow: origin coordinates + 15 minutes → Isoline API → GeoJSON service area → map layer.

An isochrone models reachable roads and nearby areas; it is not a circle around the origin. Bridges, road access, travel mode, and traffic settings affect its shape.

Calculate a 15-minute drive-time area

Set type=time, mode=drive, and range=900. Time ranges are always expressed in seconds, so 15 minutes is 15 × 60 = 900 seconds.

https://api.geoapify.com/v1/isoline?lat=52.52&lon=13.405&type=time&mode=drive&range=900&traffic=free_flow&format=geojson&apiKey=YOUR_API_KEY

The origin uses separate lat and lon parameters. GeoJSON coordinates in the response use [longitude, latitude] order.

Parameter Value Meaning
lat, lon 52.52, 13.405 The calculation origin.
type time Calculate an isochrone rather than an isodistance.
mode drive Use passenger-car routing.
range 900 Include locations reachable within 900 seconds.
traffic free_flow Use free-flow travel times. This is also the default.
format geojson Return a GeoJSON FeatureCollection. This is the default format.

Use traffic=approximated when the use case should reflect typical traffic instead. The result is a planning estimate, not a guarantee for a particular departure time.

Reduced response: The polygon coordinates are omitted because the complete MultiPolygon is large.

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "id": "0c5f7e09b6ceda88bb4b01ad2594398c",
        "lat": 52.52,
        "lon": 13.405,
        "mode": "drive",
        "type": "time",
        "range": 900
      },
      "geometry": {
        "type": "MultiPolygon"
      }
    }
  ]
}

Use the complete geometry returned by the API for display or later spatial operations. Do not copy the reduced response into an application.

Display the service area with MapLibre GL

Use this after creating a MapLibre map and waiting for its load event. It requests the complete GeoJSON response, draws a translucent service area, and fits the map to every returned coordinate.

const apiKey = "YOUR_API_KEY";
const params = new URLSearchParams({
  lat: "52.52",
  lon: "13.405",
  type: "time",
  mode: "drive",
  range: "900",
  traffic: "free_flow",
  format: "geojson",
  apiKey
});

const response = await fetch(`https://api.geoapify.com/v1/isoline?${params}`);
if (!response.ok) throw new Error(`Isoline request failed: ${response.status}`);

const serviceArea = await response.json();
if (!serviceArea.features?.length) throw new Error("No service area was returned");

map.addSource("service-area", { type: "geojson", data: serviceArea });
map.addLayer({
  id: "service-area-fill",
  type: "fill",
  source: "service-area",
  paint: { "fill-color": "#623aff", "fill-opacity": 0.25 }
});
map.addLayer({
  id: "service-area-outline",
  type: "line",
  source: "service-area",
  paint: { "line-color": "#623aff", "line-width": 2 }
});

// Extend the bounds with every Polygon or MultiPolygon position.
const bounds = new maplibregl.LngLatBounds();
const includeCoordinates = coordinates => {
  if (typeof coordinates[0] === "number") bounds.extend(coordinates);
  else coordinates.forEach(includeCoordinates);
};
serviceArea.features.forEach(feature => includeCoordinates(feature.geometry.coordinates));
map.fitBounds(bounds, { padding: 40 });

Keep the returned GeoJSON unchanged: MapLibre expects [longitude, latitude], which already matches the API response. Add a marker for the origin separately if users need to see where the calculation started.