Skip to main content
Glama

Snap a GPS trace to streets

map_match
Read-onlyIdempotent

Map-match a GPS trace: snap points onto the street graph, stitch a route.

Instructions

Map-match a GPS trace: snap points onto the street graph, stitch a route.

points is an ordered list of {"lat": ..., "lon": ...} — up to 100 of
them (Mapbox's Map Matching tool takes the same cap; anything past it
returns {"error": "bad_request"} rather than truncating the trace
silently). A malformed point (missing/non-numeric lat or lon, or a
coordinate out of range) returns {"error": "bad_request"} naming the
offending index as "points[i]: ...".

Returns {"matched_length_m", "roads", "confidence", "geometry",
"unmatched_points"}: matched_length_m is the summed routed (not
straight-line) distance across every stitched leg; roads lists the
street names crossed in travel order, deduplicated only where they
repeat back to back; geometry is the stitched polyline as a GeoJSON
LineString, simplified to fit the same token budget every geometry-
returning tool here targets; unmatched_points lists the input
indices that never made it into the stitched route — points too far
from any street, and points the stitching's outlier guard rejected
(a routed detour wildly out of proportion to the straight-line gap,
e.g. a trace point that jumped to a different block). confidence
(0..1) blends how much of the trace stitched against how far the
matched points sat from their snapped street position.

A trace that matches nothing is a real answer, not an error:
matched_length_m 0, empty roads/geometry, every index in
unmatched_points, with a "note" explaining it. Do not treat that shape
as a failure — it means the trace is genuinely off the mapped street
network here, which is itself useful to know. A trace where only ONE
point matches gets the same empty-geometry shape with its own note: a
single position can't make a LineString (RFC 7946 requires two) or a
route.

Offline graph work, same as route()/isochrone(): builds one street
graph from Overture's transportation theme over the trace's own padded
bounding circle (no network beyond the existing tile/graph path) and
reuses route()'s per-mode class exclusions, so e.g. a drive trace never
snaps onto a footway. Omit mode to use the stored preferences mode,
else walk. An unrecognized mode string returns
{"error": "unsupported_mode"}. If no usable street graph exists near
the trace at all, returns {"error": "no_graph_nearby"}; a trace whose
padded bounding circle exceeds the mode's extraction cap (e.g. a walk
trace spanning well past ~10 km) returns {"error": "radius_too_large",
"max_radius_m": ...} — try the trace in segments, or a faster mode; a
scan that can't reach the upstream Overture data returns
{"error": "upstream_unavailable", "retry_advised": true}; missing
essential source columns returns {"error": "schema_degraded"}.

Attribution: street geometry and names from Overture Maps
transportation data.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
modeNoTravel mode. Default: stored preference, else walk.
pointsYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv0.11.0

TDQS

Score is being calculated.