How to Snap a GPS Track to the Road Network

API or service
Map Matching API
Task
Ordered GPS measurements → matched road route
Examples
URL
Difficulty
Intermediate
Time
10 min

Snap a GPS track to the road network

You have an ordered sequence of noisy GPS measurements from a completed or ongoing trip and need a road-aligned route. The Map Matching API associates those measurements with plausible road positions and returns matched route geometry and road steps.

Map matching preserves input order and follows the recorded track as closely as possible. It does not reorder points or optimize a new trip like the Routing API.

Task flow: ordered GPS measurements → Map Matching API → matched points, road-aligned geometry, and route details.

Submit a GPS track

POST up to 1000 ordered measurements. Each location uses [longitude, latitude] order; ISO timestamps help the matcher evaluate movement between samples.

POST https://api.geoapify.com/v1/mapmatching?apiKey=YOUR_API_KEY
Content-Type: application/json
{
  "mode": "drive",
  "waypoints": [
    {
      "timestamp": "2019-11-04T07:09:34.000Z",
      "location": [10.694703, 47.567028]
    },
    {
      "timestamp": "2019-11-04T07:09:57.000Z",
      "location": [10.6952599, 47.5682759]
    },
    {
      "timestamp": "2019-11-04T07:10:17.000Z",
      "location": [10.6975647, 47.5691475]
    },
    {
      "timestamp": "2019-11-04T07:10:49.000Z",
      "location": [10.7004255, 47.5696526]
    },
    {
      "timestamp": "2019-11-04T07:11:34.000Z",
      "location": [10.7028073, 47.5688025]
    },
    {
      "timestamp": "2019-11-04T07:11:55.000Z",
      "location": [10.7059951, 47.5678558]
    },
    {
      "timestamp": "2019-11-04T07:12:16.000Z",
      "location": [10.7106272, 47.5658437]
    },
    {
      "timestamp": "2019-11-04T07:12:47.000Z",
      "location": [10.7175699, 47.5655232]
    }
  ]
}

Choose the mode that produced the track. An optional bearing from 0 to 360 degrees can provide additional direction context for a measurement.

Read matched points

The response is a GeoJSON FeatureCollection. Its geometry is the reconstructed road route, while properties.waypoints relates each input measurement to its matched location.

Reduced response:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "distance": 2024,
        "time": 138,
        "waypoints": [
          {
            "original_index": 0,
            "original_location": [10.694703, 47.567028],
            "location": [10.694689, 47.56703],
            "match_type": "matched",
            "match_distance": 1.022797,
            "leg_index": 0,
            "step_index": 0
          },
          {
            "original_index": 1,
            "original_location": [10.6952599, 47.5682759],
            "location": [10.695257, 47.568269],
            "match_type": "matched",
            "match_distance": 0.792993,
            "leg_index": 0,
            "step_index": 10
          },
          {
            "original_index": 2,
            "original_location": [10.6975647, 47.5691475],
            "location": [10.697561, 47.569138],
            "match_type": "matched",
            "match_distance": 1.012806,
            "leg_index": 0,
            "step_index": 14
          }
        ]
      }
    }
  ]
}

original_location preserves the measurement, while location is the road-matched position. match_distance is the distance between them in meters. Do not overwrite the original GPS data when storing matched results.

The route geometry is omitted from this reduced response. The complete feature contains a MultiLineString with 129 road-aligned coordinates for this request.

Handle match quality

Inspect every returned waypoint instead of assuming that all measurements matched successfully.

match_type Meaning for the application
matched The measurement was associated with a road position.
interpolated The position was inferred from surrounding matched measurements.
merged A measurement was combined with a nearby measurement.
unmatched No suitable road position was found.

Use match_distance as a quality signal, but choose thresholds based on the device accuracy, sampling interval, road density, and product requirements. A larger value is not automatically wrong in tunnels, urban canyons, or sparse road networks.

For production tracks:

  • keep measurements ordered and retain their original indexes;
  • send timestamps and bearings when they are available and reliable;
  • split tracks longer than 1000 measurements into manageable chronological chunks;
  • detect large time or distance gaps before matching unrelated trip segments together;
  • retain original and matched coordinates for auditing;
  • handle an empty route or unmatched measurements without breaking visualization or analytics.