Map matching
Map matching takes an ordered GPS trace and snaps it to roads in the installed Valhalla region. It differs from routing: routing creates a path between points, while map matching reconstructs the roads followed by a recorded track.
Valhalla must be installed, ready and contain both the trace and nearby roads. Each request needs at least two points. Atlas accepts up to 10,000 points by default.
Send a trace
Send coordinates in recording order. Include epoch-second timestamps and accuracy in metres whenever the source provides them; they help Valhalla match noisy or ambiguous tracks.
curl --request POST 'http://localhost:8484/api/v1/map-match' \
--header 'content-type: application/json' \
--data '{
"shape": [
{"lat": 52.5000, "lon": 13.4000, "time": 1714032000, "accuracy": 8},
{"lat": 52.5100, "lon": 13.4100, "time": 1714032030, "accuracy": 6}
],
"mode": "auto",
"shape_match": "map_snap",
"format": "geojson"
}'
mode accepts auto, bicycle or pedestrian. shape_match accepts
map_snap, walk_or_snap or edge_walk. Optional search_radius,
gps_accuracy and breakage_distance values tune Valhalla's matcher; use the
API reference for the complete schema.
Read the result
Every successful response includes:
data.summary: total matched length in kilometres and estimated time in seconds.data.matched_points: one correlation result for each input point, in the same order. Its type ismatched,interpolatedorunmatched.data.stats: counts, number of segments, distance error statistics and Valhalla confidence scores when available.
The geometry depends on format:
polyline6is the default.data.legscontains one independently drawable encoded polyline per matched segment.geojsonreturnsdata.geometryplus independently drawabledata.segments. One continuous match is aLineString; a trace with gaps is aMultiLineString. This prevents false straight lines across unmatched gaps.
Request directions only when needed
Set include_directions to true when a client needs narrative maneuvers:
{
"shape": [
{"lat": 52.5000, "lon": 13.4000},
{"lat": 52.5100, "lon": 13.4100}
],
"include_directions": true
}
Atlas then makes a second Valhalla request. Read the primary and alternate
direction results from data.directions.paths. Without this option,
data.legs contains matched geometry segments and no narrative maneuvers.
This response contract changed in 0.6.0. Clients written for earlier versions
that read maneuvers from data.legs must opt into directions and use the new
path above.
Capacity and retries
Map matching is CPU-intensive and occupies a Valhalla worker for the request. Atlas admits four map matches concurrently by default and does not queue excess work. When all slots are occupied it returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
The JSON error code is MAP_MATCH_BUSY. Wait for the indicated delay before
retrying, and use exponential backoff if the instance remains busy.
Operators can change the limit with MAP_MATCH_CONCURRENCY. Raising it above
Valhalla's practical capacity can increase latency for every request. The
MAP_MATCH_MAX_POINTS setting changes the per-request point limit; splitting a
long recording into sensible time or distance windows is usually safer than
raising it.
An unmatchable trace returns 422 VALIDATION_ERROR. Check that its coordinates
are valid, fall inside the installed region and are neither too sparse nor too
noisy. An unavailable Valhalla instance returns 503 UPSTREAM_UNAVAILABLE.