
Look closely at that picture. The wide green line is a real GPS recording of a real ride through Henley. Follow it and it strays across Market Place where there is no road, rounds the town hall on the wrong side, and cuts the corner by the car park.
That is not a bad receiver or a bad ride. That is just what recorded tracks are: a few thousand guesses at where you were, each one a little off, joined up with straight lines. The line has the shape of your ride without ever quite being it.
The thin red line is the same ride after Match to Roads, new in PitStopper and firmly in alpha. It works out which roads you actually used and redraws the line along them, and the blue markers are the turn instructions it read off the result.
In the usual words: a track to route converter
Most people arrive at this looking for one of a handful of phrases. Track to route. Convert a GPX track to a route. Snap a GPS track to the roads. Attach to road, which is what the OsmAnd issue that inspired half of this calls it. Map matching, if you come at it from the software side. They are all the same job, and this is it.
What it converts is the frame of reference. A track is a list of positions: it knows where you were and nothing about where that is. After matching, every point sits on a known road, so the line can be described in the road network's own terms. The turn instructions, the road names, the surface and the more honest distance are not four separate features. They are four things that only become answerable once that single change is made.
Two things worth being precise about, because they are what people ask next.
It produces a navigable track, not a GPX <rte>. The output is still a <trk>, with the instructions hung on its trackpoints as navigation extensions. That is the convention Cruiser and Locus Map use, and it keeps the shape of your ride rather than reducing it to a handful of waypoints.
It is not a router. A route in the planning sense is something a routing engine worked out, which means the engine gets a vote on where you go. Here nothing is computed. The line stays exactly where your track went, detour to the shops included, and only its description changes. That is precisely why it can be trusted on a ride nobody would ever have planned.
What it is for
Three things come out of knowing which roads you were on.
The shape gets honest. The wander goes, and so does the opposite problem: joining GPS fixes with straight lines quietly cuts the corner off every bend. On one 44 km ride whose bike computer kept its own odometer, the raw coordinates were 120 m short of the device's figure and the matched line was 80 m out. Not a transformation, but the right direction, and for the right reason.
You get turn-by-turn directions. This is the part people ask for. A ride you recorded becomes a navigable route with proper instructions, exported as a GPX that Cruiser and Locus Map can follow.
You learn what you rode on. Road names, and what the road is made of.
The result
Run it from the sidebar "..." menu, or from Route -> Match to Roads. It takes about a second on a fifty kilometre ride. The help guide covers the whole thing in more detail.

Your recording is never touched. The matched version arrives as a second route beside it, drawn thin and red over the original's wide green so you can compare them at a glance. That is the whole safety model: nothing is overwritten, and if you do not like the result you press Discard and everything is exactly as it was.
When you are happy, Keep only the matched track removes the recording, hands your stops over to the matched version, and puts it back to a normal colour and width.
What it did
A match takes about a second, which is fast enough to look like nothing happened. It will tell you otherwise.

Most of those numbers were being worked out anyway and thrown away. "Road sections" rather than roads, incidentally, because OpenStreetMap splits a road at every bridge, surface change and parish boundary - 164 sections on that ride came to 45 actual named roads.
Turn-by-turn, read off your own line
The turns come from the shape of your track, not from a router. Nothing is re-planned. If you took a road no route planner would ever suggest, you still get instructions for it.

Each instruction names the road it leads onto, read from OpenStreetMap at the junction itself. The distance and time beside each row are the real gap since the last turn, measured from your recording rather than estimated.
The list is deliberately short. This is most of the work. Naively, every handover from one map section to the next is a turn, which gives about four instructions per kilometre, and a wiggly lane reads as four separate turns onto the same road. A 53 km route comes out with 35 instructions. If that is not to your taste, Level of detail moves it up or down and the list rebuilds instantly.
You can correct any of them. The pencil changes an instruction, the bin removes it. A junction the map draws as a sweeping bend, a turn into a car park you would rather not be told about: one click each. There is more on the turn list, and on printing it for a bar mount, in the help guide.
Road surface, for free
The roads were fetched to do the matching, and everything OpenStreetMap knows about them came along too.

About 70% of a typical road ride has a surface recorded. The rest is shown as Unknown rather than assumed, because a road nobody has surveyed is not the same as a smooth one. It goes into the exported file too, in the same format Cruiser writes, so a device that understands surface gets it alongside the turns.
It spots a recording on import
You do not have to go looking for any of this. Import a GPS recording and PitStopper offers it.

It works out whether a file was recorded or drawn from the file itself rather than guessing. A FIT file states whether it holds an activity or a course. A heart rate or power reading can only have been measured. Most tools write their own name into the file. Only if none of that settles it does it fall back to the spacing and timing of the points. Tested against twenty-two real files it never once mistook a planned route for a recording, which is the mistake that matters.
How it works
Worth setting out, partly because the interesting decisions are the ones about what not to do.
The roads come from our own copy of OpenStreetMap. PitStopper runs a PostGIS mirror of the OSM data on its own hardware, the same one that answers every points-of-interest search. Matching asks it a different question: not "what is near here" but "give me every road within 80 metres of this line". A long ride is split into chunks and the answers merged; a chunk that comes back truncated is treated as a miss and retried narrower, because a corridor cut off at the row limit is missing roads somewhere, and reading that as "no road here" would draw a confidently wrong line.
Eighty metres is wider than it sounds it needs to be. The track is simplified before it is sent, so a corridor of radius R only guarantees R minus the simplification tolerance around the real line. The extra is that tolerance.
Finding the candidate roads needs a grid over segments, not points. The obvious tool is a spatial index of coordinates, and it is the wrong one: it indexes points, so a 500 metre road drawn with two vertices is invisible from anywhere in the middle of it, which is exactly where a rider tends to be. So the index is built over road segments instead, in a grid of cells sized to the search radius.
Junctions need recovering too. The ways table stores geometry but not the node identities that tie roads together, so a junction is found the way it appears in the data: two roads that share an identical coordinate to seven decimal places are meeting there.
Then the actual matching, which is a Viterbi pass. For each sample along the track, a handful of candidate positions on nearby roads, plus one extra state meaning "not on any road at all". Each candidate carries an emission cost, being how far the fix is from that road and how badly its heading disagrees with the road's, with a small preference for the more major road at equal distance. Each move between consecutive candidates carries a transition cost: nothing for staying on the same road, a modest charge for crossing a junction, more for a two-junction hop, and a real penalty for turning around. The cheapest chain through the whole trace wins.
That last part is why a chain and not simply the nearest road each time. Nearest-point snapping fails on the three cases that matter most: it flickers between a cycle track and the road running parallel to it, it wanders onto a side road wherever a fix strays near a junction, and on an out-and-back along a dual carriageway it puts both directions on whichever carriageway happens to be closer. A chain has to pay for each of those, so it stops doing them.
BRouter is deliberately not involved. We run BRouter for route planning, and it would be the obvious tool here. It is the wrong one. A router's job is to find a good way from A to B, so given your track it would produce a route it likes, which is not the same thing as the route you rode. It would smooth away the odd detour, refuse the closed road you actually used, and quietly move the turns to justify itself. The whole promise of this feature is that the line stays where you put it, so nothing is routed. The intelligence is in your track already.
Road names and surface are free once the matching is done. Each returned road carries the full set of tags OpenStreetMap holds for it, so once we know which road you were on at each point we also know what it is called and what it is made of, with no second request. As it happens BRouter could not have supplied the names anyway: it decodes only the tags it prices, and a road's name is not one of them.
Turns come from the shape of the matched line, not from the roads it crosses. OpenStreetMap splits a road at every bridge, surface change and parish boundary, so treating each handover as a turn gives about four instructions per kilometre. Instead the angle is measured over a fixed distance either side of each point, a corner spanning several points collapses to its sharpest, and a bend that leaves you on the same road has to be severe before it earns a word.
The whole thing takes about a second on a fifty kilometre ride, and needs one request.
The roundabout that went the wrong way
Worth telling in full, because the bug was not the one it looked like and the fix says something about how the whole thing works.
A rider in Belgium sent this in. His recording, the wide green line, went round a small roundabout the way the law requires: anti-clockwise, the long way round the west side. Our matched line, the thin red one, cut down the east side against the traffic.
Before:

After:

Same ride, same roundabout, same view. The obvious explanation is that we were not reading the one-way tag. That was true. It was also not the cause.
A roundabout carries no one-way tag. junction=roundabout implies it, and mappers rely on that, so anything reading only oneway sees a two-way ring. Fine, we could read the implication. But adding that alone would not have fixed it, because of something more basic.
The legal way round was not a candidate at any price. When the matcher crosses a short connecting way between two fixes, it works out how far it travelled along that way by subtracting one offset from the other. On a way that closes on itself, that subtraction can only ever describe the arc that does not cross the join. The other side of the ring is not expensive, it is unreachable. This particular roundabout is 6.3 metres in radius: the wrong way round is 13.2 metres and the legal way is 26.7, and the matcher took the only one it could see.
Once both arcs are on the table, the fix mostly makes itself. The track is sampled every 20 metres, and 26.7 metres is a much better fit to a 20 metre step than 13.2 is. The right answer wins on its own merits.
No, you do not need to tell it which side of the road you drive on
The reasonable next question, and the answer is a nice one: OpenStreetMap already knows, per roundabout, without anybody tagging it. A roundabout is drawn in the direction traffic flows around it, so in a right-hand-traffic country the way runs anti-clockwise and in a left-hand-traffic country it runs clockwise. We checked 76 roundabout ways:
| Place | Drives on | Roundabouts | Direction |
|---|---|---|---|
| Sint-Pieters-Leeuw, Belgium | right | 9 | all anti-clockwise |
| Utrecht, Netherlands | right | 6 | all anti-clockwise |
| Swindon, UK | left | 16 | all clockwise |
| Milton Keynes, UK | left | 45 | all clockwise |
A setting would be redundant at best, and wrong on a ride that crosses a border.
A penalty, never a rule
Direction is now read, including oneway=-1 and the contraflow cycling lanes that are ordinary and signed across Belgium and the Netherlands, where oneway:bicycle=no cancels it. Charging a rider for using a lane they were entitled to use would push their line onto a detour they never took, which is a worse failure than the shortcut being fixed.
And going the wrong way costs something rather than being forbidden, which matters more than it sounds. On that 6.3 metre roundabout the two arcs are never more than 12.6 metres apart, which in the cost model is less than the wrong way costs, so the map decides. That is the right answer when the geometry has nothing to say. Make the roundabout six times bigger and the fixes say plainly which arc the rider was on, and the track wins again. The map is a tiebreaker, not an authority. It has to be, because the entire promise is that your line stays where you rode it.
Where it disagrees with you
It follows your track. It does not tidy it. If you detoured to the shops, so does the matched line.
But sometimes it cannot follow, and it says so rather than hiding it. Every place the two lines part company for a meaningful distance is listed and marked with a numbered pin.

That one is a walking trail crossing ground where the mapped path and the walked line genuinely differ. Worth a look before you rely on it, which is exactly what the panel says.
Gotchas, honestly
This is alpha and it has rough edges we already know about.
- Your climbing figure will probably drop a little. A line rebuilt from fewer, road-anchored points counts less GPS wobble as ascent. On that 44 km ride it went from 460 m to 424 m. The hills have not changed and neither has your ride; the noise has. Both figures are shown, and neither is offered as a correction to the other.
- Unmapped ground is left alone. A beach, a ferry, a path nobody has mapped: where there is no road within reach, your recording is kept exactly as it was for that stretch and the panel says how much. On a 134 km mountain trail that was 5.71 km.
- Paths give you a lot of turns. A footpath junction is a real junction, and a wiggly one bends constantly. That same trail produces 287 instructions where a road route of the same length would give perhaps 80. Level of detail helps; it does not make a footpath behave like a road.
- Surface data is patchy. 70% on a British road ride is normal. In some countries it will be far less.
- Turns from an imported navigation file cannot be edited, only ones we generated. That file is re-exported exactly as it arrived, so editing the list would change what you see and not what you get.
- It matches the whole track, not a section of it. If only one wooded stretch drifted, you still rematch the lot. Edit Track remains the tool for a single stretch.
Two things we have measured but not built
Both of these are known, both are real, and both are sitting in reserve rather than shipped. We would rather wait for evidence from other people's files than tune a matcher against our own rides until it fits them perfectly and nothing else.
It does not know what you were riding. The preference for a road over the footpath beside it is currently the same whether you were on a motorbike or on foot, so a motorbike route can come out on a stretch of cycleway. On a set of four Belgian motorbike routes this was 160 metres out of 42 kilometres on one of them and nothing at all on the other three. Worth fixing, not worth guessing at: the fix is to let the matcher know the vehicle, and we would like to see more cases first.
Your GPS may be more accurate than the map. Where a recording runs a few metres to one side of a road for a stretch, the natural assumption is a wobbly receiver. It often is not. On one 44 kilometre ride the offset across the whole route averaged 8 centimetres, so there is no global bias at all, but 13 of 55 windows along it were systematically offset, the worst by 13 metres with only 3 metres of scatter. That tightness is the interesting part: the fixes are tracking the shape of the road faithfully while sitting beside it, which is at least as likely to mean the road is drawn in the wrong place as that the receiver is wandering. Roads traced from slightly offset aerial imagery are common.
Correcting for it would help exactly where this feature is weakest, because a path running parallel to a road looks closer than the road when everything is displaced. It would also be easy to get wrong: you need the match to estimate the offset and the offset to make the match, and a confident first mistake would harden into a confident second one. So it waits.
Something we did rule out along the way, in case it saves you the thought: bearing cannot separate a road from the path beside it, because a parallel path has the same bearing. We tried it. Only position, or the consistency of position, tells them apart.
Send us the ones it gets wrong
This is the part we would genuinely like help with.
Map matching is easy to demonstrate and hard to finish. It is tested against real rides across England, Belgium and Wales, on road bikes, motorbikes and on foot, and it will still meet a road layout that defeats it: a parallel cycle track it picks in preference to the road, a dual carriageway taken the wrong way round on an out-and-back, a tunnel, a ferry, a housing estate rebuilt since the map last saw it.
If you run a track through it and the result is wrong, we want that file. A GPX or FIT and one sentence about what it should have done is enough. Those are worth more than any amount of synthetic testing, because the cases that break a matcher are never the ones you would think to invent.
Match to Roads is in the Route menu and the sidebar "..." menu, marked Alpha. Your recording is never altered, so there is nothing to lose by trying it. The help guide has the full description, and the rest of the help covers everything else PitStopper does with a route.


