How to Choose the Travel Mode for Map Matching

API or service
Map Matching API
Task
GPS track + candidate modes → the mode that fits the track
Examples
URLAI
Difficulty
Beginner
Time
8 min

Choose the travel mode for map matching

You have a recorded GPS track and need to send it to the Map Matching API, but the request needs a mode. The mode decides which roads and paths the matcher may use. Where a bike path runs next to a highway, the same points can snap to either of them, depending only on this parameter.

This guide matches one car track on the Henry Hudson Parkway in Manhattan as drive, bicycle, and truck, compares the results, and shows which response fields tell you that a mode is wrong.

If you still need the basic request and response, start with How to Snap a GPS Track to the Road Network.

Task flow: recorded GPS track + candidate travel mode → Map Matching API → matched share, match distance, and legs → keep or change the mode.

Pick candidate modes

The Map Matching API accepts the same 15 travel modes as the Routing API. The mode limits the road network: a car can't use a bike path, a bicycle can't use a motorway, and the truck modes skip roads closed to trucks.

Group Modes Typical source of the track
On foot walk, hike Pedestrians, field workers, hiking apps
Bicycle bicycle, mountain_bike, road_bike Bike couriers, bike sharing, fitness apps
Car and two-wheelers drive, scooter, motorcycle Passenger cars, motor scooters and mopeds, motorcycles
Trucks light_truck, medium_truck, truck, heavy_truck, truck_dangerous_goods, long_truck Delivery vans and trucks by size and weight, trucks with dangerous goods
Bus bus Buses

Vehicle sizes and weights for each mode are listed in the Routing API travel modes table.

Start with the mode of the device or vehicle that recorded the track, for example from your fleet data. When the source is unknown or mixed, match the track with two or three candidate modes and compare the results as shown in the next sections. Each candidate is a separate request and costs credits again: max(1, ceil(waypoints / 100)) per request, so 1 credit for this 35-point track.

Match one track with several modes

The track below was recorded as a car trip on the Henry Hudson Parkway, northbound from West 79th Street to West 125th Street in Manhattan, New York, NY. It has 35 points, 8 seconds apart, about 4.7 km in total. It is a test track: the points are sampled from a Routing API drive route about every 140 m, with random offsets of up to 8 m to imitate GPS noise.

Send the same body three times and change only mode. Coordinates use [longitude, latitude] order.

POST https://api.geoapify.com/v1/mapmatching?apiKey=YOUR_API_KEY
Content-Type: application/json
{
  "mode": "drive",
  "waypoints": [
    { "location": [-73.986555, 40.782006], "timestamp": "2026-11-04T14:00:00.000Z" },
    { "location": [-73.985279, 40.783501], "timestamp": "2026-11-04T14:00:08.000Z" },
    { "location": [-73.98417, 40.785065], "timestamp": "2026-11-04T14:00:16.000Z" },
    { "location": [-73.983565, 40.78617], "timestamp": "2026-11-04T14:00:24.000Z" },
    { "location": [-73.983041, 40.787316], "timestamp": "2026-11-04T14:00:32.000Z" },
    { "location": [-73.982513, 40.788428], "timestamp": "2026-11-04T14:00:40.000Z" },
    { "location": [-73.982176, 40.789415], "timestamp": "2026-11-04T14:00:48.000Z" },
    { "location": [-73.981597, 40.790489], "timestamp": "2026-11-04T14:00:56.000Z" },
    { "location": [-73.980811, 40.791571], "timestamp": "2026-11-04T14:01:04.000Z" },
    { "location": [-73.979996, 40.792555], "timestamp": "2026-11-04T14:01:12.000Z" },
    { "location": [-73.979339, 40.793502], "timestamp": "2026-11-04T14:01:20.000Z" },
    { "location": [-73.978277, 40.794384], "timestamp": "2026-11-04T14:01:28.000Z" },
    { "location": [-73.97742, 40.795188], "timestamp": "2026-11-04T14:01:36.000Z" },
    { "location": [-73.976405, 40.795971], "timestamp": "2026-11-04T14:01:44.000Z" },
    { "location": [-73.97581, 40.796973], "timestamp": "2026-11-04T14:01:52.000Z" },
    { "location": [-73.975032, 40.798902], "timestamp": "2026-11-04T14:02:00.000Z" },
    { "location": [-73.9746, 40.800023], "timestamp": "2026-11-04T14:02:08.000Z" },
    { "location": [-73.973603, 40.801628], "timestamp": "2026-11-04T14:02:16.000Z" },
    { "location": [-73.972985, 40.802688], "timestamp": "2026-11-04T14:02:24.000Z" },
    { "location": [-73.972134, 40.80367], "timestamp": "2026-11-04T14:02:32.000Z" },
    { "location": [-73.971543, 40.804659], "timestamp": "2026-11-04T14:02:40.000Z" },
    { "location": [-73.97061, 40.80574], "timestamp": "2026-11-04T14:02:48.000Z" },
    { "location": [-73.969941, 40.806626], "timestamp": "2026-11-04T14:02:56.000Z" },
    { "location": [-73.969239, 40.807592], "timestamp": "2026-11-04T14:03:04.000Z" },
    { "location": [-73.96846, 40.808615], "timestamp": "2026-11-04T14:03:12.000Z" },
    { "location": [-73.967381, 40.810204], "timestamp": "2026-11-04T14:03:20.000Z" },
    { "location": [-73.966841, 40.811182], "timestamp": "2026-11-04T14:03:28.000Z" },
    { "location": [-73.966011, 40.812201], "timestamp": "2026-11-04T14:03:36.000Z" },
    { "location": [-73.965302, 40.81313], "timestamp": "2026-11-04T14:03:44.000Z" },
    { "location": [-73.964629, 40.814074], "timestamp": "2026-11-04T14:03:52.000Z" },
    { "location": [-73.964085, 40.81512], "timestamp": "2026-11-04T14:04:00.000Z" },
    { "location": [-73.963373, 40.816103], "timestamp": "2026-11-04T14:04:08.000Z" },
    { "location": [-73.962472, 40.816989], "timestamp": "2026-11-04T14:04:16.000Z" },
    { "location": [-73.961581, 40.817945], "timestamp": "2026-11-04T14:04:24.000Z" },
    { "location": [-73.960503, 40.818957], "timestamp": "2026-11-04T14:04:32.000Z" }

  ]
}

Repeat the request with "mode": "bicycle" and "mode": "truck". All three requests returned HTTP 200 on November 4, 2026:

mode Matched points Legs Route distance Average match_distance Roads in the result
drive 35 of 35 1 4,691 m 3.5 m (max 8.2 m) Henry Hudson Parkway (motorway), the whole route
bicycle 34 of 35 2 4,484 m 36.0 m (max 96.3 m) Cherry Walk 2,437 m, unnamed park paths 1,181 m, Hudson River Greenway 363 m, Riverside Walk 350 m
truck 7 of 35 3 585 m 37.2 m (max 74.6 m) Short pieces on 12th Avenue, Saint Clair Place, and an unnamed road

The route distance is features[0].properties.distance; the road names come from legs[].steps[].name. The average match distance covers the points with match_type matched, because unmatched points have no match_distance.

  • drive is the mode that recorded the track: every point matched, on one leg, within 8.2 m of the road.
  • bicycle can't use the parkway, so the matcher moved the points to the riverside paths that run beside it. Most points still matched, but on average 36 m away from where they were recorded.
  • truck can't use the parkway either: in OpenStreetMap, the Henry Hudson Parkway is tagged hgv=no, and NYC DOT closes it to commercial vehicles north of 59th Street. With no allowed road near most points, 28 points came back unmatched, and the few matched pieces form three separate legs.

Reduced response for mode=truck, first waypoint:

{
  "original_index": 0,
  "location": [-73.986555, 40.782006],
  "original_location": [-73.986555, 40.782006],
  "match_type": "unmatched"
}

An unmatched waypoint keeps its original coordinates in location and has no match_distance, leg_index, or step_index.

Check whether the mode fits

The response contains everything you need to judge a mode. Compute these values from features[0].properties for each candidate:

Signal How to compute it What a wrong mode looks like
Matched share waypoints with match_type matched, interpolated, or merged, divided by all waypoints Many unmatched points: the mode isn't allowed on the roads the vehicle used (truck: 7 of 35 matched)
Average match distance mean match_distance of the matched waypoints, in meters Far above the usual error of the device: the points were moved to a parallel network (bicycle: 36.0 m vs 3.5 m for drive)
Leg count legs.length More than one leg on a continuous trip: the matcher couldn't connect parts of the track (truck: 3 legs)
Timestamps vs. mode speed distance between consecutive waypoints divided by the time between their timestamp values Faster than the mode can travel: points are filtered as incorrect, and the route breaks into legs. The same car track sent as walk, with points 8 seconds and about 140 m apart (about 60 km/h), returned 11 legs, 11 unmatched points, and 600 m of route. Without timestamps, the same points matched as one 5,431 m walking route
Route distance distance compared with the length of the raw track Much shorter: parts of the track were dropped (truck: 585 m of 4.7 km). Much longer: the route detours around roads the mode can't use

A high matched share alone doesn't prove the mode is right. The bicycle result matched 34 of 35 points, but its average match distance was ten times higher than for drive.

When you compare candidates, keep the mode with the highest matched share, a single leg, and the lowest average match distance. Choose thresholds from your own data: the device accuracy, the sampling interval, and how dense the road network is all change what a normal match distance is. To learn how each match_type is assigned, see Check match quality.

Travel mode check with an AI coding agent

Copy this prompt into Codex, Claude Code, Cursor, or another coding agent to add map matching with a travel mode check to your project.

Add GPS track matching with a travel mode check to my project with the Geoapify Map Matching API.

Before you start
- Inspect the existing project first. Reuse its current framework, HTTP client, data models, and conventions. Make the smallest necessary changes.
- Ask only what the project does not answer: where tracks come from, whether each track has a known vehicle type, and whether requests run in a backend or use a restricted browser API key.
- Read the Geoapify API key from the project's environment configuration. Never hardcode, print, or log it.

API request
- POST https://api.geoapify.com/v1/mapmatching?apiKey=... with a JSON body { mode, waypoints }.
- waypoints: up to 1,000 points in recorded order; location is [longitude, latitude]; timestamp (ISO) and bearing (0–360) are optional.
- mode: one of walk, hike, scooter, motorcycle, drive, light_truck, medium_truck, truck, heavy_truck, truck_dangerous_goods, long_truck, bus, bicycle, mountain_bike, road_bike. Map the project's vehicle type to a mode; if it is unknown, match the track with up to three candidate modes.
- Split tracks longer than 1,000 points into chronological chunks. Each request costs max(1, ceil(waypoints / 100)) credits, and every candidate mode is a separate request.

Mode check
- For each result, read features[0].properties: waypoints[].match_type and match_distance, legs.length, and distance.
- Compute the matched share (match_type matched, interpolated, or merged), the average match_distance of matched points, and the leg count.
- Keep the candidate with the highest matched share, a single leg, and the lowest average match_distance. Flag the track for review if the best candidate still has many unmatched points or more than one leg.
- Store the chosen mode with the matched route.

Errors
- Show the API message for HTTP 400 responses, retry 429 responses a limited number of times with backoff, and treat unmatched waypoints as data, not as errors.
- Add a test with a mocked response that contains matched and unmatched waypoints and two legs.

Review the generated code against the requests in this guide. Check the coordinate order ([longitude, latitude]), the mode names, that unmatched waypoints are excluded from the average match distance, and the API-key handling.