MapMatch output does not lie on OSM graph?


I am writing a paper that involves studying GPS data, only instead of looking at the actual GPS points, we want to view GPS traces as paths on the road network graph. To do this I am trying to transform raw gps data into a list of edges of OSM that are covered by the points.
My first step has been to use Graphhopper to mapmatch my trajectories to OSM. (I used the web app rather than importing the graphhopper library as the rest of my code is not in Java.). Now, I am trying to, for each mapmatched point, find on which graph edge it lies. However, it seems that not every mapmatched point actually lies on the map. It seems like most points are OSM vertices, but some points are up to 100 meters away from the nearest vertex, and also do not seem to lie in the interior of an edge. I’m not sure if there is documentation somewhere that explains the structure of the output of graphhopper, but I can’t find it so I’m asking here. Are all output points required to lie on the graph? Or are other points allowed (like maybe points of the original input that lie “close enough” to an edge, or whatever).

For full clarity: I am mapmatching on the OSM map of Zuid-Holland, the Netherlands, downloaded from I further trimmed this map using Osmosis, leaving only the edges marked in osm as a highway and between latitude 51.969619-52.138908 and longitude 4.421357-4.873424

For context, here are some screenshots. The blue path is graphhopper output, the red path is what you get when all vertices of the blue path get matched to the closest OSM vertex, and the vertices are then connected by shortest path in the graph. Graphhopper does some sort of smoothing?

Could it have something to do with how OSM is approached? When I load OSM in my own code I break down each “way” in OSM to edges, where there will be an edge for every consecutive pair of measured points. Does graphhopper smooth ways before they are converted into edges?