On this page
Routes
A route is a line on the map with a marker and label at each end. There are three ways to get the line:
- You provide it: a GeoJSON line or an encoded polyline.
- The server draws it locally:
straightsegments or ageodesicgreat circle between your points. - A routing engine computes it:
car,bikeorfootalong real roads.
GET describes one route. POST takes up to 10 in routes, plus extra lines and polygons in shapes. Without an area, the map is framed on the routes and points, so a route alone is a complete request.
A line you already have#
If you route elsewhere, send the result. As GeoJSON (POST):
/v1/map{
"routes": [
{
"geometry": {
"type": "LineString",
"coordinates": [[16.6068, 49.1951], [16.9, 49.24], [17.2, 49.23], [17.6667, 49.2266]]
},
"start": { "label": "Brno" },
"finish": { "label": "Zlín" }
}
],
"width": 480,
"height": 280
}
Or as an encoded polyline (Google algorithm). Precision 5 is the default; Valhalla and OSRM use 6, which you set with polylineprecision. URL-encode the polyline: it can contain @, {, | and other characters that mean something in a URL.
/v1/map.pngGET /v1/map.png?polyline=klgkHoojdBswGogx%40n%7D%40_ry%40fT%7BczA&fromlabel=Brno&tolabel=Zlín&w=480&h=280
Parameters: polyline, polylineprecision.
Straight and geodesic lines#
profile=straight connects from, the via points and to with straight segments. profile=geodesic follows the great circle, which is what you want for flights. Neither needs a routing engine. geodesic is the default, so a route without profile always renders; road routes need an explicit profile=car, bike or foot.
from, to and via take lat,lon or place:Name. Repeat via for more waypoints; they are visited in order.
/v1/map.pngGET /v1/map.png?from=49.1951,16.6068&to=49.2266,17.6667&via=49.24,16.9&profile=straight&fromlabel=Brno&tolabel=Zlín&w=480&h=280
/v1/map.pngGET /v1/map.png?from=50.1,14.26&to=40.64,-73.78&profile=geodesic&fromlabel=Prague&tolabel=New+York&routedash=2,1.5&w=520&h=300
With place names, the start and finish labels default to the names, so from=place:Brno&to=place:Zlín is already labeled.
/v1/map.pngGET /v1/map.png?from=place:Brno&to=place:Zlín&profile=straight&w=480&h=280
The same in POST, with a title and a point of interest on the way:
/v1/map{
"routes": [
{
"from": { "lat": 40.4168, "lon": -3.7038 },
"to": { "lat": 37.3891, "lon": -5.9845 },
"via": [{ "lat": 38.98, "lon": -3.93 }, { "lat": 38.25, "lon": -4.75 }],
"profile": "straight",
"start": { "label": "Madrid" },
"finish": { "label": "Seville" }
}
],
"pois": [
{ "lat": 39.42, "lon": -3.78, "label": "Crash Site\n(near Urda)", "labelWeight": 700,
"marker": { "shape": "dot", "size": 16, "strokeColor": "#000000", "strokeWidth": 2 } }
],
"title": { "text": "Madrid – Seville" },
"width": 500,
"height": 440
}
Routed profiles (car, bike, foot)#
car, bike and foot ask a routing engine for a real route. This needs one of:
- A configured server. The operator points
WHEREBOX_VALHALLA_URLat a Valhalla instance, or sets a key for openrouteservice or GraphHopper. See the configuration reference and Self-hosting. With nothing configured, a routed profile returns400 bad-request. - Your own key. For openrouteservice and GraphHopper, send your key in the
X-Routing-Keyrequest header, and choose the provider withrouteprovider(GET) orprovider(POST). LikeX-Provider-Key, the header keeps the secret out of URLs and logs, and is scrubbed from error messages.
If the provider finds no route you get 422 no-route; if it is down or slow, 502 or 504 (Errors and limits). Public routing demo servers are rate-limited and not for production use.
This request is parsed but not rendered in the docs build, because it needs a routing engine:
/v1/map{
"routes": [
{
"from": { "place": "Brno" },
"via": [{ "place": "Jihlava" }],
"to": { "place": "Praha" },
"profile": "car",
"provider": "openrouteservice"
}
],
"width": 480,
"height": 320
}Send it with the key in a header, for example curl -H 'Content-Type: application/json' -H 'X-Routing-Key: YOUR_KEY' --data @route-car.json https://YOUR-HOST/v1/map -o route.png, where route-car.json holds the body above.
The response's meta (with ?response=json) includes the routed distance and duration per route.
Via points#
via forces the route through intermediate points, in order, up to 20. In GET repeat the parameter; in POST use an array of endpoints. The straight example above uses one via point. For routed profiles each via point becomes a waypoint the engine must pass.
Styling the line#
Color, width, dash pattern and opacity of the line, and a casing (an outline under the line that helps it read on busy basemaps):
/v1/map.pngGET /v1/map.png?from=49.1951,16.6068&to=49.2266,17.6667&profile=straight&routecolor=%231565c0&routewidth=4&routedash=2,1.5&routeopacity=0.9&fromlabel=Brno&tolabel=Zlín&w=480&h=280
Parameters: routecolor, routewidth, routedash, routeopacity, routecasing.
Start and finish#
Each end gets a marker and a label. By default the start is a ring and the finish a flag (see markers), labeled with the place name if you gave one. Change the label or marker, or hide an end:
/v1/map.pngGET /v1/map.png?from=49.1951,16.6068&to=49.2266,17.6667&profile=straight&fromlabel=Start&tolabel=Finish&frommarker=dot&tomarker=pin&w=480&h=280
/v1/map.pngGET /v1/map.png?from=49.1951,16.6068&to=49.2266,17.6667&profile=straight&showfrom=false&tolabel=Zlín&w=480&h=280
Parameters: fromlabel, tolabel, frommarker, tomarker, showfrom, showto. In POST these are start and finish objects with the full marker and label options.
Route plus area#
A route on its own frames itself. Add an area to keep the locator look and frame the whole area instead:
/v1/map{
"area": "Zlínský kraj",
"routes": [
{
"from": { "place": "Zlín" },
"to": { "place": "Kroměříž" },
"profile": "straight",
"color": "#d01c1c"
}
],
"width": 420,
"height": 300
}
Forcing the frame with bounds#
bounds=west,south,east,north fixes the frame, overriding automatic framing. Use it to keep a series of maps at the same zoom, or to show context around a short route.
/v1/map.pngGET /v1/map.png?from=49.1951,16.6068&to=49.2266,17.6667&profile=straight&bounds=15.5,48.6,18.5,49.8&w=480&h=280
See bounds.
Globe projection#
Web Mercator stretches everything away from the equator: Greenland looks the size of Africa, and a flight from Alaska to Europe bends into a long arc. For routes that span continents, projection=globe draws an orthographic globe centered on your content instead. Shapes keep their true proportions, and great-circle legs look like the shortest paths they are.
/v1/map.pngGET /v1/map.png?from=64.5011,-165.4064&to=52.52,13.405&via=47.6062,-122.3321&via=40.7128,-74.0060&profile=geodesic&fromlabel=Nome&tolabel=Berlin&poi=47.6062,-122.3321|label:Seattle|marker:dot&poi=40.7128,-74.0060|label:New+York|marker:dot&projection=globe&w=600&h=420
By default the whole globe is shown, centered on your content, so the map reads as a globe at a glance. The same request without projection=globe gives the familiar Mercator map, with Greenland inflated and the route curving far north.
Whole globe or zoomed in#
globeview=fit zooms in until the content fills the image. Only part of the globe is visible, but the route area gets a larger scale and more detail:
/v1/map.pngGET /v1/map.png?from=64.5011,-165.4064&to=52.52,13.405&via=47.6062,-122.3321&via=40.7128,-74.0060&profile=geodesic&fromlabel=Nome&tolabel=Berlin&poi=47.6062,-122.3321|label:Seattle|marker:dot&poi=40.7128,-74.0060|label:New+York|marker:dot&projection=globe&globeview=fit&w=600&h=420
Which one to use:
full(default) when the point is where on Earth the route goes: a flight across the Pacific, an expedition, a world tour. Everyone recognizes a globe.fitwhen the route itself matters more than the planet: its exact path, the labels along it, smaller images where every pixel counts.
In JSON the same option is "globe": { "view": "fit" }.
projection=auto decides for you: the globe when the content spans a large part of the Earth or would be stretched a lot by Mercator, Mercator otherwise (the thresholds are in the projection reference). A country-sized map stays Mercator, and when auto picks the globe it shows the whole globe unless you pass globeview=fit.
Things to know:
- Everything framed must fit on one side of the globe. Content too spread out for that is a
400 bad-request; split it into several maps. - Neighbor labels are not available on the globe yet.
- Markers, labels and route lines are drawn directly on the globe, so they stay sharp. The basemap is rendered as a flat map and wrapped onto the sphere, so its finest lines get slightly softer toward the globe's edge and near the poles.