How to Find Gaps Between Service Areas and a Target Region
- API or service
- Isoline API + Geometry Operations API
- Task
- Facilities + target region → uncovered area
- Examples
- Difficulty
- Intermediate
- Time
- 15 min
Find gaps between service areas and a target region
You have several facilities and a region that should be covered within a travel-time target. Calculate a service area for every facility, merge those polygons, and subtract the merged coverage from the target region. The remainder is the uncovered area.
Task flow: facility coordinates → Isoline API service areas → union coverage → subtract from target polygon → coverage gaps.
This workflow supports delivery expansion, emergency response planning, store-network analysis, and public-service accessibility. It measures geographic coverage under the chosen travel assumptions; it does not prove that capacity or demand inside the covered area is sufficient.
Plan the coverage-gap workflow
Use the same settings for every facility so the polygons remain comparable:
- Calculate one Isoline API polygon per facility with the same
mode,type,range, traffic model, and avoidance rules. - Send the service-area geometries to the Geometry Operations API with
operation=union. - Send the target polygon first and the unioned coverage second with
operation=difference. - Display or measure the returned Polygon or MultiPolygon. An empty result means the supplied target region is fully covered by those geometries.
The target can be an operational GeoJSON polygon drawn by a user or an administrative polygon obtained from the Boundaries API. GeoJSON coordinates always use [longitude, latitude] order, and each polygon ring must repeat its first position as its last position.
For difference, order matters: every polygon after the first is subtracted from the first. Use [targetRegion, combinedCoverage], not the reverse.
Calculate uncovered areas with JavaScript
This compact example analyzes two 15-minute drive-time areas against a rectangular target region in Berlin. Replace the rectangle with the actual GeoJSON Polygon or MultiPolygon for your service territory.
const apiKey = "YOUR_API_KEY";
const facilities = [
{ lat: 52.52, lon: 13.405 },
{ lat: 52.505, lon: 13.32 }
];
const targetRegion = {
type: "Polygon",
coordinates: [[
[13.20, 52.42], [13.60, 52.42],
[13.60, 52.62], [13.20, 52.62],
[13.20, 52.42]
]]
};
async function requestJson(url, options) {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`Geoapify request failed: ${response.status}`);
return response.json();
}
async function geometryOperation(body) {
return requestJson(
`https://api.geoapify.com/v1/geometry/operation?apiKey=${encodeURIComponent(apiKey)}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
}
);
}
// Geometry results can be a geometry or a GeoJSON Feature; normalize both.
const asGeometry = value => value.type === "Feature" ? value.geometry : value;
const serviceAreas = await Promise.all(facilities.map(async facility => {
const params = new URLSearchParams({
lat: String(facility.lat),
lon: String(facility.lon),
type: "time",
mode: "drive",
range: "900",
traffic: "free_flow",
format: "geojson",
apiKey
});
const result = await requestJson(`https://api.geoapify.com/v1/isoline?${params}`);
return result.features[0].geometry;
}));
// Merge overlapping facility coverage before subtracting it.
const unionResult = await geometryOperation({
operation: "union",
polygons: serviceAreas
});
const combinedCoverage = asGeometry(unionResult.data);
// Difference returns the parts of the target that remain uncovered.
const gapResult = await geometryOperation({
operation: "difference",
polygons: [targetRegion, combinedCoverage]
});
const uncoveredArea = gapResult.type === "empty" ? null : asGeometry(gapResult.data);
console.log(uncoveredArea?.type ?? "Fully covered");
// MultiPolygon for these example inputs
The API can return a Polygon or MultiPolygon because separate gaps may remain. Keep every polygon part; selecting only the first can silently discard uncovered locations.
Prepare coverage analysis for production
- Use comparable inputs: Keep mode, range, traffic, route preference, and avoidance rules identical across facilities unless the differences are intentional.
- Use the real target boundary: Simplified administrative geometry may be enough for regional planning, but parcel or contractual service boundaries may require a more precise source.
- Validate geometry: Reject invalid or unclosed input rings before calling
unionordifference. Preserve all parts of MultiPolygon results. - Avoid double counting: Union overlapping service areas before calculating gap area, population, or other totals.
- Separate reachability from capacity: A location can be reachable while its assigned facility lacks staff, stock, or appointment capacity.
- Store calculation settings: Save the origins and isoline parameters with the result so later comparisons remain reproducible.
- Handle partial failures: Do not report full network coverage if one facility's isoline request failed. Retry temporary errors and show which facilities were excluded.
For large facility networks, process requests within account rate limits and cache unchanged service areas. Recalculate only when a facility or reachability rule changes.