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
- 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.