Planetary-scale answers, unlocked.
A Hands-On Guide for Working with Large-Scale Spatial Data. Learn more.
Authors
Map matching takes the positions a vehicle's GPS (Global Positioning System) receiver recorded and finds the roads it drove on. The result is one connected path on a road network, with each GPS record placed on a road.
The simplest way to do this is to move each GPS record to its nearest road. That works when the GPS position is close to the road. It fails where the error is larger than the gap between two roads.
We tested this on one week of drives in Ann Arbor, Michigan: 199,249 GPS records, matched two ways. The first way moved each record to its nearest road. The second used hidden Markov model (HMM) map matching, which scores whole chains of connected roads and keeps the most likely route.
Where a record was within 5 m of the matched road, the methods disagreed on 5.1% of records. At 20 to 50 m, they disagreed on 54.2%. Many disagreements put a moving car on a driveway or parking aisle next to the main road.
For moving vehicles, use HMM map matching. In 12,968 records, nearest-road snapping put the car on a driveway, parking aisle or other service road where the HMM put it on the main road. 56.6% of those records were moving at 40 km/h or more, a speed that fits the main road.
Nearest-road snapping gives nearly the same answer only when GPS error is small: within 5 m of the road, the two methods agreed on 94.9% of records. The test had no record of the true route, so it shows where the methods differ and which result the recorded speed supports. It does not give an error rate for either method.
Mohammed Quddus, Washington Ochieng and Robert Noland define map-matching algorithms in Current map-matching algorithms for transport applications (Transportation Research Part C, 2007). In their words, these algorithms "integrate positioning data with spatial road network data (roadway centrelines)." Their purpose is "to identify the correct link on which a vehicle is travelling and to determine the location of a vehicle on a link." A link is one stretch of road between two junctions. A centreline is the line drawn down the middle of a road.
Two inputs go in:
One output comes out: a path along the road network, with each GPS record placed on one road.
Map matching is needed because GPS positions are noisy. Pingfu Chao, Yehong Xu, Wen Hua and Xiaofang Zhou list the two main error sources in A Survey on Map-Matching Algorithms (arXiv, 2019). The first is measurement error, where a recorded position lies some distance from the true one. The second is sampling error, which grows as the time between GPS records gets longer. A noisy GPS record can sit beside the road, in a parking lot, or closer to a road the car never used.
Map matching is one step in geospatial analysis of vehicle data. Its output becomes the input for distance per road, speed per road and route counts.
Quddus and his co-authors grouped methods published before 2007 into four kinds: geometric, topological, probabilistic and advanced. Chao and his co-authors summarize the groups.
Geometric methods use only the distance between GPS records and roads. Topological methods also use how roads connect and their shapes. Probabilistic methods model GPS error and search for the path most likely to have produced the trace. Advanced methods use tools such as Kalman filters, particle filters and fuzzy logic.
The oldest geometric method is point-to-curve matching. In the words of the Chao survey, it "projects each trajectory point to the geometric-closest edge." An edge is one road piece between two connections. This method needs only a distance calculation, so it is fast and easy to run in Structured Query Language (SQL), the standard language for querying databases.
It ignores order and connections. Two GPS records one second apart can land on roads with no link between them.
Curve-to-curve methods compare a piece of the GPS trace with a piece of road and pick the road whose shape is closest. The Chao survey names the Fréchet distance as the most common measure. The Fréchet distance compares two lines while keeping the order of their points, so it measures shape as well as position. The survey also notes that it is sensitive to outliers: one bad GPS record can dominate the score.
A hidden Markov model is a statistical model of a sequence of states that cannot be seen directly. Each state produces a measurement that can be seen. Lawrence Rabiner explains HMMs in A tutorial on hidden Markov models and selected applications in speech recognition (Proceedings of the IEEE, 1989).
In map matching, the hidden state is the vehicle's real position on the road. The GPS record is the measurement. The Chao survey describes the steps:
The transition score can outweigh distance. A chain on the service road would need two detours through a parking lot, so it scores lower than a straight drive on the main road.
The Chao survey separates two modes. Online map matching runs while the vehicle drives. It uses the current GPS record and a few records near it, so a navigation app can show the car on the right road with little delay. Offline map matching runs after the whole trip is recorded. It can use every record, so it can aim for the best path for the whole trip.
HMM methods work in both modes. The survey notes that online HMM methods match each record after a short delay.
The results of studies that checked both methods against a known route follow one pattern. Snapping each record to the nearest road works when GPS records are frequent and accurate and no other road runs close by. With ordinary GPS, HMM map matching holds up better when records are noisy, far apart, or near other roads. On stacked roads, neither method did well with ordinary GPS alone.
The Ann Arbor test below fits this pattern. The two methods mostly agreed where records sat within 5 m of the road, and split near junctions and next to service roads.
radiuses
Map matching works for any mode of travel, as long as the network matches the mode. A car trace is matched to roads a car can use. A walking trace needs sidewalks, crosswalks, footpaths and steps. A cycling trace needs bike paths plus the roads a bike may use.
Map matching services ask for the mode up front. The Mapbox Map Matching API takes a profile: mapbox/driving, mapbox/driving-traffic, mapbox/walking for "pedestrian and hiking" travel, or mapbox/cycling. In the OSRM API, the profile is fixed when the road data is prepared and is "typically car, bike or foot."
mapbox/driving
mapbox/driving-traffic
mapbox/walking
mapbox/cycling
Open map data carries the paths these modes need. Overture's transportation data has road classes for footways (with sidewalk and crosswalk subclasses), cycleways, paths, steps and pedestrian streets. Its scoping rules let an access restriction apply to one travel mode only.
We measured those paths in the same Ann Arbor area as the test below, with Overture data in Wherobots. Footways, paths, cycleways, steps, pedestrian streets and bridleways add up to 2,064 km. That is 58% of the 3,561 km of road the car test used:
SELECT SUM(CASE WHEN class IN ('footway','path','cycleway','steps','pedestrian','bridleway') THEN ST_LengthSpheroid(geometry) END) / 1000 AS walk_bike_km FROM wherobots_open_data.overture_maps_foundation.transportation_segment WHERE subtype = 'road' AND bbox.xmin > -83.86 AND bbox.xmax < -83.62 AND bbox.ymin > 42.18 AND bbox.ymax < 42.37
Many of these paths run right beside a road:
The median distance counts only segments with a car road within about 25 m. The table comes from this query:
WITH seg AS ( SELECT id, class, subclass, geometry FROM wherobots_open_data.overture_maps_foundation.transportation_segment WHERE subtype = 'road' AND bbox.xmin > -83.86 AND bbox.xmax < -83.62 AND bbox.ymin > 42.18 AND bbox.ymax < 42.37), walk AS ( SELECT id, CASE WHEN class = 'footway' AND subclass = 'sidewalk' THEN 'sidewalk' WHEN class = 'footway' THEN 'other footway' ELSE class END AS kind, ST_LineInterpolatePoint(geometry, 0.5) AS mid FROM seg WHERE class IN ('footway', 'cycleway', 'path')), car AS ( SELECT geometry FROM seg WHERE class IN ('motorway','trunk','primary','secondary','tertiary','residential','unclassified','living_street')), near AS ( SELECT w.id, MIN(ST_DistanceSphere(w.mid, ST_ClosestPoint(c.geometry, w.mid))) AS d FROM walk w JOIN car c ON ST_DWithin(c.geometry, w.mid, 0.0003) GROUP BY w.id) SELECT w.kind, COUNT(*) AS segments, AVG(CASE WHEN n.d <= 15 THEN 1.0 ELSE 0.0 END) AS share_within_15m, percentile_approx(n.d, 0.5) AS median_distance_m FROM walk w LEFT JOIN near n ON n.id = w.id GROUP BY w.kind
Those gaps of about 9 m are close to the GPS error in the car test. There, the median distance from a GPS record to its matched road was 5.8 m. So a walking or cycling trace faces the same problem as a car beside a parking lot: the nearest line is often the wrong one. Snapping a pedestrian to the nearest line can put them in the traffic lane. Snapping a cyclist on a bike path can put them on the road next to it.
The car test below left these paths out on purpose, because a car cannot drive on them. It did not measure walking or cycling traces. Separate bike paths appear as cycleway segments in Overture; this article did not check how painted bike lanes on a road are recorded.
Wherobots Map Matching runs HMM map matching on tables of trips. Its Python matcher reference documents matcher.match, which takes a table of road edges and a table of trips. The Wherobots Map Matching launch post describes it as "a Hidden Markov Model approach in the lineage of Newson and Krumm." Nearest-road snapping is a spatial join in WherobotsDB SQL. So both methods can run on the same records in one job.
matcher.match
Claim. Snapping each GPS record to its nearest road puts a moving car on the wrong road often enough to change per-road results. The errors cluster near junctions and where a service road runs next to the road the car drove.
What would support it. Disagreement between the methods rises as GPS error rises, and is higher near junctions. In disagreements, nearest-road snapping returns a service road while the car is moving at road speed. The HMM path stays close to the length of the raw trace, so it does not add detours.
What would break it. Disagreement stays flat across GPS error and junction distance. Disagreements split evenly between "nearest picks the service road" and "HMM picks the service road." Or the HMM path is much longer than the raw trace.
A limit applies to the whole test. VED has no ground-truth path, so neither method can be scored as right or wrong. The test measures where the methods differ, and uses recorded vehicle speed to judge which placement is plausible.
The GPS records come from the VED week starting 1 November 2017, as published in the Wherobots examples bucket. We kept one record per second per trip. That left 344,200 records from 854 trips by 258 vehicles.
The road network is Overture Maps road segments in a box around Ann Arbor, from the transportation segment table in Wherobots Open Data. Overture describes its transportation data as segments, which are the paths, and connectors, which are the junctions where they meet. Each segment was split at its connectors into edges. That produced 65,235 edges from 29,980 segments, totaling 3,560.9 km of road.
Method 1 snaps each GPS record to the nearest edge within 50 m:
SELECT trip_id, sec, eid AS nn_eid, seg_id AS nn_seg, d AS nn_d FROM ( SELECT p.trip_id, p.sec, e.eid, e.seg_id, ST_DistanceSphere(p.pt, ST_ClosestPoint(e.geometry, p.pt)) AS d, ROW_NUMBER() OVER (PARTITION BY p.trip_id, p.sec ORDER BY ST_DistanceSphere(p.pt, ST_ClosestPoint(e.geometry, p.pt)), e.eid) AS r FROM p JOIN edges e ON ST_DWithin(e.geometry, p.pt, 0.0006) ) WHERE r = 1 AND d <= 50
ST_DWithin with 0.0006 degrees (about 49 to 67 m at this latitude) narrows each record to nearby edges before the exact distance is measured. ST_DistanceSphere gives that distance in meters.
ST_DWithin
ST_DistanceSphere
Method 2 runs Wherobots Map Matching on each trip as one line of GPS positions. The settings allow a GPS record to be up to 50 m from its road, with an expected GPS error of 20 m:
from wherobots import matcher sedona.conf.set("wherobots.tools.mm.matcher", "legacy") sedona.conf.set("wherobots.tools.mm.maxdist", "50") sedona.conf.set("wherobots.tools.mm.maxdistinit", "50") sedona.conf.set("wherobots.tools.mm.obsnoise", "20") mm = matcher.match(roads_mm, trips, "geometry", "geometry", "ids")
The matcher returns matched_nodes, the junctions the matched path passes through, in order. Each pair of consecutive junctions is one road edge. All 47,669 junction pairs in the matched paths joined to an edge:
matched_nodes
-- mn: one row per consecutive junction pair (n, n2) in each trip's matched_nodes SELECT DISTINCT ids, eid FROM ( SELECT mn.ids, e.eid FROM mn JOIN edges e ON e.src = mn.n AND e.dst = mn.n2 UNION ALL SELECT mn.ids, e.eid FROM mn JOIN edges e ON e.dst = mn.n AND e.src = mn.n2 )
Each GPS record was then placed on the nearest edge of its own trip's matched path. A record counts as a disagreement when the two methods put it on different Overture segments.
All 833 trips with at least 5 records and 100 m of travel were matched. The matched path was close in length to the raw trace. The ratio of matched length to trace length had a median of 1.005, with 10th and 90th percentiles of 0.988 and 1.045. So the HMM path did not add long detours.
199,249 GPS records had a road from both methods. They disagreed on 32,596 records, or 16.4%. 771 of the 833 trips had at least one disagreement. For 31,808 records (16.0%), the nearest-road segment was not on the trip's HMM path at all. The median distance from a GPS record to its road was 4.86 m for nearest-road snapping and 5.76 m for the HMM path.
Disagreement rose with GPS error. Where the GPS record was within 5 m of the road on the HMM path, the methods disagreed on 5.1% of 89,262 records. At 20 to 50 m, they disagreed on 54.2% of 12,387 records.
Junctions raised disagreement. We counted a record as near a junction when it was within 25 m of a point where three or more edges meet. 111,420 records met that test. The methods disagreed on 22.5% of them, against 8.6% of the other records. One likely reason: near a junction, a cross street lies a few meters from the car, so a small GPS error can make it the nearest road.
Speed made less difference. Disagreement was 11.4% below 5 km/h, 16.8% at 5 to 30 km/h, 19.1% at 30 to 60 km/h and 14.4% at 60 km/h or more.
Overture's road classes include main roads (motorway, trunk, primary, secondary, tertiary), residential streets and service roads. Service roads include driveways, parking aisles and alleys. The most common disagreement was a record the HMM placed on a secondary road and nearest-road snapping placed on a service road: 8,576 records.
In 12,968 disagreements, nearest-road snapping returned a service road and the HMM returned a main road. In 405, it was the other way round. Of the 12,968 records, 56.6% were moving at 40 km/h or more, with a median speed of 44 km/h. The 405 records had a median speed of 16 km/h.
Of the service roads nearest-road snapping returned, 4,275 were driveways, 2,142 parking aisles and 232 alleys. 6,319 had no subclass in Overture.
Across all 99,317 compared records at 40 km/h or more, nearest-road snapping put 8,429 (8.5%) on a service road. The HMM put 1,119 (1.1%) there.
One trip shows the pattern. Vehicle 457 drove along South Industrial Highway in Ann Arbor, a road lined with driveways and parking lots. The trip passed the same stretch twice, at 54 to 63 km/h. Nearest-road snapping put 48 of the 63 records in that stretch on service roads. The HMM placed all 63 on the highway.
The records sit west of the road centreline. Along this stretch, a driveway or parking aisle is often closer to them than the centreline, so nearest-road snapping returned it. In the HMM, a drive along the highway got a higher transition score than hops between separate driveways.
The claim held. Disagreement rose from 5.1% within 5 m of the road to 54.2% at 20 to 50 m. Near junctions it was 22.5%, against 8.6% elsewhere.
When the methods split between a main road and a service road, nearest-road snapping returned the service road 12,968 times and the HMM 405 times. 56.6% of those 12,968 records were moving at 40 km/h or more. The HMM path was no more than 4.5% longer than the raw trace for 90% of trips.
Without a ground-truth path, this test cannot give an error rate for either method. It shows where they differ. In the main road vs service road splits, the recorded speeds fit the HMM result far more often.
Early algorithms (2000). White, Bernstein and Kornhauser's 2000 study tested simple map matching algorithms for personal navigation assistants, the handheld and in-car navigation devices of the time.
The 2007 review. Quddus, Ochieng and Noland's review sorted methods into geometric, topological, probabilistic and advanced groups. It notes that navigation in intelligent transport systems needs a horizontal accuracy of 1 m to 40 m (95%). It found that existing algorithms could not always meet those needs, "especially in difficult and complex environments such as dense urban areas."
Hidden Markov models (2009). Paul Newson and John Krumm published Hidden Markov map matching through noise and sparseness in 2009, at the Association for Computing Machinery (ACM) SIGSPATIAL conference. It combined the emission and transition scores described above with the Viterbi algorithm. The Wherobots launch post says "most map matching implementations are variants" of their algorithm.
Low sampling rates (2009). At the same conference, Yin Lou, Chengyang Zhang, Yu Zheng, Xing Xie, Wei Wang and Yan Huang published Map-matching for low-sampling-rate GPS trajectories. Their method scores candidate paths by distance and by whether the implied speed is reasonable. It targets traces with long gaps between GPS records.
Speed through precomputation (2017). Yang and Gidófalvi's FMM adds precomputation to HMM map matching: shortest paths in the road network are computed once, before any trip is matched.
Surveys (2019). Chao, Xu, Hua and Zhou's survey proposed four newer groups: similarity models, state-transition models (HMMs among them), candidate-evolving models such as particle filters, and scoring models.
Map matching at scale. Each trip needs its own candidate search and shortest-path searches, so the work grows with the number of trips. Jia Yu, Jinxuan Wu and Mohamed Sarwat introduced GeoSpark (ACM SIGSPATIAL, 2015) to run spatial joins on Apache Spark, a system that splits data processing across many machines. Yu, Zongsi Zhang and Sarwat described how GeoSpark divides spatial data across machines in Spatial data management in Apache Spark: the GeoSpark perspective and beyond (GeoInformatica, 2018). GeoSpark became Apache Sedona, the engine WherobotsDB is built on.
The Wherobots launch post reports matching 90 million US trips in 1.5 hours on the Wherobots 2XL runtime, at a cost of $873. That is about $9.70 per million trips. The same post lists July 2024 prices per million trips of $1,600 for Mapbox, $4,400 for HERE and $8,000 for Google Maps Platform.
Match GPS traces to roads at scale with Wherobots at cloud.wherobots.com.
Map matching takes a GPS trace, the series of positions a device recorded, and finds the roads the vehicle drove on. The result is a path along a road network. Each GPS record gets a road and a position on that road. Raw GPS positions are a few meters off, so they often fall beside the road or closer to a different road.
A hidden Markov model (HMM) is a statistical model of a sequence of hidden states that can only be observed through noisy measurements. In map matching, the hidden state is the true road position of the vehicle, and the GPS record is the noisy measurement.
Each GPS record gets a few candidate positions on nearby roads. An emission score rates how close each candidate is to the GPS record. A transition score rates how plausible the drive between two candidates is. The Viterbi algorithm then finds the chain of candidates with the best combined score. Newson and Krumm described this method in 2009.
Snapping moves each GPS record to the closest road, one record at a time. Map matching uses the order of the records and the connections between roads, so the result is one connected path. In a test on 199,249 GPS records from Ann Arbor, Michigan, the two methods put 16.4% of records on different roads. Where a GPS record was 20 to 50 m from the matched road, they disagreed on 54.2% of records.
For moving vehicles with ordinary GPS, usually yes. On open roads in Sweden and France, at one GPS record per second, snapping with survey-grade positioning scored 93.80 out of 100. An online HMM with ordinary GPS scored 93.73. On stacked roads in Shanghai, snapping with ordinary GPS scored 43.45 out of 100 against 63.33 for an online HMM. With survey-grade positioning, snapping scored 65.25 there, slightly above the online HMM.
In the Ann Arbor test, snapping put 12,968 records on a service road where the HMM chose the main road, 56.6% of them moving at 40 km/h or more.
A map matching API is a web service that takes a GPS trace and returns the matched path. The Mapbox Map Matching API accepts up to 100 coordinates per request. The Google Roads API takes up to 100 GPS points per request.
HERE, a location data company, offers a Route Matching API. The Open Source Routing Machine (OSRM), an open source routing engine, has a match service. In Wherobots, map matching runs as a function over a table of trips.
Online map matching runs while the vehicle drives. It uses the current GPS record and a few records before it, so navigation apps can show the car on the right road. Offline map matching runs after the whole trip is recorded. It can use every record in the trip, so it can aim for the best path for the whole trip.
Yes, if the network includes the paths people walk and ride. Mapbox’s Map Matching API has walking and cycling profiles, and OSRM is usually set up with car, bike or foot profiles. Sidewalks and bike paths often run next to roads. In Ann Arbor, 57% of Overture sidewalk segments and 66% of cycleway segments have their midpoint within 15 m of a car road. So matching a walking or cycling trace to a car-only network, or snapping it to the nearest line, often picks the wrong one.
You need two inputs. The first is a GPS trace for each trip: positions in time order, ideally with timestamps. The second is a road network: road lines plus the points where they connect, so the method can tell which roads join. Overture Maps transportation segments are one open road network for this.
Accuracy depends on GPS error, on the time between GPS records, and on how close roads are to each other. Measuring accuracy requires a ground-truth path, which most public datasets lack. In the Ann Arbor test, nearest-road snapping and HMM map matching agreed on 94.9% of GPS records that were within 5 m of the matched road. Agreement fell to 45.8% for records 20 to 50 m away.
Paul Newson and John Krumm of Microsoft Research published Hidden Markov map matching through noise and sparseness in 2009, at the Association for Computing Machinery (ACM) SIGSPATIAL conference. Many later map matching tools build on their method, including Wherobots Map Matching.
The Wherobots Map Matching launch post lists five uses. They are satellite and GPS navigation, GPS tracking of freight, scoring driving risk for insurance pricing, analysis of self-driving car trips, and transportation engineering and urban planning. Each use needs every GPS record tied to the road the vehicle was on.
What is a Kelvin Wave? Speed, El Niño and 2026 Data
A Kelvin wave is a long, low ocean wave that carries warm water east along the equator in an El Niño. In the 30 days to 10 November 2026, the sea at San Diego stood a record 41.2 cm above NOAA's tide prediction.
What Is an ETL Pipeline? Steps, Examples and Spatial ETL
An ETL (extract, transform, load) pipeline moves data from sources into storage. Learn the steps with examples. Then see a spatial mistake that passed the usual checks: rounding coordinates emptied 27% of Denver's building outlines.
What is an MCP Server? Spatial Context for AI Agents
An MCP server gives AI agents tools to call. With no tools, Claude Code gave no count of San Francisco's buildings. Via Wherobots MCP, it counted 162,538.
share this article
Awesome that you’d like to share our articles. Where would you like to share it to: