> ## Documentation Index
> Fetch the complete documentation index at: https://docs.footstep.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# snap_trace

> Clean up a GPS trace and get road details

Map-match a recorded GPS trace (up to 20,000 points) to the road network. Returns the corrected path with a confidence score, plus road details like surface type, road class, speed limits, and terrain analytics.

Useful for analysing recorded activities (runs, rides, walks) or cleaning noisy GPS data.

## Example prompts

* "Clean up this GPS trace from my bike ride"
* "What roads did I actually travel on during this run?"
* "Snap these GPS coordinates to roads and show me the surface types"
* "Analyse my recorded walk - what was the terrain and road quality like?"

## What you get back

A confidence-scored snapped path, route with terrain analytics (ascent, descent, difficulty), and per-segment road attributes (surface type, road class, speed limit, grade). Also includes per-point match quality so you can see where GPS was noisy.

Consecutive segments that share the same street names, road class, and surface are returned as a single edge — a long stretch of one road shows up once, not many times. Lengths sum across merged edges; `speed_kph` and `grade_percent` are length-weighted averages. The split is preserved whenever any of those attributes differ.

### Edge attributes

Each edge carries:

* **`road_class`** — one of `motorway`, `trunk`, `primary`, `secondary`, `tertiary`, `unclassified`, `residential`, `service`. Roughly mirrors OSM's `highway=*` hierarchy from biggest road type to smallest. `service` covers alleys, parking aisles, and driveways.
* **`surface`** — one of `paved_smooth`, `paved`, `paved_rough`, `compacted`, `dirt`, `gravel`, `ground`, `impassable`. `compacted` is a firm gravel/dirt mix; `ground` is natural untreated terrain.
* `names` — array of street names for the edge (often empty on unnamed paths).
* `length_meters`, `speed_kph`, `grade_percent` — numeric attributes.

Unknown values from the underlying engine are dropped rather than passed through, so any string you see in `road_class` or `surface` is from the lists above.

### Low-confidence matches

When `confidence` is below 0.5 — meaning the trace couldn't be reliably matched to the road network (sparse points, off-road, or noisy GPS) — the response includes:

* `match_quality: "low"` — a flag indicating the match is unreliable.
* `match_quality_reason` — a short human-readable explanation.

`distance_meters`, `duration_seconds`, `edges`, and `terrain` are still populated so you can see what the engine reconstructed. The disclaimer travels alongside the data — treat numbers as approximate when `match_quality` is set, exact when it isn't.

## When a trace can't be matched

Some inputs can't produce a meaningful match — too few points, points spaced too widely, or points too far from any road. The endpoint returns **422 Unprocessable Entity** with a message describing the cause (e.g. `"Insufficient number of trace points"`, `"No suitable edges near input location"`). Treat 422 as a "fix the input" signal rather than retrying. Common fixes:

* **Sparse traces** — provide more points (every few seconds, not every minute) or include `time` on each point.
* **Off-road points** — relax `gps_accuracy` or `search_radius` so the matcher can snap further from the recorded location.
* **Single-mode mismatch** — if a phone trace was recorded while indoors or in a tunnel, try `shape_match: "walk_or_snap"` (the default) rather than strict `map_snap`.

## Matching strictness

The tool defaults to a forgiving matching mode (`walk_or_snap`) that handles typical phone-GPS noise — if a point falls a few metres off the nearest road, the tool walks the closest edge rather than rejecting the whole trace. This matches the realistic 5–15 m accuracy of urban GPS recordings.

For high-quality traces (cyclometer downloads, surveying-grade data) or when you want strict per-point snapping, the REST API exposes `shape_match` (`edge_walk` / `map_snap` / `walk_or_snap`) and `gps_accuracy`. Defaults are sensible for most cases — only override when you have a specific reason.

## Map rendering

Responses include a `render` envelope with a `linestring` layer for the snapped trace. Pass `compact: true` for summary-only responses. See [response defaults & controls](/mcp/defaults) and [render envelopes](/mcp/render-envelopes).

## Example response

```json theme={null}
{
  "structuredContent": {
    "confidence": 0.91,
    "distance_meters": 2300,
    "duration_seconds": 480,
    "terrain": { "difficulty": "flat", "total_ascent_meters": 4 },
    "edges": [/* coalesced segment-level surface / class / speed / grade */],
    "render": [
      { "kind": "linestring", "label": "Snapped trace", "data": {/* GeoJSON LineString */}, "bbox": [/* … */] }
    ]
  }
}
```
