Integrate A-to-B route planning, turn-by-turn navigation, route optimization, isochrone calculations, location clustering and other tools into your application.
Integrate A-to-B route planning, turn-by-turn navigation, route optimization, isochrone calculations, location clustering and other tools into your application.
Authenticate to the API by passing your key as a query parameter in every request.
You can also try all API parts without registration in our API explorer.
To speed up development and make coding easier, we offer a JavaScript client and a Java client.
You should utilize the SSL session to speed up responses after the initial response or use a library that does this. E.g. for Java the OkHttp library automatically reuses SSL/TLS sessions and also the browser takes care of this automatically. For python you can use the requests
library: first you create a session (session = requests.Session()
) and then do requests only with this session instead of directly using "requests".
If you create your own client, make sure it supports http/2 and gzipped responses for best speed. If you use the Matrix, the Route Optimization API or the and want to solve large problems, we recommend you to reduce bandwidth by compressing your POST request and specifying the header as follows: Content-Encoding: gzip
. This will also avoid the HTTP 413 error "Request Entity Too Large".
The default data source is OpenStreetMap and as an alternative we have also integrated TomTom.
The Route Optimization API can be used to solve traveling salesman or vehicle routing problems. You can use our API Explorer to explore Route Optimization. If you have successfully solved the first problem, we recommend this tutorial - Getting Started with the Optimization API. It shows and describes the essential elements to model your vehicle routing problem.
Further reading:
The Routing API calculates the best path connecting two or more points, where the meaning of ''best'' depends on the vehicle profile and use case. Besides path coordinates it can return turn-by-turn instructions, elevation, path details and other useful information about the route.
Use our API Explorer to explore the Routing API.
Geocoding describes the process of transforming an textual address representation to a coordinate (latitude,longitude
). For example the conversion from Berlin
to 52.5170365,13.3888599
.
Reverse geocoding converts a coordinate to a textual address representation or place name. Find out more about Geocoding itself on Wikipedia.
An isochrone of a location is ''a line connecting points at which a vehicle arrives at the same time'', see Wikipedia. With the same API you can also calculate isodistances, just use the parameter distance_limit instead of time_limit`.
Some possible areas in which this API may be useful to you:
See the clients section in the main documentation, and our API explorer.
You can snap measured GPS points typically as GPX files to a digital road network to e.g. clean data or attach certain data like elevation or turn instructions to it.
See the clients section in the main documentation, and our API explorer.
The cost for one request depends on the number of GPS location and is documented here.
One request should not exceed the Map Matching API location limit depending on the package, see the pricing in our dashboard.
It solves the “capacity clustering problem” by assigning a set of customers to a given number of distinct groups (called clusters). The API “clusters” by minimizing the total distance from each individual customer to its designated group median. It can also consider minimum and maximum capacity restrictions for each group.
Clustering can be used in many practical applications. For example, it can help to plan territories, i.e. territory optimization for field teams with large territories for field workers, or to solve large vehicle routing problems (VRP).
Try Clustering in our API Explorer!
The idea is to divide a certain number of customers, a pre-specified number of clusters. As already written above, a distribution is sought that minimizes the total cost (e.g. distance or time or a function of distance and time). We currently support two approaches.
You can simply define a certain number of clusters via configuration ("clustering" with empty set of "clusters") and additionally how many customers should be in such a cluster. This is defined by an upper and lower limit ("min_quantity" and "max_quantity). The algorithm then searches for suitable clusters and divides the customers into these clusters.
You can explicitly define clusters via "clusters". In this way, each individual cluster can be defined. This approach not only allows each cluster to have its own capacity upper and lower bound, but each cluster can also be assigned a fixed cluster center. In contrast to 1. the algorithm then does not search for a suitable center, but assigns the customers given the fixed centers to each cluster. Note that if you define clusters explicitly, any configuration of "clustering" will be overwritten by these explicit clusters.
A custom model allows you to modify the default routing behavior of a vehicle profile by specifying a set of rules in JSON language. There are three JSON properties to change a profile: priority
, speed
and distance_influence
that are described in great detail in the next sections and you can get a quick overview in this example-driven blog post.
But first we will give an introductory example for each of these JSON properties. Let's start with speed
:
{
"speed": [{
"if": "road_class == MOTORWAY",
"limit_to": "90"
}]
}
As you might have already guessed this limits the speed on motorways to 90km/h. Changing the speed will of course change the travel time, but at the same time this makes other road classes more likely as well, so you can use this model to avoid motorways.
You can immediately try this out in the Browser on GraphHopper Maps. GraphHopper Maps offers an interactive text editor to comfortably enter custom models. You can open it by pressing the "custom" button. It will check the syntax of your custom model and mark errors in red. You can press Ctrl+Space or Alt+Enter to retrieve auto-complete suggestions. Pressing Ctrl+Enter will send a routing request for the custom model you entered. To disable the custom model you click the "custom" button again.
In the second example we show how to avoid certain road classes without changing the travel time:
{
"priority": [{
"if": "road_class == LIVING_STREET || road_class == RESIDENTIAL || road_class == UNCLASSIFIED",
"multiply_by": "0.1"
}]
}
This example avoids certain smaller streets. View it in GraphHopper Maps.
The third example shows how to prefer shortest paths:
{
"distance_influence": 200
}
View this example in GraphHopper Maps.
There is a fourth JSON property areas
that allows you to define areas that can then be used in the if
or else_if
conditions for speed
and priority
. Please read more about this and the other properties below and try some examples in GraphHopper Maps with the help of this blog post.
When using custom models you do not need to define rules that specify a speed for every road segment, but rather GraphHopper assumes a default speed. All you need to do is adjust this default speed to your use-case as you will always use the custom model in conjunction with a routing profile which is used to determine the default speed.
The custom model is a JSON object and the first property we will learn about here is the speed
property. The speed
property's value is a list of conditional statements that modify the default speed. Every such statement consists of a condition and an operation. The different statements are applied to the default speed from top to bottom, i.e. statements that come later in the list are applied to the resulting value of previous operations. Each statement is only executed if the corresponding condition applies for the current road segment. This will become more clear in the following examples.
Currently the custom model language supports two operators:
multiply_by
multiplies the speed value with a given numberlimit_to
limits the speed value to a given numberLet's start with a simple example using multiply_by
:
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
}
]
}
This custom model reduces the speed of every road segment for which the road_class
attribute is MOTORWAY
to fifty percent of the default speed (the default speed is multiplied by 0.5
). Again, the default speed is the speed that GraphHopper would normally use for the profile's vehicle. Note the if
clause which means that the operation (multiply_by
) is only applied if the condition road_class == MOTORWAY
is fulfilled for the road segment under consideration. The ==
indicates equality, i.e. the condition reads "the road_class equals MOTORWAY". If you're a bit familiar with programming note that the condition (the value of the if
key) is just a boolean condition in Java language (other programming languages like C or JavaScript are very similar in this regard). A more complex condition could look like this: road_class == PRIMARY || road_class == TERTIARY
which uses the or (||
) operator and literally means "road_class equals PRIMARY or road_class equals TERTIARY".
There can be multiple such 'if statements' in the speed section, and they are evaluated from top to bottom:
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
},
{
"if": "road_class == PRIMARY || road_environment == TUNNEL",
"multiply_by": "0.7"
}
]
}
In this example the default speed of road segments with road_class == MOTORWAY
will be multiplied by 0.5
, the default speed of road segments with road_class == PRIMARY
will be multiplied by 0.7
and for road segments with both road_class == MOTORWAY
and road_environment == TUNNEL
the default speed will be multiplied first by 0.5
and then by 0.7
. So overall the default speed will be multiplied by 0.35
. For road segments with road_class == PRIMARY
and road_environment == TUNNEL
we only multiply by 0.7
, even though both parts of the second condition apply. It only matters whether the road segment matches the condition or not.
road_class
and road_environment
are road attributes of 'enum' type, i.e. their value can only be one of a fixed set of values, like MOTORWAY
for road_class
.
Other road attributes like road_class_link
are of boolean
type. They can be used as conditions directly, for example:
{
"speed": [
{
"if": "road_class_link",
"multiply_by": "0.6"
}
]
}
which means that for road segments with road_class_link==true
the speed factor will be 0.6
.
For attributes with numeric values, like max_width
you should not use the ==
(equality) or !=
( inequality) operators, but the numerical comparison operators "bigger" >
, "bigger or equals" >=
, "smaller" <
, or "smaller or equals" <=
, e.g.:
{
"speed": [
{
"if": "max_width < 2.5",
"multiply_by": "0.8"
}
]
}
which means that for all road segments with max_width
smaller than 2.5m
the speed is multiplied by 0.8
.
Besides the multiply_by
operator there is also the limit_to
operator. As the name suggests limit_to
limits the current value to the given value. Take this example:
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.8"
},
{
"if": "surface == GRAVEL",
"limit_to": "60"
}
]
}
This implies that on all road segments with the GRAVEL
value for surface
the speed will be at most 60km/h
, regardless of the default speed and the previous rules. So for a road segment with road_class == MOTORWAY
, surface == GRAVEL
and default speed 100
the first statement reduces the speed from 100
to 80
and the second statement further reduces the speed from 80
to 60
. If the road_class
was PRIMARY
and the default speed was 50
the first rule would not apply and the second rule would do nothing, because limiting 50
to 60
still yields 50
.
A common use-case for the limit_to
operation is the following pattern:
{
"speed": [
{
"if": "true",
"limit_to": "90"
}
]
}
which means that the speed is limited to 90km/h
for all road segments regardless of its properties. The condition "true
" is always fulfilled.
The else
statement allows you to define that some operations should be applied if an road segment does not match a condition. So this example:
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
},
{
"else": "",
"limit_to": "50"
}
]
}
means that for all road segments with road_class == MOTORWAY
we multiply the default speed by 0.5
and for all others we limit the default speed to 50
(but never both).
In case you want to distinguish more than two cases (road segments that match or match not a condition) you can use else_if
statements which are only evaluated in case the previous if
or else_if
statement did not match:
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
},
{
"else_if": "road_environment == TUNNEL",
"limit_to": "70"
},
{
"else": "",
"multiply_by": "0.9"
}
]
}
So if the first condition matches (road_class == MOTORWAY
) the default speed is multiplied by 0.5
, but the other two statements are ignored. Only if the first statement does not match (e.g. road_class == PRIMARY
) the second statement is even considered and only if it matches (road_environment == TUNNEL
) the default speed is limited to 70. The last operation (multiply_by: "0.9"
) is only applied if both previous conditions did not match.
else
and else_if
statements always require a preceding if
or else_if
statement. However, there can be multiple 'blocks' of subsequent if/else_if/else
statements in the list of rules for speed
.
else_if
is useful for example in case you have multiple multiply_by
operations, but you do not want that the speed gets reduced by all of them. For the following model
{
"speed": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
},
{
"else_if": "road_environment == TUNNEL",
"multiply_by": "0.8"
}
]
}
only the first factor (0.5
) will be applied even for road segments that fulfill both conditions.
You can not only modify the speed of road segments based on properties, like we saw in the previous examples, but you can also modify the speed of road segments based on their location. To do this you need to first create and add some areas to the areas
section of the custom model. You can then use the name of these areas in the conditions of your if/else/else_if
statements.
In the following example we multiply the speed of all road segments in an area called custom1
with 0.7
and also limit it to 50km/h
. Note that each area's name needs to be prefixed with in_
:
{
"speed": [
{
"if": "in_custom1",
"multiply_by": "0.7"
},
{
"if": "in_custom1",
"limit_to": "50"
}
],
"areas": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"id": "custom1",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
1.525,
42.511
],
[
1.510,
42.503
],
[
1.531,
42.495
],
[
1.542,
42.505
],
[
1.525,
42.511
]
]
]
}
}]
}
}
Areas are given in GeoJson format (FeatureCollection). Currently a member of this collection must be a Feature
with a geometry type Polygon
. Note that the coordinates array of Polygon
is an array of arrays that each must describe a closed ring, i.e. the first point must be equal to the last, identical to the GeoJSON specs. Each point is given as an array [longitude, latitude], so the coordinates
array has three dimensions total.
Using the areas
feature you can also block entire areas i.e. by multiplying the speed with 0
, but for this you should rather use the priority
section that we will explain next.
Make sure you read the introductory section of this document to learn what the priority
factor means. In short it allows similar modifications as speed
, but instead of modifying the road segment weights and travel times it will only affect the weights. By default, the priority is 1
for every road segment, so it does not affect the weight. However, changing the priority of a road can yield a relative weight difference in comparison to other roads.
Customizing the priority
works very much like changing the speed
, so in case you did not read the section about speed
you should go back there and read it now. The only real difference is that there is no limit_to
operator for priority
. As a quick reminder here is an example for priority:
{
"priority": [
{
"if": "road_class == MOTORWAY",
"multiply_by": "0.5"
},
{
"else_if": "road_class == SECONDARY",
"multiply_by": "0.9"
},
{
"if": "road_environment == TUNNEL",
"multiply_by": "0.1"
}
]
}
means that road segments with road_class==MOTORWAY
and road_environment==TUNNEL
get priority 0.5*0.1=0.05
and those with road_class==SECONDARY
and no TUNNEL, get priority 0.9
and so on.
Edges with lower priority values will be less likely part of the optimal route calculated by GraphHopper, higher values mean that these road segments shall be preferred. If you do not want to state which road segments shall be avoided, but rather which ones shall be preferred, you need to decrease the priority of others:
{
"priority": [
{
"if": "road_class != CYCLEWAY",
"multiply_by": "0.8"
}
]
}
means decreasing the priority for all road_classes except cycleways.
Just like we saw for speed
you can also adjust the priority for road segments in a certain area. It works exactly the same way:
{
"priority": [
{
"if": "in_custom1",
"multiply_by": "0.7"
}
]
}
To block an entire area set the priority value to 0
. You can even set the priority only for certain roads in an area like this:
{
"priority": [
{
"if": "road_class == MOTORWAY && in_custom1",
"multiply_by": "0.1"
}
]
}
Some other useful attributes to restrict access to certain roads depending on your vehicle dimensions are the following:
{
"priority": [
{
"if": "max_width < 2.5",
"multiply_by": "0"
},
{
"if": "max_length < 10",
"multiply_by": "0"
},
{
"if": "max_weight < 3.5",
"multiply_by": "0"
}
]
}
which means that the priority for all road segments that allow a maximum vehicle width of 2.5m
, a maximum vehicle length of 10m
or a maximum vehicle weight of 3.5tons
, or less, is zero, i.e. these "narrow" road segments are blocked.
The distance_influence
property allows you to control the trade-off between a fast route (minimum time) and a short route (minimum distance). The larger distance_influence
is the more GraphHopper will prioritize routes with a small total distance. More precisely, the distance_influence
is the time you need to save on a detour (a longer distance route option) such that you prefer taking the detour compared to a shorter route. Please note that this value is a number, not a string.
A value of 100
means that one extra kilometer of detour must save you 100s
of travelling time or else you are not willing to take the detour. Or to put it another way, if a reference route takes 600s
and is 10km
long, distance_influence=100
means that you are willing to take an alternative route that is 11km
long only if it takes no longer than 500s
(saves 100s
). Things get a bit more complicated when priority
is not 1
, but the effect stays the same: The larger distance_influence
is, the more GraphHopper will focus on finding short routes.
GraphHopper stores different attributes for every road segment. Some frequently used are the following (some of their possible values are given in brackets):
MISSING
or the country as a ISO3166-1:alpha3
code e.g. DEU
)To learn about all available encoded values you can query the /info
endpoint
Besides this kind of categories, which can take multiple different string values, there are also some that represent a boolean value (they are either true or false for a given road segment), like:
There are also some that take on a numeric value, like:
sac_scale
in OSM, e.g. 0 means "missing", 1 means "hiking", 2 means "mountain_hiking" and so onsum(distance_i)=edge_distance
. Important for longer road segments where ups (or downs) can be much bigger than the average_slope.You can directly use custom models with the POST Route Endpoint.
To use custom models with the Route Optimization API or the Matrix API, use the Profiles API to create a new named profile with your custom model. You can then use that profile like you would use a pre-defined profile.
This feature will strongly benefit from feedback, so do not hesitate to share your experience, your favorite custom model or some of the problems you ran into when you tried building your own custom model.
For debugging you can use the custom model editor in GraphHopper Maps (click the 'gear' button in the top left).
When debugging problems with custom models you should first try if your request goes through without an error using an empty custom model.
The route calculation with custom_models will be slower as a different algorithm has to be used. The more the result deviates from the optimum the slower the response can get. Still for certain use cases you can make the calculation faster when you tune the custom_model and e.g. exclude certain ways via { "if": "road_class == TRACK || road_class == RESIDENTIAL", "multiply_by": "0" }
.
This could mean that either your custom model made some of the roads near the start and destination inaccessible, then usually we return a PointNotFoundException with the point_index with the "location snap" problem.
Or, the custom model made a route between your start and destination impossible, then we return a ConnectionNotFoundException. This happens e.g. when you exclude tunnels, ferries or motorways but all routes between start and destination have these road attributes satisfied, i.e. we cannot find a route.
Solution for both cases: relax your custom model and e.g. instead of excluding certain road attributes via "multiply_by": "0"
you should try to use "0.01"
.
You can create routing profiles that are customized to your needs. You can take advantage of all the modelling options described in the Custom Model section and use the created custom profile (prefix cp_
) with our Routing, Matrix and Route Optimization APIs.
Important notes
car
, bike
, foot
and ecargobike
. Contact us if you have different requirements. Motor vehicles can be emulated like done for truck
in this post.A curl example:
curl -X POST -H "Content-Type: application/json" "https://graphhopper.com/api/1/profiles?key=YOUR_KEY" -d '{"bounds":{"bbox":[11.45462,48.00954,11.77322,48.2076]},"custom_model":{"priority":[{"if":"road_class == MOTORWAY","multiply_by":"0"}]},"profile":"car"}'
If you plan to tweak your custom_model frequently it is recommended to initially use the Routing API where a different custom model can be specified in every request. Or use GraphHopper Maps and click the gear button.
Creating custom profiles using the API Explorer
Besides using the /profiles
endpoint directly you can also create custom profiles from our API explorer.
id
from the output window (it starts with cp_
)."profile": "car"
(vehicle_types
section) with the profile id
and click "Send":You should now see that the solution no longer uses motorways. Keep in mind that this is a simple example. The custom model language is a lot more powerful than this. Make sure you read the Custom Model section to learn about all the details.
Note that you can use the profile id
just as well for the /matrix
or /route
endpoint. E.g. select "Routing API" and use the profile id
in the request: