Overpass API/Language Guide

From OpenStreetMap Wiki
Jump to navigation Jump to search

This guide shows you examples for queries to make to an Overpass API server: adapt the queries to your particular need.


Background and concepts

Overpass API allows you to query for OSM data by your own search criteria. For this purpose, it has two specifically crafted query languages: Overpass XML, and Overpass QL.

The basic semantics of Overpass API is that flows of OSM data (nodes, ways...) are generated and modified by statements, which are executed one after another. The following simple query can for instance generate a flow of data containing all the nodes in a given bounding box, and print it:

node(50.745,7.17,50.75,7.18);
out;

You can then filter further the resulting flow, looking only for the bus stops:

node(50.745,7.17,50.75,7.18)[highway=bus_stop];
out;

Or you could also extend the result to include the ways which are referencing using the selected nodes (using the (bn) "recurse back to nodes" clause). In this case, you may also want to extend the result with all nodes referenced by these ways (with the > "recurse down" operator):

node(50.745,7.17,50.75,7.18);way(bn);
( ._; >; );
out;

These statements and their syntax are described in more details below.

The Overpass API languages

Overpass API now offers its full expressive power within a single HTTP GET request. For this purpose, the new query language Overpass QL is introduced in parallel to the established XML query language. You can always convert between the two: just paste one of the examples below into this form. You can choose there to get the output in:

  • XML query format: this matches the XML form below in all the examples.
  • to pretty Overpass QL: this matches the Overpass QL form below.
  • to concise Overpass QL: this yields a one-line HTTP GET request for the same expression.

To execute the query, use the same form.

Overpass QL Basics

Examples of the QL syntax are provided below. The QL syntax is more concise than Overpass XML, and is to some extent similar to C-like programming languages. A statement always ends with a semicolon ";". Furthermore, a statement is either:

  • a query statement, starting with "node", "way", "relation", "rel" (short for "relation"), "nwr" (short for a union of node+way+relation) or one of the recursion query statements ">", ">>", "<", or "<<", or
  • an output statement, starting with "out".

Query statements consist of the type of object to be retrieved

 node
 way
 rel

and of at least one clause that described the object to be retrieved, e.g.

 ["name"="Berlin"]

to give e.g. this query

 node["name"="Berlin"];

which retrieves all nodes named Berlin.

Overpass QL clauses

There are different types of clauses that you can use:

  • to filter objects (nodes, ways, relations or Overpass areas) that are present in the input result set, or
  • to perform recursion queries on them in order to replace all of them by the union of all their recursively related objects.

All Overpass QL for filters (or recursion queries) can only be used after specifying a main query type (or .resultset), they are not queries by themselves.

Tag request clauses (or "tag filters")

All variants of tag requests; e.g.,

  ["key"]            /* filter objects tagged with this key and any value */
  [!"key"]           /* filter objects not tagged with this key and any value */
  ["key"="value"]    /* filter objects tagged with this key and this value */
  ["key"!="value"]   /* filter objects tagged with this key but not this value, or not tagged with this key */
  ["key"~"value"]    /* filter objects tagged with this key and a value matching a regular expression */
  ["key"!~"value"]   /* filter objects tagged with this key but a value not matching a regular expression */
  [~"key"~"value"]   /* filter objects tagged with a key and a value matching regular expressions */
  [~"key"~"value",i] /* filter objects tagged with a key and a case-insensitive value matching regular expressions */

Bounding box clauses ("bbox query", "bounding box filter")

Bounding box clauses (like all other clauses for filters or recursion queries) can only be used as filters after specifying a main query type (or .resultset), they are not queries by themselves. In the Overpass QL syntax, they have a form like in this example:

  /*your query here*/(51.0, 7.0, 52.0, 8.0)

Bounding box clauses always start with the lowest latitude (southernmost) followed by lowest longitude (westernmost), then highest latitude (northernmost) then highest longitude (easternmost). Note that this is different from the ordering in the XAPI syntax.

The Overpass XML syntax is safeguarded by using (more explicit) named parameters (but note that their name may still be misleading, as they still take negative values for all absolute coordinates in the southern or western hemispheres, and positive values for all absolute coordinates in the northern or eastern hemispheres):

  <query><!-- replace by an effective query type; if this element is missing, a default <query type="node"> is assumed -->
    <bbox-query s="51.0" w="7.0" n="52.0" e="8.0"/>
  </query><!-- replace by an effective query type -->

A bounding box spanning through the antimeridian (which would otherwise swap the two longitudes) is equivalent to an union of two subqueries for each side of the antimeridian. For example the long band which complements the previous bounding box over the same span of latitudes is equivalent to this union of queries on two bounding boxes (as this is a very large area covering too much data, this query will probably fail, unless the main queries include more selective filters such as tag filters):

  (
    /*your query here*/(51.0,  7.0, 52.0, 180); /* West side of the antimeridian (up to the positive longitude 180°E) */
    /*your query here*/(51.0, -180, 52.0, 8.0); /* East side of the antimeridian (from  the negative longitude 180°W) */
  );

Note that you must specify same the main query here (at least "node", "way", "rel", "area" or a ".namedresultset", optionally followed by other filters or recursions) in each subquery. Currently, the Overpass API offers no facility to make this transform automatically if you swap the longitudes; instead Overpass API returns an error if the first specified longitude is greater than the second longitude.

And it is still not possible to create a single compound filter containing an union of bounding boxes (or other polygonal shapes based on an ordered list of coordinates pair, or other disc shapes based on a the cordinates of a central node and a maximum radius, or exclusions based on a substraction of two simple or compound shapes). As well, the Overpass API offers no way to geometrically transform such simple or compound shapes using positive or negative buffers, in order to use more complex bounding filters: queries have to be repeated using different pretransformed simple shapes. For more details, see the sections below related to the supported unions of queries, and to (around: ...) or (poly: "...") special filters for other kinds of simple bounding shapes.

Area clauses ("area filters")

The "area" objects are not directly OSM objects, they are generated (and cached on the Overpass API server) by a batch running periodically on this server to process all new or modified data changes in the database, and look for non-node objects describing an enclosed surface; these objects include closed ways, or relations (notably "boundary" and "multipolygon" relations) whose members include one or more ways joined together to create closed "inner" or "outer" rings delimiting a surface. Overpass processes these objects in order to extract their geometry (and reconnect and order them appropriately in the case of relations) as a set of polygonal boundaries. The Overpass API server then stores the computed geometry, and associates them (by id) with the OSM way or relation object listing their tags; the batch also recognizes some naming tags that will be useful to identify them more easily.

Overpass "areas" are useful to avoid using explicit recursion queries and also as precomputed filters that won't return relations and ways that in fact don't enclose any area. But as they are generated by periodic batches, they may not reflect the most recent state of the OSM database (or even all the most recent diffs that are already received and stored in the Overpass API server). But they can greatly simplify and speedup the queries, notably for large surfaces with complex geometries, usually using "boundary" or "multipolygon" relations (such as boundaries of countries or their regional subdivisions, or the complex boundaries of large "landuse" or "natural" areas).

These areas can then be used as more selective bounding filters (instead of using simple bounding boxes), or can also be used themselves as queries (in which case they will return all nodes in the surface enclosed by the area geometry).

If areas are referenced by their internal id in Overpass (and that area has been included), any areas present in input set is ignored and only OSM objects in the input set that are intersecting with that specified area will be kept as is:

  (area:2400000001) /* filter objects in area whose surface is delimited by the way with id=1 in OSM */
  (area:3600000001) /* filter objects in area whose surface is delimited by ways members of the relation with id=1 in OSM */

The ids for precomputed Overpass areas are currently assigned by adding simply large static constants to the OSM id (provided that the associated OSM objects effectively enclose a surface).

Selecting areas by name

However areas are usually selected by running a separate special query (supported by the Overpass Turbo client) on their known naming tags for the OSM object they represent (Nominatim is used to process, recognize and index several naming tags, including tags for translated names) and storing the found areas into a named result set: any matching area with relevant tags will be stored in that named result set:

  {{geocodeArea:"United Kingdom"}}->.a; /* finds an area tagged with "name"="United Kingdom" */
  {{geocodeArea:"GB"}}->.a;             /* finds an area tagged with "ISO3166-1"="GB" */

Note that the "geocodeArea" queries above will return (into the result set "a") only Overpass areas matching the indicated name, but no OSM objects (nodes, ways or relations). Not all possible areas are returned by such queries, only the first matching one is returned: this is using an Overpass Turbo syntax extension, which allows performing a search by name (using Nominatim) and then convert the returned object into a suitable Overpass area id. These queries will not work directly on basic Overpass API servers, and you'll need to specify the constant area id yourself.

Without using the Overpass Turbo extension (which is more limited and may not return the area you expect), you can still use the Overpass API construct to get the same thing (but without being limited to only one area in the result set, and with more possibilities to filter the selected union area by explicit tags):

  ( area[name="United Kingdom"]; )->.a;  /* or more selectively: */
  ( area["ISO3166-1"="GB"][admin_level=2]; )->.a;

Then this named result set can be used to filter objects by intersection with this area. The following filter clause will keep only objects from the current result set that are intersecting with any area present in the named result set "a":

  /*your query here*/(area.a)

Note that this filter will keep any object (nodes, ways, relations, or areas) in the main query that are fully contained in any area in "a", or partially covered by any one of them, or any object in the query whose surface completely encloses any area in "a". For example, if the selected area is the area of a city, the filter will return all local subdivisions (districts, quarters) in that city, all natural features (such as lakes) in that city, and all subdivisions that are including that city (nodes, ways, relations and areas in the input set), unless you use additional tag filters in the main query to be more selective (such as ["admin_level"="8"] for just selecting OSM objects representing that city; the closed objects for the surrounding cities that also tagged with ["admin_level"="8"], and that are sharing only a common border with the selected city will normally not be returned because the surface of their mutual intersection should be empty and limited to these common borders; however any nodes and ways that are in the input set, and that are also falling exactly on the border of the selected area will be returned, independently of other relations or closed ways in which they could be members).

Recursion clauses ("recursion filters")

Or recursion forward or backward about membership links

  (r)
  (w)
  (n)
  (br)
  (bw)
  (bn)
  (>)
  (>>)
  (<)
  (<<)

Special clauses ("special filters")

Or special clauses of the form "(type:value)", e.g. the "(around:value)" clause.

More details are provided in the respective parts of the Usage Examples.

About the links

Most examples are illustrated with showing links to a map. This is still a very experimental solution. The bounding box is fixed to show always the German town Bonn. And some queries take quite a lot of time, maybe over a minute if none of the needed data is in the cache on the server. The symbols are ugly, but this could also be changed for a mashup layer aiming at end users. They should be primarily easy to find.

Usage examples: All data in a bounding box

Let's start looking at some examples for queries by looking at querying by bounding box.

The bounding box

The bbox-query lets you download all nodes, ways or relations from the given bounding box. Specify with:

  • s the southern limit in decimal degrees (lowest latitude, measured along a meridian from the nearest point on the Equator, negative in the Southern Hemisphere)
  • w the western limit in decimal degrees (lowest longitude, measured along a parallel from the nearest point on the Greenwich meridian, negative in the Western Hemisphere)
  • n the northern limit in decimal degrees (highest latitude, measured along a meridian from the nearest point on the Equator, positive in the Northern Hemisphere)
  • e the eastern limit in decimal degrees (highest longitude, measured along a parallel from the nearest point on the Greenwich meridian, positive in the Eastern Hemisphere))

These coordinates are specified in the OSM database and in the OverPass API by vertically projecting the real points to nodes on the WGS84 ellipsoid.

Please note also that the Overpass QL form has the implicit order (s, w, n, e). This is more concise than the explicit XML syntax, but of course requires some care to get the order right. The western limit is higher than the eastern limit if and only if your query surpasses the longitude ±180.0 degrees with a bounding box passing through the Antimeridian (in that case the query is equivalent to the union of two bounding boxes on each side the Antemeridian.

For areas that aren't boxes, see the Poly command.

Retrieving all nodes within a bounding box

All nodes in a small sample bounding box:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <bbox-query e="7.157" n="50.748" s="50.746" w="7.154"/>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node(50.746,7.154,50.748,7.157);
out body;

Display result: OpenLayers map, JSON, XML.

Ways

In a similar fashion, you can get all ways of the bounding box. A way is found not only if it has a node inside the bounding box but also if it just crosses somewhere the bounding box.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="way">
    <bbox-query e="7.157" n="50.748" s="50.746" w="7.154"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
way(50.746,7.154,50.748,7.157);
out body;

Display result: OpenLayers map, JSON, XML.

Relations

A relation is found in a bounding box if it has a member of type node or way within the bounding box.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="relation">
    <bbox-query e="7.157" n="50.748" s="50.746" w="7.154"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
relation(50.746,7.154,50.748,7.157);
out body;

Display result: OpenLayers map, JSON, XML.

Usage examples: Simple queries for tags and bounding boxes

Wherever you see the this symbol: overpass turbo icon, you can click it to use overpass turbo for inspecting the query and its results.

Finding something in the OpenStreetMap data always means to search for a location or for the values of certain tags. You can choose any key for the tag in the following examples. In a first step, we find objects by their names, thus we search for certain values of the key "name".

By exact name

In our first example, we search for a node by the value of its name tag:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node["name"="Gielgen"];
out body;

Display result: OpenLayers map, JSON, XML.

By exact name and rough location

If this isn't exact enough, you could also specify a bounding box to get results from only within a certain bounding box. The coordinate order is (lower lat., lower lon., upper lat., upper lon.). If you don't have a bounding box, the following example may fit better to you:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  (50.7,7.1,50.8,7.2);
out body;

Display result: OpenLayers map, JSON, XML.


Non-exact names

But even when you don't know the exact name, you can find the object. For that purpose, Overpass API supports (POSIX extended) regular expressions. We give a couple of examples for useful regular expressions.

The first example searches for any node that contains the substring "holtorf" in its name:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="holtorf"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"~"holtorf"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

The second example searches for any node that has the substring "Holtorf" as the beginning of the name:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="^Holtorf"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"~"^Holtorf"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

The third example searches for any node that has the substring "holtorf" as the end of the name:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="Holtorf$"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"~"holtorf$"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

Of course you could also search for "^Holtorf$", but this is the same as a simple search for equal value.

And you can search case insensitive with regular expressions by enclosing both variants in brackets:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="[hH]oltorf"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"~"[hH]oltorf"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

Accents and decorated characters

A lot of European languages have modified variants of the well known Latin characters, not only "e" but also "é" or "ê". You can obtain them with a regular expression:

By list listing candidates:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="H[oôóòö]ltorf" />
    <bbox-query s="50.7" w="7.1" n="50.8" e="7.25" />
  </query>
  <print />
</osm-script>
Overpass-turbo.svg
node
  ["name"~"H[oôóòö]ltorf"]
  (50.7,7.1,50.8,7.25);

out body;

Or by leaving a dot wildcard:

Overpass XML Overpass QL
Overpass-turbo.svg
<osm-script>
  <query type="node">
    <has-kv k="name" regv="H.ltorf" />
    <bbox-query s="50.7" w="7.1" n="50.8" e="7.25" />
  </query>
  <print />
</osm-script>
Overpass-turbo.svg
node
  ["name"~"H.ltorf"]
  (50.7,7.1,50.8,7.25);

out body;

Please note:

  • A single wildcard dot replaces a single UTF-8 encoded code point, not necessarily only a single byte in that encoding (only the characters in the 7-bit US-ASCII subset are encoded in UTF-8 on one byte). So a single dot matches "e" as well as "é" or "ê" (but also any other letter, including non-Latin; "-" or a space), but not "ø̄" which is not encodable as a single codepoint, but as the precombined letter barred o followed by the combining macron, or as the precombined letter o with macron followed by the combiningbar overlay, or as the base letter o followed in any order by the combining macron and the combining bar overlay).
  • Letters with combining diacritics should be stored in the database in Unicode “Normalized Form Composed”, or NFC. Most letters with diacritics used in modern European languages are composable in NFC, but not every pair consisting in a base letter with by a single combining diacritic are composable into a single code point, and some letters with two combining diacritics are still encodable in NFC with a single codepoint, such as "ế" used in Vietnam and will be matched by a single wildcard dot), instead of the canonically equivalent encoding as the base letter "e" followed by the two distinct combining diacritics in either order (one of this order is the “Normalized Form Decomposed” (NFD) used by some OSes like MacOS (which prefers storing filenames encoded as NFD in its filesystem), or by some keyboard drivers or text editors.
  • For this reason it is not easy to match all possible encoding forms of the same base letter e (including lettercase variants) with or without one or more combining diacritics: the Overpass API still does not support matching regular expressions based on collation (whose rules depend on the language and script used, and on the collator used for that language and script, and on the collation strength parameters (such as letter case sensitivity). Instead you can enumerate expected the letter variants in [square] brackets, or use unions of queries for each orthography or encoding of the letter you're looking for.

One or another name

If you want to allow two alternative values, you can use a pipe for that.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" regv="holtorf|Gielgen"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"~"holtorf|Gielgen"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

More information about (POSIX extended) regular expressions can be found on the console or by your favourite search engine with "man 7 regex".

Negation

Regular expressions don't allow negation on their own. For that reason, there is an explicit negation operator in Overpass QL.

For example, the following query yields all ways that do not have a highway key value:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="way">
    <has-kv k="highway" modv="not" regv="."/>
    <bbox-query e="7.18" n="50.75" s="50.74" w="7.17"/>
  </query>
  <print limit="" mode="body" order="id"/>
</osm-script>
try it yourself in overpass-turbo
way
  ["highway"!~"."]
  (50.74,7.17,50.75,7.18);
out body;

Display result: OpenLayers map, JSON, XML.

As a second example, you can restrict a query for bus stops to those that have a shelter. Technically, we search for nodes with "highway"="bus_stop" and tag "shelter" present, but not set to "no".

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="highway" v="bus_stop"/>
    <has-kv k="shelter"/>
    <has-kv k="shelter" modv="not" v="no"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["highway"="bus_stop"]
  ["shelter"]
  ["shelter"!="no"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

The same thing with regular expressions:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="highway" v="bus_stop"/>
    <has-kv k="shelter"/>
    <has-kv k="shelter" modv="not" regv="no"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["highway"="bus_stop"]
  ["shelter"]
  ["shelter"!~"no"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

Multiple tags

Of course you can search also for nodes that have a tag "highway" to value "bus_stop" and a tag "shelter" to value "yes":

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="highway" v="bus_stop"/>
    <has-kv k="shelter" v="yes"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["highway"="bus_stop"]
  ["shelter"="yes"]
  (50.7,7.1,50.8,7.25);
out body;

Display result: OpenLayers map, JSON, XML.

Streets and other ways

Every of the above queries also works for ways or relations. We search for the street "Gielgenstraße" within the now well-known bounding box:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="way">
    <has-kv k="name" v="Gielgenstraße"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
way
  ["name"="Gielgenstraße"]
  (50.7,7.1,50.8,7.25);
out;

Display result: OpenLayers map, JSON, XML.

Please note that you need to also request the nodes of the way if you want to display the way in map (or need the coordinates for another reason. This is done with an extra-recurse down statement. To get also the way, we put both in an union statement. All these statements are explained further down.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="way">
    <has-kv k="name" v="Gielgenstraße"/>
    <bbox-query e="7.25" n="50.8" s="50.7" w="7.1"/>
  </query>
  <union>
    <item />
    <recurse type="way-node"/>
  </union>
  <print/>
</osm-script>
try it yourself in overpass-turbo
(
  way
    ["name"="Gielgenstraße"]
    (50.7,7.1,50.8,7.25);
  >;
);
out;

Relations

And now we search for the relation of "network"="VRS" and "ref"="636". This is a local bus service. As the network shortcut is unique, we don't need a bounding box or any other similar aid.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="relation">
    <has-kv k="network" v="VRS"/>
    <has-kv k="ref" v="636"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
relation
  ["network"="VRS"]
  ["ref"="636"];
out body;

Display result: OpenLayers map, JSON, XML.

Query by element id

If you want a specific id from the database, you can query for it. We give

  • an example for a node:
Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <id-query ref="507464799" type="node"/>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node(507464799);
out;

Display result: OpenLayers map, JSON, XML.

  • an example for a way:
Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <id-query ref="24777894" type="way"/>
  <print/>
</osm-script>
try it yourself in overpass-turbo
way(24777894);
out;

Display result: OpenLayers map, JSON, XML.

  • an example for a relation:
Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <id-query ref="1745069" type="relation"/>
  <print/>
</osm-script>
try it yourself in overpass-turbo
relation(1745069);
out;

Display result: OpenLayers map, JSON, XML.

The union operator: combining results and forming sets

Combining results with the union operator

The "union" statement means the set of brackets "(...);" in QL. The output of that union is placed in "_".

And, finally, we search for all kind of objects with a certain tag within a bounding box. If not using "nwr", you need to repeat the tag for every type and to use the union operator. To allow us displaying everything on a map, we also ask for the nodes and ways that are referred by the relations and ways in the result:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <union>
    <query type="node">
      <has-kv k="amenity" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
    <query type="way">
      <has-kv k="amenity" modv="" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
    <query type="relation">
      <has-kv k="amenity" modv="" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
  </union>
  <union>
    <item/>
    <recurse type="down"/>
  </union>
  <print/>
</osm-script>
try it yourself in overpass-turbo
(
  node
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
  way
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
  rel
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
);
(._;>;);
out;

Display result: OpenLayers map JSON, XML.

The default set "_" and recalling the default set "._"

Similar to a default variable in the programming language PERL, Overpass QL has a default set, called "_". Let's look at the last query again:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <union>
    <query type="node">
      <has-kv k="amenity" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
    <query type="way">
      <has-kv k="amenity" modv="" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
    <query type="relation">
      <has-kv k="amenity" modv="" v="fire_station"/>
      <bbox-query e="7.3" n="50.8" s="50.6" w="7.0"/>
    </query>
  </union>
  <union>
    <item/>
    <recurse type="down"/>
  </union>
  <print/>
</osm-script>
try it yourself in overpass-turbo
(
  node
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
  way
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
  rel
    ["amenity"="fire_station"]
    (50.6,7.0,50.8,7.3);
);
(
    ._;
    >;
);
out;

Display result: OpenLayers map JSON, XML.

The query consists of

  • A first union (nodes, ways, relations), indicated by the "union" statement or first set of brackets "(...);" in QL. The output of that union is placed in "_".
  • A second union "(._;>;);" in QL, consisting of
    • recalling the default set ("item" or "._;" in QL)
    • recurse down, (">;" in QL)

The output of that second union is again placed in "_", which is then printed.

The print command prints the content of the container "_" at execution time. This comes very close to "the last set defined".

Other named sets

The item standalone query consists only of an input set prefix. It takes the input set specified by its prefix. This is in particular useful for union statements: it reproduces its input set as (part of the) result of the union statement. The most common usage is the usage with the default input set:

  ._;

In the context of a union statement, the following will return all items in the default input set along with the recurse down result.

  (._; >;);

But of course other sets are possible too:

  .a;

In the context of a union statement:

  (.a; .a >;);

Note: Subsequent statements in a union statement are not impacted by the item statement. In particular `.a;` does not add the contents of the input set to the default item set "_".

The item statement can also be used as filter.

Union and assigning sets: .->a

Overpass has an imperative execution model. In particular, the statements are executed one after another, and each statement is terminated by a semicolon. Each statement puts its results into a container in its memory named by default "_". If a statement needs input, it reads its input from "_". For example, the print statement reads from "_". Sometimes it is useful to use more than one container during a more complex query. In this case, the output can be redirected to another container, e.g. with name "x". This is what the above syntax controls.

The union block statement is written as a pair of parentheses. Inside the union, any sequence of statements can be placed, including nested union and foreach statements.

  (statement_1; statement_2; )[->.result_set];

It takes no input set. It produces a result set. Its result set is the union of the result sets of all sub-statements, regardless of whether a sub-statement has a redirected result set or not.

Example:

  (node[name="Foo"];way[name="Foo"];);

This collects in the first statement all nodes that have a name tag "Foo" and in the second statement all ways that have a name tag "Foo". After the union statement, the result set is the union of the result sets of both statements.

The result set of the union statement can be redirected with the usual postfix notation.

Example:

  (node[name="Foo"];way[name="Foo"];)->.a;

Same as the preceding example, but the result is written into the variable a.

Limitation : Note foreach and print statements cannot be sub-element of element union.

Recursion: ">", "<", etc

Recursion clauses

We already met the recursion clauses:

  (r)
  (w)
  (n)
  (br)
  (bw)
  (bn)
  (>)
  (>>)
  (<)
  (<<)

We'll now have a look at some of these.

Why we need recursion

In general, you will be interested in complete data, rather than just elements of a single type. First, there are several valid definitions of what "complete map data" means. The first unclear topic is what to do with nodes outside the bounding box which are members of ways that lie partly inside the bounding box.

The same question repeats for relations. If you wait for a turn restriction, you may prefer to get all elements of the relation included. If, for example, your bounding box hits the border of Russia, you likely don't want to download ten thousand kilometers of boundaries around half the world.

A second question for relations is whether relations on relations should be included.

For that reason, we subsequently give examples for several variants of map calls. It is a discipline where the query paradigm shows its strength: you can construct a query of any flavor you want. Just choose from the examples below or modify them to your needs.

The particular statements of the calls are explained in the more advanced sections further below.

Recursing down: ">" and ">>"

Recursing up: "<" and "<<"

This call includes all nodes in the bounding box, all ways that have such a node as member, and all relations that have such a node or such a way as members. Please observe that not all returned ways or relations are displayed in OpenLayers because Open Layers requires all nodes of a way or members of a relation to be present.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <union into="_">
    <bbox-query e="7.157" n="50.748" s="50.746" w="7.154"/>
    <recurse type="up"/>
  </union>
  <print mode="meta"/>
</osm-script>
try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  <;
);
out meta;

More about this query below.

Recursing up and down: Completed ways and relations

This call includes all nodes in the bounding box, all ways referring to any of these nodes, all member nodes of these ways whether these are inside the bounding box or not, all relations that have such a node or such a way as a member, and their node and way member, and even the nodes of these ways. Note that due to the involved relations, objects from quite far outside the bounding box are included.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <union into="_">
    <bbox-query e="7.157" n="50.748" s="50.746" w="7.154"/>
    <recurse type="up"/>
    <recurse type="down"/>
  </union>
  <print limit="" mode="meta" order="id"/>
</osm-script>
try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  <;
  >;
);
out meta;

More about this query below.

More complex recursion

See Overpass API/Advanced examples.

Special clauses: around and poly

"around" - finding something near something else

A less technical way to get one of multiple results can be to find something by providing a nearby location. For example, you can search for a location called "Gielgen" in a 1000 meter radius of a location called "Bonn".

(Be aware that the computations are made with a non-spheroid formula (see more here), that may cause some approximations)

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Bonn"/>
  </query>
  <query type="node">
    <around radius="1000"/>
    <has-kv k="name" v="Gielgen"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node["name"="Bonn"];
node
  (around:1000)
  ["name"="Gielgen"];
out body;

Display result: OpenLayers map, JSON, XML.

Select region by polygon

In addition to bounding boxes, now also polygons can be used to cut out a region for download. A simple example is a part of my home town in Germany:

try it yourself in overpass-turbo
(
  node(poly:"50.7 7.1 50.7 7.12 50.71 7.11");
  <;
);
out meta;

Display result: XML, JSON

More general, the examples from above can be adapted to the polygon variant: Just replace the bbox condition by the polygon condition. The only restriction is that polygons can only be used as borders for nodes. Please use one of the various recurse statements to get ways and relations from it.

If you want to use a polygon like the output of rel2poly.pl as a boundary, you can convert it with the following bash script poly2request.sh:

#!/usr/bin/env bash

echo -n '(node(poly:"'
awk '{ if ($1 != "1" && $1 != "polygon" && $1 != "END") printf $2" "$1" "; }'
echo '");<;);out;'

Now you can get your download with e.g.

./poly2request.sh <polygon.txt >request.txt
wget --post-file=request.txt http://overpass-api.de/api/interpreter

Control output format (print, out)

Print does what its name lets you expect: it prints the contents queried so far as returned data. Thus, almost every query ends with a print statement. For the sake of brevity, print has been renamed to out; in Overpass QL.

Degree of verbosity

Print exists in four different degrees of verbosity, which are specified by the mode attribute: body (default), skeleton, ids_only, and meta. Those are explained by the following examples, giving the relevant parts of the query and the result. The more concise the output is, the faster the query runs. For that reason, skeleton is used in this guide for the OpenLayers layers. meta is likely to be the best choice if you want to edit the data. If you are unsure what you need, try body first. Also see Overpass QL out docs.

XML QL Description
<print/> out;
or
out body;
The normal print mode.
<print mode="skeleton"> out skel; The skeleton print mode is somewhat shorter than the usual print mode: No tags are printed in this mode, only ids, child elements, and coordinates of nodes.
<print mode="tags"> out tags; The tags print mode only print ids and tags for each element, and not coordinates or members.
<print mode="ids_only"> out ids; ids_only is the shortest print mode; only ids are printed. ids_only is shortened to ids in Overpass QL. Note that this doesn't work with OpenLayers because no coordinates are returned.
<print mode="meta"> out meta; meta is the most complete mode. Beside child elements and tags, also the meta data (timestamp, version, changeset, user name and id) is printed.

Normal (body) =

body is the default mode: ids, child elements, and tags are printed. If you want the mode body, you can omit the mode attribute.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <has-kv k="place" v="suburb"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  ["place"="suburb"];
out;

Display result: OpenLayers map, JSON, XML.

Concise (skeleton, skel)

The skeleton print mode is somewhat shorter: No tags are printed in this mode, only ids, child elements, and coordinates of nodes:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <has-kv k="place" v="suburb"/>
  </query>
  <print mode="skeleton"/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  ["place"="suburb"];
out skel;

Display result: OpenLayers map, JSON, XML.

Brief (ids_only, ids)

ids_only is the shortest print mode; only ids are printed. ids_only is shortened to ids in Overpass QL. Note that this doesn't work with OpenLayers because no coordinates are returned.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <has-kv k="place" v="suburb"/>
  </query>
  <print mode="ids_only"/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  ["place"="suburb"];
out ids;

Display result: OpenLayers map, JSON, XML.

Verbose (meta, meta)

meta is the most complete mode. Beside child elements and tags, also the meta data (timestamp, version, changeset, user name and id) is printed:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <has-kv k="place" v="suburb"/>
  </query>
  <print mode="meta"/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  ["place"="suburb"];
out meta;

Display result: OpenLayers map, JSON, XML.

This meta data is, in particular, necessary in order to handle the result in JOSM.

Order attribute for faster results (quadtile, qt)

You can also change the order of the elements. By default, elements are ordered by their id (i.e., order="id"). You get faster results if you allow elements to be ordered by their location (i.e., order="quadtile", or qt in Overpass QL).

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
    <has-kv k="place" v="suburb"/>
  </query>
  <print order="quadtile"/>
</osm-script>
try it yourself in overpass-turbo
node
  ["name"="Gielgen"]
  ["place"="suburb"];
out qt;

Display result: OpenLayers map, JSON, XML.

Limit attribute to limit elements (limit, n)

It is also possible to limit the number of printed elements:

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
  </query>
  <print limit="2"/>
</osm-script>
try it yourself in overpass-turbo
node["name"="Gielgen"];
out 2;

Display result: OpenLayers map, JSON, XML.

This limits the output to at most two nodes.

Geometry attributes

XML QL Description
<print mode="geom"> out geom; geom please refer to the Overpass QL wiki page.
<print mode="center"> out center; center adds the center of the object's boundingbox to the output, not guaranteed to be on the object's area.
<print mode="bb"> out bb; bb: please refer to the Overpass QL wiki page.

Also see Overpass API/Overpass API by Example.


Geometry attribute (center, center)

Add the center of the object's boundingbox to the output, not guaranteed to be on the object's area.

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script>
  <query type="relation">
    <has-kv k="boundary" v="postal_code"/>
    <has-kv k="postal_code" v="65343"/>
  </query>
  <print geometry="center"/>
</osm-script>
try it yourself in overpass-turbo
rel["boundary"="postal_code"][postal_code=65343];
out center;

OSM Script options

Choose file format (output="json", [out:json])

You can get the result as JSON or as XML. By default, you get the data as XML. To get the result as JSON, just add a JSON request to the query header (before the first statement):

Overpass XML Overpass QL
link=http://overpass-turbo.eu/?Q=%3Cosm-script%20output%3D%22json%22%3E%0A%20%20%3Cquery%20type%3D%22node%22%3E%0A%20%20%20%20%3Chas-kv%20k%3D%22name%22%20v%3D%22Gielgen%22%2F%3E%0A%20%20%3C%has-kv k="name" v="Gielgen"/> 2Fquery%3E%0A%20%20%3Cprint%2F%3E%0A%3C%2Fosm-script%3E&C=50.73515;7.20519;14&R
<osm-script output="json">
  <query type="node">
    <has-kv k="name" v="Gielgen"/>
  </query>
  <print/>
</osm-script>
try it yourself in overpass-turbo
[out:json];
node["name"="Gielgen"];
out body;

CSV (Comma Separated Values) format: see Overpass QL wiki page.

Display result: OpenLayers map, JSON, XML.

Resource management options (osm-script)

The osm-script is silently added if you don't specify it explicitly when using the XML syntax. The reason to specify one explicitly is to tweak the resource management options by setting optional XML attributes (equivalent bracketted options may also be specified in an empty statement at start of your query when using the QL syntax).

Overpass XML Overpass QL
try it yourself in overpass-turbo
<osm-script timeout="900" element-limit="1073741824">
  <bbox-query s="51.15" w="7.0" n="51.35" e="7.3"/>
  <print/>
</osm-script>
try it yourself in overpass-turbo
[timeout:900][maxsize:1073741824];
node(51.15,7.0,51.35,7.3);
out;

This query extends the timeout from 3 minutes to 15 minutes (written as 900 seconds). Additionally, the soft quota for memory usage is set to 1 GiB (equals 1073741824 byte).

Warning: when running this example, more than 100 MiB of data will be retrieved (even if it does not recurse up to give all details like in the first example, here it will only retrieve a flat list of nodes with their tags). Overpass will alert you if you run it directly in your browser to render the data on the map, the browser tab may crash if you continue loading it. The results of such large requests should be downloaded for processing by other tools.

These resource limits cannot be set to arbitrary high values: each Overpass API instance may refuse to extend them above some threshold (depending on server capabilities or current server load), or the query may just fail with an error message (and non-OK HTTP server error status).

See also