New and improved bike routing, with low stress options

Bicyclists ride to commute, to exercise, for sport, for leisure. But no matter the reason, most cyclists will ride on the road at some point, and when they do, they’ll think about the safety and comfort of their route.

Should you take a longer route to ride on a road with a dedicated cycling lane? Do you take a left turn to avoid those difficult hills? Different cyclists will make different choices, as the ideal route for one bicyclist may not be so ideal for another.

Valhalla, the open-source routing engine that powers Mapzen Turn-by-Turn, has always had customization parameters. While these include use_roads and use_hills, setting these to zero didn’t quite define what most would consider a “low stress” bike route. At least not until now!

This summer, I and the Mapzen routing team enhanced Valhalla’s bicycle costing system. Not only is overall routing improved, but use_roads and use_hills are now much more versatile: when both of these parameters are set to 0, Valhalla generates a nice, “low-stress” biking route. As these parameters get closer to 1, it linearly increases to a more “professional” biking route.

Along with this new update, our default bike settings have also changed — use_roads and use_hills previously defaulted to 0.5, but now they default to 0.25. The default bike (and thus speed) has also been changed from a road bike to a hybrid bike, which is more suited for city riding.

Technical Details

The meat of this update is the added support for low-stress biking. Our original goal was to introduce a new “low-stress bike” costing class derived from the regular bike costing class. However, after doing this, we realized that the algorithms of the new LowStressBicycleCost class were actually cleaner and easier to manage than our original bike costing algorithms. This inspried us to rewrite the old bike code to look like the new low-stress bike code. This way, the use_roads and use_hills parameters acted as variables that scale the costs of edges (i.e. road segments) with particular attributes in a way that provides low-stress biking at one end of the spectrum, and professional road biking on the other.

When originally making the LowStressBicycleCost class, we made use of research by Michael B. Lowry at the University of Idaho, Peter Furth at Northeastern, and Tracy Hadden-Loh with the Rails-to-Trails Conservancy. Their paper titled “Low-Stress Neighborhood Bikeability Assessment to Prioritize Bicycle Infrastructure” provides a way to score a road based on how stressful it is to bike on. Here are the variables that are included in the score:

    stress_factor = accomodation_factor * road_stress
    edge_weight = 1.0 + stress_factor + slope_factor
  • accomodation_factor is a value between 0 and 1, where 0 means the road is very well accommodated for biking and 1 is not accomodated for biking.
  • road_stress represents how stressful it is to bike on the road due to things like road speed and lane count. This number can be greater than 1 — the higher it is, the more stressful the road segement.
  • Multiplying these two values gets the total_stress value which is added with the slope_factor and 1 to get edge_weight.
  • We multiply edge_weight at the end of our EdgeCost function to the estimated time it takes to travel the edge. This way, edges that have unfavorable attributes for our needs are less likely to be taken.

Due to the predictability this algorithm had over our previous one, we folded this code back into the original BicycleCost class and removed the LowStressBicycleCost class all together, leaving the control with use_roads and use_hills. As a result, our routing is better and our API has stayed simple and intuitive.


Here are a few examples of the “new and improved” versus the “old” bike routing (both with use_roads and use_hills set to 0).


Here the old bike route was skipping what is known as “The Wiggle” in San Francisco. The Wiggle is comprised of shared lanes in a zig-zag shape and is the flattest ways to move in that direction. With the low-stress settings, our new and improved bike routing now follows the entire Wiggle.


On this San Francisco route, the old system suggested taking Guerrero Street all the way to the right turn onto Cesar Chavez Street, but the new and improved system takes a shortcut through Tiffany Avenue, then onto the protected Valencia cycleway. While Guerrero has painted bike lanes, it is a very busy street with significant car traffic, while Tiffany Avenue is a numbered bike route, on a residential road classified as a “living street”. The new bike routing gives living streets and numbered routes much higher preference when calculating lower-stress routes.


In Arlington, Virginia, the old bike system here suggestes an odd zig-zag route to try and avoid busy streets like South Glebe Road. The new and improved biking system goes straight north, using a bike path and some residential roads to riders’ advantage. This is not only quicker but is also safer to ride.

Turn Costing

Turns are tricky business. In Valhalla, turns are penalized to a certain degree to keep routes from becoming ridiculous. However, with low-stress biking, there were certain areas (like the Wiggle and Tiffany Avenue) where we wanted more turns. In those situations, it’s worth taking a few more turns if it means you can ride along a nice dedicated cycle lanes or a calm side street.

So inside the transition costing, we had to penalize the turns onto low-stress roads a little less to allow more turns onto those roads. Still, we didn’t want to encourage too many unnecessary turns. After some tuning, we think we’ve struck a reasonable balance for turn costing.

(There aren’t similar issues with use_hills, since grade and elevation are calculated along edges, rather than at turning/transition nodes.)

Learn More

You can access the new and improved bike routes, as well as the “low-stress” options now in our Turn-by-Turn API and mapzen.js!

Or directly make an API request like this: {"costing":"bicycle","costing_options":{"bicycle":{"use_roads":0,"use_hills":0}},"directions_options":{"language":"en-US","units":"miles"},"locations":[{"lat":37.799201,"lon":-122.399584},{"lat":37.7431177,"lon":-122.424318}]}&api_key=your-mapzen-api-key

In mapzen.js, just tell the built-in router to use bicycle costing, and set use_roads and use_hills to 0 if you want the lowest-stress route.

            router = L.Mapzen.routing.control({
                waypoints: [
                router: L.Mapzen.routing.router('your-mapzen-api-key', {
                    costing: "bicyle",
                    costing_options: {
                        "bicycle": {
                            use_roads: 0,
                            use_hills: 0
                    directions_options: {
                        language: 'en-US',
                        units: 'miles'

Want to display your stress-free bike routes on an attractive map? Or want to browse bike lanes and paths, before you plan a particular trip? See Mapzen’s updated bike map.