Skip to main content

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.

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 and render envelopes.

Example response

{
  "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": [/* … */] }
    ]
  }
}