Overpass API/Overpass API by Example

From OpenStreetMap Wiki
Jump to navigation Jump to search
Overpass API logo.svg
edit
Overpass API · Language reference · Language guide · Technical terms · Areas · Query examples · Sparse Editing · Permanent ID · FAQ · more · Web site
Servers status · Versions · Development · Technical design · Installation · XAPI compatibility layer · Public transport sketch lines · Applications · Source code and issues
Overpass turbo · Wizard · Overpass turbo shortcuts · MapCSS stylesheets · Export to GeoJSON · more · Development · Source code and issues · Web site
Overpass Ultra · Overpass Ultra extensions · MapLibre stylesheets ·more · Source code and issues · Web site

The Overpass API offers a variety of search possibilities. This is also known as querying. The results of those searches or queries can be displayed directly on a map, but it is also possible to retrieve only the data. On this page we will focus on examples that have to be displayed on a map. This means that all queries can be inserted in the code editor of Overpass turbo. From there the query can be executed and the result will be shown on a map.

Simply click on the overpass turbo Icon next to each query to try it in overpass turbo!


Introduction

The simplest way to get started with Overpass API is to use Taginfo and to navigate to the tag you are interested in. Take post boxes as an example. Push the Overpass Turbo button there in the upper right. This will start the Overpass Turbo user interface and produce the following query

try it yourself in overpass-turbo
/*
This query looks for nodes, ways and relations 
with the given key/value combination.
Choose your region and hit the Run button above!
*/
[out:json][timeout:25];
// gather results
(
  // query part for: “amenity=post_box”
  node["amenity"="post_box"]({{bbox}});
  way["amenity"="post_box"]({{bbox}});
  relation["amenity"="post_box"]({{bbox}});
);
// print results
out body;
>;
out skel qt;

The Overpass Turbo user interface has a lot of capabilities. For the moment it should suffice that you have in the upper right corner of the map view a textfield. Type in your favorite location. It will then, with the use of Nominatim move the map view to that location. Type in e.g. Manhattan and choose the first hit. The map then jumps to the upper end of the Central Park in Manhattan. Zoom out two levels to see some of the built area. Run the query by hitting Run.

The Taginfo Example

Now we can start to understand the query.

Most of the previous query are comments - everything after // and between /* and */. Hence, a more concise variant of the query is

try it yourself in overpass-turbo
[out:json][timeout:25];
(
  node["amenity"="post_box"]({{bbox}});
  way["amenity"="post_box"]({{bbox}});
  relation["amenity"="post_box"]({{bbox}});
);
out body;
>;
out skel qt;

As we are about a simple example here, we reduce the query further in two steps to get it really simple.

We know for post boxes by common knowledge that they are always nodes:

try it yourself in overpass-turbo
[out:json][timeout:25];
(
  node["amenity"="post_box"]({{bbox}});
);
out body;
>;
out skel qt;

And we can remove most of the cryptic syntax that mostly tells what to do with ways and relations. We can get the same result as before with only two lines.

try it yourself in overpass-turbo
node["amenity"="post_box"]({{bbox}});
out;

All these steps work with a tag from Taginfo. There is no magic involved. It just replaces amenity = post_box with the respective value.

Some Standard Features

Now what about the extra syntax? Let us review them bit by bit. To see an effect, we switch to query for restaurants instead of post boxes, because then you can see the effect in adding support for ways.

try it yourself in overpass-turbo
node["amenity"="restaurant"]({{bbox}});
out;

Not all restaurants are mapped as nodes. Hence we want to search for ways and relations too:

try it yourself in overpass-turbo
way["amenity"="restaurant"]({{bbox}});
out;

Running this query will result in a message that geometry is missing. This is because the OpenStreetMap data model does not directly associate coordinates to ways and relations. Ways and relations instead get their geometry by resolving their node references.

The out statment has various modes to address this problem in a more convenient way: You can choose for example out geom to let Overpass API resolve the coordinates for you. Or you use out center to collapse the geometry to a single coordinate per object:

try it yourself in overpass-turbo
way["amenity"="restaurant"]({{bbox}});
out center;

We can put all these requests simply one after another. Then we get the results one after another and Overpass Turbo displays them all at once.

try it yourself in overpass-turbo
node["amenity"="restaurant"]({{bbox}});
out;
way["amenity"="restaurant"]({{bbox}});
out center;
relation["amenity"="restaurant"]({{bbox}});
out center;

The Taginfo generated queries use instead the sequence out body, >, out skel qt. This is merely for historical reasons. This does essentially the same as out geom but delivers elements strictly from the OpenStreetMap data model. Overpass Turbo nowadays can directly process the results of out geom and out center and the delivered raw data is more concise.

As a last step, we make the query more concise:

try it yourself in overpass-turbo
[bbox:{{bbox}}];
( node["amenity"="restaurant"];
  way["amenity"="restaurant"];
  relation["amenity"="restaurant"]; );
out center;

This still has the same result as before. But we have brought the bounding box to a single place in the beginning of the query. An important reason to do so is that you should develop the habit of having always a bounding box unless you really want results from all over the planet.

We also have grouped the query statements by an union statement - these are the parentheses. This allows to have only a single output statement.

The Taginfo generated query also uses two other global settings: The first is [out:json]. This might be an advantage if you want to directly read the returned data. You can do so on the Data tab over the map view.

The second one is [timeout:25]. This limits the runtime of the query to 25 seconds. If something goes wrong then the limit assures that neither the server nor you waste time. Like the Global Bounding Box it is a useful precaution.

In total, we arrive at the following request:

try it yourself in overpass-turbo
[timeout:25][bbox:{{bbox}}];
( node["amenity"="restaurant"];
  way["amenity"="restaurant"];
  relation["amenity"="restaurant"]; );
out center;


Newer Overpass API versions also allow to combine node, way and relation using the shortcut nwr:

try it yourself in overpass-turbo
[timeout:25][bbox:{{bbox}}];
nwr["amenity"="restaurant"];
out center;

Rare Tags

If you do not know beforehand where you would expect a tag, but if you are pretty sure that there are not much more than some hundred elements, then you can drop the bounding box.

try it yourself in overpass-turbo
[timeout:25];
( node[name="Belsenplatz"];
  way[name="Belsenplatz"];
  rel[name="Belsenplatz"]; );
out center;

If you also leave the timeout setting out, then the server sets a default of 180 seconds:

try it yourself in overpass-turbo
( node[name="Belsenplatz"];
  way[name="Belsenplatz"];
  rel[name="Belsenplatz"]; );
out center;

Other examples

In addition to this page, there are lots more examples are in the Overpass API dev blog. There are also links to specific examples from sections below.

Understanding Data

This section is about queries that answer the question whether specific data situations exist.

There is no sharp boundary to the Building Blocks section below. The general criterion is that the examples here are from a geographic point of view, but the Building Blocks are from a database point of view and may be purely technical criteria.

The difference to Quality Assurance is that the queries here usually have valid results, whereas results of Quality Assurance queries usually need to be fixed one way or another.

Tagging

To make sense, an OpenStreetMap object always needs to have a type. Usually, humans need in addtion a handle to refer to such an object - this is what is called a name. With respect to KISS, this handle is almost always in the name tag. But sometimes there is a valid reason to have it in another tag like ref or name:fr.

One of the standard assumptions when dealing with OpenStreetMap data is that named objects have a type. This is opposed to unnamed elements of the OpenStreetMap database. They may be part of another object and then do not constitute an object on their own.

Conversely, at least certain types of objects always have names - there is no unnamed museum. However, is there no unnamed bus service? Has every restaurant a name?

Tagged Nodes

The following query returns all nodes in the current bbox having at least one tag:

try it yourself in overpass-turbo
node({{bbox}})(if:count_tags() > 0);
out geom;

The question was posed here.

Nodes with exactly one specific tag

The aim of the following query is to find out all nodes with a specific tag and no other tag.

Since 0.7.54 you can use a filter expression:

try it yourself in overpass-turbo
node({{bbox}})[name](if:count_tags() == 1);
out geom;

Please replace the name with whatever tag may fit your needs. The pitfall of this approach is that you will not find objects that have a meaningless second tag. If you want to do so then you should filter out all acceptable tags. A simple example is in the Building Blocks. More examples are in the Overpass API dev blog.

The original question comes from this source.

Leading & Trailing spaces in names

Find name* tag values with leading and trailing space characters, or multiple consecutive spaces.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
(
  node[~"^name"~"^[[:blank:]]|[[:blank:]]$|[[:blank:]]{2,}"];
  way[~"^name"~"^[[:blank:]]|[[:blank:]]$|[[:blank:]]{2,}"];
);
(._;>;);
out meta;

Count Pharmacies per County (updated 0.7.54)

The following example returns the number of pharmacies per county with regional key starting with "057". The output is in CSV format.

try it yourself in overpass-turbo
/*
   CSV-Format: To load the query results in LibreOffice, click on 
                 "Export" -> "Open Raw Data directly from Overpass API"
               in overpass turbo. Fields are tab-separated.
*/

// Define fields for csv output
[out:csv(::type, "de:regionalschluessel", name,
         ::count, ::"count:nodes", ::"count:ways", ::"count:relations")];

//All areas with regional key (German: "Regionalschlüssel") starting with 057
area["de:regionalschluessel"~"^057"];

// Count the pharmacies in each area
foreach->.regio(
  // display details for the current area
  .regio out;

  // Collect all Nodes, Ways and Relations with amenity=pharmacy in the current area
  ( node(area.regio)[amenity=pharmacy];
    way(area.regio)[amenity=pharmacy];
    rel(area.regio)[amenity=pharmacy];);

// Count the elements in the current area Area  
  out count; 
);

Since 0.7.54 we can merge the two separate lines for the area and statistical counts into a single line:

try it yourself in overpass-turbo
[out:csv( "de:regionalschluessel", name, total, nodes, ways, relations )];

//All areas with regional key (German: "Regionalschlüssel") starting with 057
area["de:regionalschluessel"~"^057.*"];

// Count the pharmacies in each area
foreach->.regio(
  // Collect all Nodes, Ways and Relations wth amenity=pharmacy in the current area
  ( node(area.regio)[amenity=pharmacy];
    way(area.regio)[amenity=pharmacy];
    rel(area.regio)[amenity=pharmacy];);
  
  make count "de:regionalschluessel" = regio.set(t[ "de:regionalschluessel"]),
             name = regio.set(t["name"]),
             total = count(nodes) + count(ways) + count(relations),
             nodes = count(nodes),
             ways = count(ways),
             relations = count(relations);
  out;
);

Count number of wikimedia_commons globally

try it yourself in overpass-turbo
[out:csv(::count, ::"count:nodes", ::"count:ways", ::"count:relations")][timeout:125];
(
  node["wikimedia_commons"];
  way["wikimedia_commons"];
  relation["wikimedia_commons"];
);
out count;

Count number of addr:housenumber in an area

The following query counts the number of addr:housenumber=* nodes/ways/relations in an area. Duplicate addresses (i.e. multiple occurrences of the same address) are not filtered out. The query result is in csv format starting with the total number of addresses, followed by the number of nodes, ways and finally relations.

try it yourself in overpass-turbo
[out:csv(::count, ::"count:nodes", ::"count:ways", ::"count:relations")][timeout:25];
{{geocodeArea:Chemnitz}}->.searchArea;
(
  node["addr:housenumber"](area.searchArea);
  way["addr:housenumber"](area.searchArea);
  relation["addr:housenumber"](area.searchArea);
);
out count;

Find relations with identical wikidata tags (since 0.7.54)

The following query determines all relations with admin_level=2 and wikidata=* tag, where the same wikidata value is used across several relations. As an example relations 1111111 is tagged as wikidata=Q183, which is also the case for relations 51477 and 62781.

try it yourself in overpass-turbo
[timeout:600];
rel[admin_level=2][wikidata]->.a;
foreach .a -> .b (
  rel.a(if:t["wikidata"] == b.u(t["wikidata"]))->.d;
  rel.d(if: id() == d.min(id()) && d.count(relations) > 1 );
  convert rel ::id = _.u(id()),
             wikidata = _.u(t["wikidata"]),
             all_relation_ids = d.set( id() );
  (._ ; .result; ) -> .result;
);

.result out;

Result:

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2017-03-29T19:04:03Z"/>

  <rel id="11980">
    <tag k="wikidata" v="Q142"/>
    <tag k="all_relation_ids" v="11980;2202162"/>
  </rel>
  <rel id="36990">
    <tag k="wikidata" v="Q235"/>
    <tag k="all_relation_ids" v="1124039;36990"/>
  </rel>
  <rel id="51477">
    <tag k="wikidata" v="Q183"/>
    <tag k="all_relation_ids" v="1111111;51477;62781"/>
  </rel>
  <rel id="87565">
    <tag k="wikidata" v="Q258"/>
    <tag k="all_relation_ids" v="1252792;87565"/>
  </rel>

</osm>

To speed up processing, an alternative approach is to export relevant fields' relation id and wikidata in CSV format and post-process the file via some shell script or similar:

try it yourself in overpass-turbo
[out:csv(wikidata, ::id;false;";")];
rel[admin_level][wikidata];
out;

Find deviating tagging

I'd like to find Objects where certain Keys have the same value. Irish streets normally have two names, one in Irish and one in English. In OSM they have three tags for that, name, name:en and name:ga. I'd like to find all objects having all three tags where name doesn't match with name:en or name:ga.

try it yourself in overpass-turbo
[timeout:300]
[bbox:51.08282186160976,-12.8759765625,55.986091533808384,-1.86767578125]
[out:csv(::id, ::type, name, "name:en", "name:ga")];

( node[name]["name:en"]["name:ga"](if:(t["name"] != t["name:en"]) && (t["name"] != t["name:ga"]));
  way[name]["name:en"]["name:ga"] (if:(t["name"] != t["name:en"]) && (t["name"] != t["name:ga"]));
  rel[name]["name:en"]["name:ga"] (if:(t["name"] != t["name:en"]) && (t["name"] != t["name:ga"]));
);
out;

The original question comes from this source.

Find wikidata relations having identical wikidata way members

The following query finds all wikidata relations in the current bounding box, where both the relation and the way member share the same wikidata id.

try it yourself in overpass-turbo
rel[wikidata]({{bbox}});     // get all relations with wikidata tag in current bounding box

foreach -> .rel(             // process each relation one by one
    
  // find out all way members where the wikidata tag matches the relation's wikidata tag
  way[wikidata](r.rel)(if: t["wikidata"] == rel.u(t["wikidata"]))->.ways;
  
  // if some way members could be found, print the current relation first...
  rel.rel(if:ways.count(ways) > 0);
  out center;
  
  // ... followed by all ways with matching wikidata tag
  .ways out tags;
);

Multipolygons with inappropiate member roles

The following query can be used to identify all multipolygon relations in the current bounding box, where not all of their members have an inner or outer role.

try it yourself in overpass-turbo
rel({{bbox}})[type=multipolygon]->.relations;

foreach .relations -> .relation (

  (
    node(r.relation);
    way(r.relation);
    rel(r.relation);
  )->.elem_all;

  (
    node(r.relation:"inner");
    way(r.relation:"inner");
    rel(r.relation:"inner");
  )->.elem_inner;
  
  (
    node(r.relation:"outer");
    way(r.relation:"outer");
    rel(r.relation:"outer");
  )->.elem_outer;
  
  
  rel.relation( if:elem_all.count(nodes)     > elem_inner.count(nodes) + 
                                               elem_outer.count(nodes) ||
                   elem_all.count(ways)      > elem_inner.count(ways)  +
                                               elem_outer.count(ways)  ||
                   elem_all.count(relations) > elem_inner.count(relations) +
                                               elem_outer.count(relations));

  out center;
);


Relations with relation members only

Relation with relation members only cannot be queried easily using a bounding box. Given the example of administrative boundaries, the following query returns such relations on a global scale.

try it yourself in overpass-turbo
rel[boundary=administrative](if:count_members() > 0 && count_members() == count_members(relations));
out meta bb;

Geometry and Topology

Count number of ways and length

This tries to count the paths that are not used in cities with designated foot or bicycle traffic, i.e. paths in the woods.

try it yourself in overpass-turbo
[out:csv(number,length)][maxsize:1000000000];
{{geocodeArea:Sweden}}->.searchArea;
way["highway"="path"][!foot][!bicycle][!segregated](area.searchArea);
make stat number=count(ways),length=sum(length());
out;

Find multipolygons with more than one outer way member (since 0.7.54)

Please note that relations with more than one outer member are valid.

try it yourself in overpass-turbo
rel[type=multipolygon]({{bbox}});
foreach -> .a (
  way(r.a:outer);
  ( rel.a(if:count(ways) > 1);
    .result; )->.result;
);
.result out center;

Find multipolygons with a single outer way member (since 0.7.55)

The following query returns all multipolygon relations with a single way member.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
rel[type=multipolygon](if:count_by_role("outer") == 1 && count_members(ways) == 1);
out geom;

Search for street intersections

The following query returns every intersection node between distinct streets (not including when a street changes its name or stops being a dual carriageway mid-block). [1]

try it yourself in overpass-turbo
[out:json][timeout:25][bbox:{{bbox}}];

// The public street network
way["highway"~"^(trunk|primary|secondary|tertiary|unclassified|residential)$"]->.streets;

// Get nodes that connect between three or more street segments
node(way_link.streets:3-)->.connections;

// Get intersections between distinct streets
foreach .connections->.connection(
  // Get adjacent streets
  way(bn.connection);
  // If the names don't all match, add the node to the set of intersections
  if (u(t["name"]) == "< multiple values found >") {
    (.connection; .intersections;)->.intersections;
  }
);

.intersections out geom;

This query excludes minor intersections that connect a public street with a service road, such as an alley or driveway. You can include these intersections by adding |service to the regular expression above. However, you may want to also filter such intersections by the presence of traffic control devices such as highway=traffic_signals or highway=stop.

Search for specific street intersections

The query above is overkill if you know something about the cross streets. The following query returns the street intersection of 6th Avenue and West 23rd Street (e.g. in New York) and is less likely to time out with a large bounding box:

try it yourself in overpass-turbo
[bbox:{{bbox}}];
way[highway][name="6th Avenue"]->.w1;
way[highway][name="West 23rd Street"]->.w2;
node(w.w1)(w.w2);
out;

Assumption: both streets need to be connected via a common node.

Note: If a way is contained in both .w1 and .w2 (e.g. because you match names using two regular expressions), all nodes of this way will be in the result set.

Source

This query can find intersections of major and minor roads without a complex foreach loop because the two sets of ways are disjoint:

try it yourself in overpass-turbo
[bbox:{{bbox}}];
way[highway~"^(motorway|trunk|primary|secondary|tertiary|(motorway|trunk|primary|secondary)_link)$"]->.major;
way[highway~"^(unclassified|residential|living_street|service|pedestrian|track)$"]->.minor;
node(w.major)(w.minor);
out;

This can be also adapted to find road-railway crossings and so on, and other cases where searching for nodes shared by both way with specific tag and way with other specific tag.

Complex Situations of Tagging and Geometry

Highway around schools with inappropriate maxspeed (since 0.7.54)

try it yourself in overpass-turbo
// see: http://blattspinat.com/index.php/posts/tempo-50-vor-schulen

[out:json][timeout:800];

// Get all schools in current bounding box
( way[amenity=school]({{bbox}});
  node[amenity=school]({{bbox}});
  rel[amenity=school]({{bbox}});
)->.schools;

// find highway=* around schools with radius 50m, ignoring
// footway and paths. In addition, highways are relevant if they 
// either
// (1) have no maxspeed tag at all
// (2) maxspeed tag indicates a value larger than 30 km/h

way(around.schools:50)[highway][highway!~"^(footway|path)$"]
   (if: (is_number(t["maxspeed"]) && t["maxspeed"] > 30) || 
        !is_tag(maxspeed) )->.streets;

// get schools in 50m distance for all identified relevant streets
( node.schools(around.streets:50);
  way.schools(around.streets:50);
  rel.schools(around.streets:50);
 )->.matchingSchools;

// return results, schools and streets
(.matchingSchools; .streets;);
out geom;

Isolated Buildings

Find buildings where the closest building is more than 1km away.

try it yourself in overpass-turbo
way[building]({{bbox}})->.a;
foreach .a (
  way.a(around:1000);
  way._(if:count(ways) == 1);
  out center;
);

NB: Query is very slow, needs the following fix

Banks far away from police stations

Find banks where the closest police station is more than 3km away.

try it yourself in overpass-turbo
[out:json][bbox:{{bbox}}][timeout:800];

// determine set of police stations
(
  node[amenity=police];
  way[amenity=police];
  rel[amenity=police];
)->.polices; // put them into the set "polices"
 
// determine set of banks
(
  node[amenity=bank];
  way[amenity=bank];
  rel[amenity=bank];
)->.banks; // put them into the set "banks"
  
// determine set of banks near police stations
(
  node.banks(around.polices:3000);
  way.banks(around.polices:3000);
  rel.banks(around.polices:3000);
)->.banksNearPolices; // put them into the set "banksNearPolices"

// determine banks far from police stations
(.banks; - .banksNearPolices;);

// return node, ways, relations as determined above
out geom meta;

City limit street signs

Tag:traffic_sign=city_limit allows putting a traffic_sign=city_limit node node on the highway (rather than somewhere next to it). The following query identifies those standalone nodes, excluding those nodes which are in close proximity to an already correctly mapped city_limit node.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
node[traffic_sign=city_limit] -> .allnodes;
way[highway](bn.allnodes);
node(w)[traffic_sign=city_limit];
node(around:15)[traffic_sign=city_limit] -> .waynodesandfriends;
(.allnodes; - .waynodesandfriends;);
out;

Pub tour in Dublin

Challenge: how far can you get with the next pub only 500m away?

try it yourself in overpass-turbo
node(3470507586);   // starting here...
complete(100) { nwr[amenity=pub](around:500); };
out center;

golf=fairway outside leisure=golf_course

Challenge: find all fairways outside of any golf_course

try it yourself in overpass-turbo
[out:json][timeout:60][bbox:{{bbox}}];
 // see https://forum.openstreetmap.org/viewtopic.php?id=70773 (in German)
 
 // search all way/rel[leisure=golf_course] in bbox
 wr[leisure=golf_course];

 // convert to area
 map_to_area ->.golfcourse;
 
 // golf=fairway inside leisure=golf_course
 way(area.golfcourse)[golf=fairway] -> .fairGolf;
 // .fairGolf out;.fairGolf >;out geom;

 // all golf=fairway
 way[golf=fairway] -> .fairAll;
 //.fairAll out;.fairAll >;out geom;

 // form difference and output
 (way.fairAll; -way.fairGolf;);
 out; > ; out geom;

Find stairs at the end of a dead end road

Since release 0.7.61, a newly added filter way_link can be used locate dead end nodes, see way_link

try it yourself in overpass-turbo
[out:json];
area[name="London"]->.a;
way(area.a)["highway"~"^(residential|living_street)$"];
node(way_link:1);
way(bn)["highway"="steps"];
out geom;

Calculate the length of a highway route

Overpass is more reliable than a routing engine for calculating the total length of a designated highway route. A routing engine may depart from the route in order to optimize for travel time or distance or avoid traffic congestion, but the length of a route per se, without any detours, is one of the basic attributes of the route.

U.S. Route 101 is one of the longest highway routes in California. Some but not all of this route runs along dual carriageway motorways. For technical reasons, the route is modeled as four relations: one route relation per direction, plus a bidirectional route relation for the rural northern segment. To obtain the "centerline" distance traveled by the route, we concatenate the southern leg's northbound route with the northern leg.

try it yourself in overpass-turbo
relation(id:108619,2306823);
make stats length=sum(length()) /* meters */;
out;

Estimate the distance to a motorway junction

In traffic management, it can be useful to know the distance along a highway route from its point of beginning up to some landmark, such as a motorway junction.

Clark County Route 215 forms part of a ring road around Las Vegas. Because each side of the ring is signposted with different cardinal directions, the route is modeled as a three-level hierarchy of route relations.

This query returns an estimated length from the beginning of the route going clockwise (westbound, then northbound, then eastbound) until exit 41. Normally, in the United States, an exit "41" would be about 41 miles (66 km) from the route's point of beginning. However, the exit numbers along this beltway are numbered from the beginning of an adjoining route, Interstate 215.

try it yourself in overpass-turbo
// Get the clockwise-bound relations of Clark County Route 215, one per leg.
relation(id:11605967,11605971,11620220)->.route;

// Recurse down to the constituent roadways.
way(r.route)->.roadways;

// Find exit 41 along the route’s roadways.
node(w.roadways)["highway"="motorway_junction"]["ref"="41"]->.exit;

// Get the first way along each route relation:
way(r.route)(
  // Only if its ID is in the set of:
  if: lrs_in(id(), route.set(
    // For each member of the route relation:
    per_member(
      // The way if it is at position 1.
      pos()==1 ? ref() : 0
    )
  ))
)->.startingWay;

// Recurse up to the roadways before and after the exit.
way.roadways(bn.exit)->.exitAdjacentWays;

// Gather all the ways together.
(
  // Start at the first roadway.
  way.startingWay;
  
  // Greedily expand the set as long as:
  complete {
    // The adjacent way is a roadway along the route and is not one of the ways adjacent to the exit.
    (way.roadways(around:0);-way.exitAdjacentWays;);
  };
  
  // Also include the way before the exit.
  // ASSUMPTION: The exit is at the end of the way.
  way.exitAdjacentWays(around:0);
);

// Output the partial route.
out geom;

// Output the distance from the route’s starting point to the exit.
make stats length=sum(length());
out;

This query assumes that the highway=motorway way has been split at the highway=motorway_junction. If not, the returned distance would be an overestimate.

Users and old data

Find newbies mapping railway signals

Task: Find all unknown newbies in an area who have started mapping railway signals railway=signal after a point in time. If needed, help them with JOSM templates, etc.

try it yourself in overpass-turbo
node
  [railway=signal](newer:"2017-01-01T07:00:00Z")     // adjust date as needed
  ({{bbox}})->.newnodes;

// List all well-known power users here, which should be excluded from the result list:
(.newnodes; - node.newnodes(user:Nakaner, "Nakaner-repair", bigbug21, mapper999);)->.newnodes;

// Output
.newnodes out meta;

This query has a few shortcomings:

  1. Only last-changed timestamp of a node is taken into account. A non-railway mapper moving a railway=signal node would trigger false positives.
  2. The list of power users needs to be manually adjusted until the number of false positives is small enough.


Find all objects last edited by a specific mapper

Task: Find all objects last edited by a specific mapper.

Especially useful in tracking down damage caused by a vandal.

try it yourself in overpass-turbo
nwr(user:"Dzielny Fokowąs");
out skel qt;

Note: For more reliable results, you should use the uid: filter instead (see Overpass_API/Overpass_QL#By_user_(user,_uid). This way, you can still query for edits by a specific user, even if they delete their user, and re-create a new user with the same display name. uid: also supports a list of user ids.

The easiest way to get uid is to follow "Changeset XML" at bottom of changeset made by a specific user.

OSM data at a certain date

The "date" parameter can be used to retrieve OSM objects as they were on a particular date, for example:

try it yourself in overpass-turbo
[date:"2014-05-06T00:00:00Z"];
( node({{bbox}}); <; >; );
out meta;

This can be used to see famous attempt of 2.5D modeling that was reverted fairly quickly as it was tagging for the renderer.
Another use-case is to find the OSM object id of a deleted object.

Old objects

Finds old buildings, not modified since specified date.

try it yourself in overpass-turbo
nwr[building]({{bbox}})->.all;
(.all; - nwr.all(newer:"2020-04-01T00:00:00Z");
);
out body;
>;
out skel qt;

Recently modified objects

Finds only buildings modified since specified date.

try it yourself in overpass-turbo
(
nwr[building]({{bbox}})(newer:"2020-04-01T00:00:00Z");
);
out body;
>;
out skel qt;

Making a Table of Object Versions

The purpose of retro plus timeline is to iterate over each version of an object and do something.

As you can get all object versions of an object from elsewhere as well, the purpose here is rather to pinpoint a property. This often works best if you make a table of the versions and the respective property.

We start with just version, timestamp, and changeset id.

try it yourself in overpass-turbo
[out:csv(version,timestamp,changeset)];
timeline(relation,2632934);
for (t["created"])
{
  retro(_.val)
  {
    rel(2632934);
    make stat version=u(version()),timestamp=u(timestamp()),changeset=u(changeset());
    out;
  }
}

We are free to use whatever makes sense within the inner brackets. In this case this is make with the three attributes version, timestamp, and changeset. They match the column titles as declared in out:csv at the top. The element name stat does not matter here because the CSV format does not print element names.

Now, each execution of out in the for loop produces one line.

In a second step, we add an extra attribute. The above mentioned relation got scrutiny because it errorneously had ten of thousands of members for a short time. We can add a column to count members. In this example we count with a flat count_members without restrictions on roles or member types:

try it yourself in overpass-turbo
[out:csv(version,timestamp,changeset,count)];
timeline(relation,2632934);
for (t["created"])
{
  retro(_.val)
  {
    rel(2632934);
    make stat version=u(version()),timestamp=u(timestamp()),changeset=u(changeset()),count=u(count_members());
    out;
  }
}

Relation 2632934 in this example has an exceptionally large number of relation members starting at version 99.

98	2018-12-10T15:05:22Z	343
99	2018-12-13T16:54:37Z	21002
100	2018-12-13T19:52:55Z	20846
101	2018-12-18T19:52:21Z	20910
102	2018-12-26T00:50:19Z	21161
103	2018-12-26T15:07:55Z	21097
104	2019-01-03T17:17:59Z	21223
105	2019-01-12T19:08:11Z	21223
106	2019-02-11T09:29:28Z	42698
107	2019-02-11T11:22:29Z	350

Exporting Data

Exporting Data has its own special requirements. As opposed to simply viewing data, it may make sense to have quite large amounts of data. There are some special precautions you should take in that case to be efficient with the resources of the public server. The second subject specific to data export is formatting the output in something different than the usual OSM XML.

List of streets

The following query allows you to compile a complete list of all street names in a town. The example is made for Troisdorf:

try it yourself in overpass-turbo
[out:csv("name";false)];
area[name="Troisdorf"];
way(area)[highway][name];
out;

This gives all the Ways inside this town, including ways that cross the town boundary. It cannot be avoided, but luckily it does not occur that often. The Nodes of the ways are not returned.

One only has to remove duplicates from this list, this can easily be done on the command line with

sort liste.csv | uniq

one can extract the list of street names.

By using a for statement, it is also possible to sort the list and remove any duplicates:

try it yourself in overpass-turbo
[out:csv("name";false)];
area[name="Troisdorf"];
way(area)[highway][name];
for (t["name"])
(
  make x name=_.val;
  out; 
);


In many cases, the boundary of a town has a different name than the city itself. This leads to empty results.E.g. Eckernförde requires the suffix "Landmasse" . The problem can be solved in general by using a regular expression

try it yourself in overpass-turbo
[out:csv("name";false)];
area[name~"Eckernförde"];
way(area)[highway][name];
out;

Adding geocoding details to POIs

Original question on help.openstreetmap.org:

I have a Overpass API query which returns lot of nodes. I would like to know whether there is a way to add reverse geocoding information to the resulting data set. Details of my case are not that important, but just for completeness:

try it yourself in overpass-turbo
area[name="Česko"];
node[information="guidepost"](area);
out;

In fact I do not need full reverse geocoding info for nodes, I only need relation of certain administrative level, so if this is possible to add into the result set, it would be great.

Solution:

try it yourself in overpass-turbo
area[name="Česko"];
node[information="guidepost"][ele~"^2..$"](area)->.posts;
    // You can remove "ele".
    // It has been added to experiment with a fewer number of results
foreach.posts(
  out;
  is_in;
  area._[admin_level~"[46]"];
      // The choice of "[46]" is arbitrary and could be anything else.
      // In this case, admin_level=4 are counties and admin_level=6 are cities,
      // which might be handy.
  out ids;
);

// collect area details in 2nd step
.posts is_in;
area._[admin_level~"[46]"];
out;

To avoid repeating full area details for each information=guidepost, the query uses the following alternative approach: for each guidepost, we will only print the osm id for the area, but nothing else. Only towards the end of the query, the full details for all relevant areas are returned.

Here's a brief example on how the format looks like: a POI (node 691566183) is followed by two area ids (3600435511 and 3600442466), which are followed by another POI and its respective area ids. To find out the details for area id 3600435511, simply consult the full area details towards the end of the response.

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API">
  <node id="691566183" lat="49.7982193" lon="13.4686623">
    <tag k="ele" v="295"/>
    <tag k="information" v="guidepost"/>
    <tag k="name" v="Dolanský most (pravý břeh)"/>
    <tag k="tourism" v="information"/>
  </node>
  <area id="3600435511"/>
  <area id="3600442466"/>
  <node id="691566191" lat="49.8003120" lon="13.4679726">
    <tag k="ele" v="295"/>
    <tag k="information" v="guidepost"/>
    <tag k="name" v="Dolanský most (levý břeh)"/>
    <tag k="tourism" v="information"/>
  </node>
  <area id="3600435511"/>
  <area id="3600442466"/>
[...]
  <area id="3600435511">
    <tag k="admin_level" v="4"/>
    <tag k="boundary" v="administrative"/>
    <tag k="name" v="Jihozápad"/>
    <tag k="name:cs" v="Jihozápad"/>
    <tag k="name:de" v="Südwesten"/>
    <tag k="population" v="1209298"/>
    <tag k="ref" v="CZ03"/>
    <tag k="ref:NUTS" v="CZ03"/>
    <tag k="source" v="cuzk:ruian"/>
    <tag k="source:population" v="csu:uir-zsj"/>
    <tag k="type" v="boundary"/>
    <tag k="wikipedia" v="cs:NUTS Jihozápad"/>
  </area>
  <area id="3600442466">
    <tag k="ISO3166-2" v="CZ-PL"/>
    <tag k="admin_level" v="6"/>
    <tag k="boundary" v="administrative"/>
    <tag k="name" v="Plzeňský kraj"/>
    <tag k="name:cs" v="Plzeňský kraj"/>
    <tag k="name:de" v="Region Pilsen"/>
    <tag k="name:ru" v="Пльзенский край"/>
    <tag k="population" v="572687"/>
    <tag k="ref" v="PL"/>
    <tag k="ref:NUTS" v="CZ032"/>
    <tag k="source" v="cuzk:ruian"/>
    <tag k="source:population" v="csu:uir-zsj"/>
    <tag k="type" v="boundary"/>
    <tag k="wikipedia" v="cs:Plzeňský kraj"/>
  </area>

Source, Thanks to Roland

Adding Georeference details to village nodes (since 0.7.54)

Since 0.7.54, it is also possible to generate is_in details for place=village nodes in the current bbox on-the-fly:

try it yourself in overpass-turbo
node({{bbox}})[place=village];
  foreach(
    is_in->.a;
    area.a[name][boundary=administrative][admin_level~"^[2-8]$"] -> .a;
    convert node ::=::,
              ::id = id(),
              is_in=a.set("{" + t["admin_level"] + ":" + t["name"] + "}");
   
    out;
  );

Performance hint: don't run this kind of query on 1000 or 10000+ objects on the overpass-api.de instance, as it consumes too much resources.


The resulting XML includes a new is_in tag, which lists all boundary=administrative with admin_level from 2..8 and a name, sorted by increasing admin_level:

  <node id="1724711941">
    <tag k="name" v="Steinklingen"/>
    <tag k="place" v="village"/>
    <tag k="is_in" v="{2:Deutschland};{4:Baden-Württemberg};{5:Regierungsbezirk Karlsruhe};{6:Rhein-Neckar-Kreis};{8:Weinheim}"/>
  </node>

Unfortunately, any nodes which have been enhanced via convert don't include any lat/lon details at this time.


Church building ways in an area

When applying this technique to ways, one has to keep in mind that the is_in statement only works on nodes. For this reason, we first have to determine all nodes for a way.

try it yourself in overpass-turbo
[timeout:60];
area["name"="Mayenne"]->.boundaryarea;
way(area.boundaryarea)["building"="church"];
  foreach(
    node(w)->.n;                                     // determine all nodes of a way
    .n is_in->.a;
    area.a[name][boundary=administrative][admin_level~"^[2-8]$"] -> .a;
    out center;
    convert way ::=::,
              ::id = id(),
              is_in=a.set("{" + t["admin_level"] + ":" + t["name"] + "}");

    out;
  );

Wiki table generator (since 0.7.54)

The following query abuses csv and make features a bit to create a wikitable syntax table, which can be copy & pasted into a wiki page (see result below). This might be useful to avoid command line post processing of Overpass results.

try it yourself in overpass-turbo
// Poor man's wikitable generator

[out:csv(_row;false)];

make out _row = "{|class=wikitable    "; out;
make out _row = "|-                   "; out;
make out _row = "! Regional Key       "; out;
make out _row = "! Name               "; out;
make out _row = "! Total              "; out;
make out _row = "! Nodes              "; out;
make out _row = "! Ways               "; out;
make out _row = "! Relations          "; out;


//All areas with regional key (German: "Regionalschlüssel") starting with 057
area["de:regionalschluessel"~"^05774"];

// Count the pharmacies in each area
foreach->.regio(
  // Collect all Nodes, Ways and Relations wth amenity=pharmacy in the current area
  ( node(area.regio)[amenity=pharmacy];
    way(area.regio)[amenity=pharmacy];
    rel(area.regio)[amenity=pharmacy];) -> .r;
  
  make out _row = "|-"; out;
  make out _row = "| " + regio.set(t[ "de:regionalschluessel"]) + 
                  " || " + regio.set(t["name"]) + 
                  " || " + (r.count(nodes) + r.count(ways) + r.count(relations)) + 
                  " || " + r.count(nodes) + 
                  " || " + r.count(ways) +
                  " || " + r.count(relations); 
  out;

);
make out _row = "|}"; out;

Query result (pasted into a wiki page):

Raw data Rendered as wiki page
{|class=wikitable    
|-
! Regional Key       
! Name               
! Total              
! Nodes              
! Ways               
! Relations          
|-                   
| 05774 || Kreis Paderborn || 68 || 61 || 7 || 0
|-
| 057740016016 || Büren || 3 || 3 || 0 || 0
|-
| 057740036036 || Salzkotten || 5 || 5 || 0 || 0
|-
| 057740040040 || Bad Wünnenberg || 3 || 2 || 1 || 0
|-
| 057740028028 || Lichtenau || 2 || 2 || 0 || 0
|-
| 057740024024 || Hövelhof || 3 || 2 || 1 || 0
|-
| 057740020020 || Delbrück || 6 || 6 || 0 || 0
|-
| 057740008008 || Bad Lippspringe || 4 || 4 || 0 || 0
|-
| 057740032032 || Paderborn || 39 || 35 || 4 || 0
|-
| 057740012012 || Borchen || 1 || 1 || 0 || 0
|-
| 057740004004 || Altenbeken || 2 || 1 || 1 || 0
|}
Regional Key Name Total Nodes Ways Relations
05774 Kreis Paderborn 68 61 7 0
057740016016 Büren 3 3 0 0
057740036036 Salzkotten 5 5 0 0
057740040040 Bad Wünnenberg 3 2 1 0
057740028028 Lichtenau 2 2 0 0
057740024024 Hövelhof 3 2 1 0
057740020020 Delbrück 6 6 0 0
057740008008 Bad Lippspringe 4 4 0 0
057740032032 Paderborn 39 35 4 0
057740012012 Borchen 1 1 0 0
057740004004 Altenbeken 2 1 1 0


All data

try it yourself in overpass-turbo
(
  node({{bbox}});
  <;
);
out meta;

Overpass_API/Advanced_examples#Example:_Simplest_possible_map_call

Quality Assurance

The general purpose of the Quality Assurance Queries is to check whether some assumption about the data universally holds. Thus, the themes covered here are converting assumptions into query conditions and mastering the functionality to understand museum data.

See QA Tool Overpass Queries for a mapping of Overpass queries based on common Quality Assurance tools such as Osmose, KeepRight, JOSM Validator, OSM Lint, and Atlas.

Checking boundary relations for correct tagging

Looking for a boundary relation with boundary=administrative and admin_level=9 and de:amtlicher_gemeindeschluessel=XXXXXXXX, because this combination is invalid. Boundary relation for villages with their own "Gemeindeschlüssel" should have at least admin_level=8 or higher.

The first query also leaves out "boundary=administrative", because it is equally possible that one has set the wrong level or did not mention the level at all

try it yourself in overpass-turbo
rel[admin_level=9]["de:amtlicher_gemeindeschluessel"];
out;

or

try it yourself in overpass-turbo
rel[boundary=administrative][admin_level=9]["de:amtlicher_gemeindeschluessel"];
out;

Finding relation members with incorrectly spelled member roles

Find boundary=* relations with an incorrectly spelled member role admin_center (should be admin_centre)

try it yourself in overpass-turbo
rel[boundary](if:count_by_role("admin_center") > 0);out meta;


Find all bus stops which are not included in a relation

This query returns all bus stop nodes, which are not part of a relation.

try it yourself in overpass-turbo
// Search bus stops without relation

// Select city of Bonn as area
area[name="Bonn"];

// Collect all bus stops in Bonn and store the result in a variable .all
node(area)[highway=bus_stop]->.all;

// Select all relations, where one of the nodes in variable .all is a member
rel(bn.all);
// ...and for those relations find all related node members
node(r)->.b;

// Calculate the set difference (.b contains all nodes which are member of a relation).
( .all; - .b; );

// Return the result including meta data (needed for JOSM exports).
out meta;

// Variant for line 9 / 10:

// Return only relations with a specific tagging:
// rel[route=bus](bn.all);

(via talk-de, Thanks to Roland)

Bus relations, which are not part of a master relation

Q: I need to find out, which bus relations (route=bus) are not part of a master relation (route_master=bus) in a given area.

try it yourself in overpass-turbo
rel({{bbox}})[route=bus]->.all;
rel[route_master=bus](br.all);
rel[route=bus](r)->.b;
(.all; - .b; );
out;

Step-by-step explanation:

  1. Determine all relations in the current bbox with type route=bus. Save the result in variable .all
  2. Determine all parent relations of our relations in .all. Those relations need to be of type route_master=bus.
  3. Based on the list of route_master relations, we determine all child relations of type route=bus. Those relations are all part of a master relation.
  4. Create the set difference of the relations in variable .all and the result from the previous step 3. This way, all relations, which are not part of a master relation, are returned.

Source

Communities without fire station

The following alternative gives all communities [admin_level=8] (Gemeinden) in Schleswig-Holstein without amenity=fire_station. The result is in CSV format and contains the OSM ID of the relation, the "amtlichen Gemeindeschlüssel" and the name of the relation.

try it yourself in overpass-turbo
// Output in CSV format
[out:csv(::id, "de:amtlicher_gemeindeschluessel", name)];

area[admin_level=4]["name"="Schleswig-Holstein"][boundary=administrative]->.boundaryarea;

// All bounding areas with level 8 in Schleswig-Holstein
rel(area.boundaryarea)[admin_level=8];
// map relations to their respective area
map_to_area -> .all_level_8_areas;

// Search All amenity=fire_station in Schleswig-Holstein
( node(area.boundaryarea)["amenity"="fire_station"];
  way(area.boundaryarea)["amenity"="fire_station"];>;);

// in which boundary areas with level 8 do they appear?
is_in;
area._[admin_level=8] -> .level_8_areas_with_firestation; 

// All level 8 bounding areas without those 
// areas with fire station
(.all_level_8_areas; - .level_8_areas_with_firestation;); 

// Calculate and output relation
rel(pivot);
out geom;

Buildings crossed by roads that are not tagged as tunnel or covered

Building overlaps highway

Query for buildings crossed by roads (Ways) that do not have a tunnel or covered tag. Since query uses the "around" operator, which searches in the environment of an item, it is possible that false positives are returned, e.g. when a street (Way) is directly connected to the building

Please note that this is a very slow query, that can better be run with a specified bounding box.

You may want to add also highway=path, highway=footway, highway=cycleway, highway=steps to the query (not roads, but it is the same type of the problem).

highway=road may turn out to be something else, but typically is also a road and you may want to include it.

try it yourself in overpass-turbo
way[!covered][!tunnel]
   ["highway"~"motorway|motorway_link|trunk|trunk_link|primary|primary_link|secondary|secondary_link|tertiary|tertiary_link|service|residential|unclassified|living_street|pedestrian|track"]["access"!~"no|private"][!area]
   ({{bbox}});
   (way(around:0)["building"~"."];
    node(w););
out meta;

Buildings passages tagged as tunnels

Building passage not connected with building, does not fit under building (too long).

Query for paths and footways tagged with tunnel=yes, then filtered by those with correct geometry (sharing node with building) and others. To print those with incorrect geometry uncomment last line and comment previous one.

Please note that this is a very slow query, that can better be run with a specified bounding box.

try it yourself in overpass-turbo
(way["highway"~"path|footway"][tunnel=yes]({{bbox}});) -> .all_tunnels;

(way(around.all_tunnels:0)[building];) ->.crossed_buildings;
(way.all_tunnels(around.crossed_buildings:0);) -> .tunnels;

(.crossed_buildings >;) -> .building_nodes;
( .tunnels > ;  - way.all_tunnels;) -> .tunnel_nodes;

(node.tunnel_nodes.building_nodes;) -> .good_geometry;

( .good_geometry <;) -> .searchhere;

(way.searchhere.tunnels;); // comment this line to see only those with incorrect geometry

//(.tunnels; - way.searchhere.tunnels;); // uncomment this line to see only those with incorrect geometry

Find duplicate nodes (since 0.7.54)

See source.


We iterate over all nodes in the current bounding box one by one, and find out the list of all nodes with the same lat/lon value. Assuming there's more than one node at the same lat/lon, those two nodes will have different node ids. That's also the condition we use to filter out those duplicate nodes. The output will only return the duplicate node for each location having the lowest node id.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
node;
foreach->.a(
    node(around.a:0)->.b;
    node.b(if:id() == b.min(id()) && b.min(id()) != b.max(id()));
    out ;
);

Unfortunately, this is very slow.

Find duplicate nearby nodes with same tag

Find peaks that are close to each other and share the same name:

try it yourself in overpass-turbo
node["natural"="peak"]({{bbox}})->.a;
foreach.a->.elem(
  node.a(around.elem:50)
    (if:is_tag("name")&&t["name"]==elem.u(t["name"]));
  (._; - .elem;);
  out meta;
);

Overpass Turbo link (with "date" for demo purposes) source (de)

Search for untagged ways

try it yourself in overpass-turbo
way({{bbox}})(if:count_tags() == 0);
out geom;

Before version 0.7.54 the following query can be run in overpass turbo and results exported to JOSM for further processing.

try it yourself in overpass-turbo
(way({{bbox}}); - way({{bbox}})[~"."~"."];)->.w1;
rel(bw.w1);way(r)->.w2;
(.w1; - .w2;);
(._; >;);
out meta;

Source

Note that it will find ways where tagging is valid (e.g., members of multipolygons).

Alternative: OSM Inspector has a Tagging layer highlighting ways without tags that applies additional filters, JOSM validator or Osmose.

Search for ways with just area=yes

try it yourself in overpass-turbo
[timeout:200];
way({{bbox}})[area=yes](if:count_tags() == 1);
out geom;

Such ways are never correct and always need fixing (sometimes adding proper tags, sometimes deletion, sometimes removal of area=yes).

Orphaned nodes (nodes without tags, not part of any way or relation)

The following query checks for nodes in the current bounding box without any tags, that are not part of any way or relation.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
rel; > -> .r;
way; > -> .w;
(( node(if:count_tags()==0); - node.r; );  - node.w; );
out meta;

Find broken associatedStreet-relations

This query finds associatedStreet relations corrupted in some typical ways, for example ones generated by JOSM-plugin "terracer" that used to create by default a broken associatedStreet-relations.

Note that opinion differs what should be done with such relation - in Germany mappers agree that such relations should be deleted as useless, in France mappers prefer to repair such relations.

try it yourself in overpass-turbo
/* Enter your city/region/etc. here */
{{nominatimArea:Berlin}}
(._; )->.area;

/* Find all associatedStreet relations in your area */
rel[type=associatedStreet]
  [!name]
  [!"addr:street"]
  (area.area)->.allASRelations;

/* Find associatedStreet relations with member ways having role "street" */
way(r.allASRelations:"street");
rel(bw:"street")[type=associatedStreet]->.relationsWithRoleStreet;

/* Find all aS relations with empty role-way members */
way(r.allASRelations:"");
rel(bw:"")[type=associatedStreet]->.relationsWithEmptyRole;

/* Find all relations with node members */
node(r.allASRelations);
rel(bn)[type=associatedStreet]->.relationsWithNode;

/* Check if there are member ways with role 'house' not having a building tag */
way(r.allASRelations:"house")[!building];
rel(bn)[type=associatedStreet]->.relationsWoHouseBuilding;
  
/* Take all aS relations and remove all relations we want to exclude */
( ( ( (.allASRelations; - .relationsWithRoleStreet;); 
  - .relationsWithEmptyRole; ); 
 - .relationsWithNode; );
 - .relationsWoHouseBuilding);

/* add ways and nodes for output*/
(._;  );
out meta;

Find house numbers without street

The following Overpass API query retrieves all Nodes, Ways and Relations that have a addr:housenumber-tag and no addr:street nor addr:place tag. For this collection, we remove all Nodes/Ways/Relations that take part in an associatedStreet-Relation with a role "house".

Notes:

  • The query assumes that the associatedStreet-relation is conformant with the wiki and that it contains at least one member with the role "street", such that the street can be deduced. This is not verified by the query!
  • associatedStreet-Relations without street-roles can be found with the query "Find broken associatedStreet-relations" . This problem has to be resolved first, as it would prevent the correct retrieval of house numbers.
  • The name-tag on the relation is ignored. Warning: in the solution of User:Gehrke for #osmwa3334 requires a name tag on the associatedStreet-Relation, but ignores the members with the role "street"

The search area can be adapted in the first line, more details in Forum Thread.

try it yourself in overpass-turbo
area[type=boundary]["de:amtlicher_gemeindeschluessel"="08115003"]->.boundaryarea;
rel(area.boundaryarea)[type=associatedStreet]->.associatedStreet;

way(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesWay;
way(r.associatedStreet:"house")->.asHouseWay;
((.allHousesWay; - .asHouseWay;); >; );out meta;

node(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesNode;
node(r.associatedStreet:"house")->.asHouseNode;
((.allHousesNode; - .asHouseNode;););out meta;

rel(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesRel;
rel(r.associatedStreet:"house")->.asHouseRel;
((.allHousesRel; - .asHouseRel;); >>; );out meta;


Alternatively, one could do a search via Nominatim:

try it yourself in overpass-turbo
{{nominatimArea:"Regionalverband Saarbrücken"}}
(._; )->.boundaryarea;

/* Shows the boundary area as extra check - one is free to activate this step */
/* rel(pivot.boundaryarea);(way(r);>;);out; */

rel(area.boundaryarea)[type=associatedStreet]->.associatedStreet;

way(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesWay;
way(r.associatedStreet:"house")->.asHouseWay;
((.allHousesWay; - .asHouseWay); >; );out meta;

node(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesNode;
node(r.associatedStreet:"house")->.asHouseNode;
((.allHousesNode; - .asHouseNode););out meta;

rel(area.boundaryarea)["addr:housenumber"][!"addr:street"][!"addr:place"]->.allHousesRel;
rel(r.associatedStreet:"house")->.asHouseRel;
((.allHousesRel; - .asHouseRel); >>; );out meta;

Nehme entweder "addr:street", "addr:place" oder "name" von associatedStreet. Trifft nichts zu, ist die Straße "null". Ich zähle nun alle Fälle (nur nodes und ways), wo es zwar eine Hausnummer gibt, aber die Straße "null"

Non-matching addr:postcode=XXXXX tags inside a boundary relation with postal code ≠ XXXXX

... what is the query for all Nodes and Ways with a different addr:postcode than the surrounding boundary relation?

Query for a specific postal code, e.g. "42103":
try it yourself in overpass-turbo
area[postal_code="42103"]->.a;
(node(area.a)["addr:postcode"]["addr:postcode"!="42103"];
 way(area.a)["addr:postcode"]["addr:postcode"!="42103"];);
out;

Non-matching addr:postcode=XXXXX tags inside multiple boundary relation with postal code ≠ XXXXX (since 0.7.54)

Since release 0.7.54, it's also possible to check several postal codes in one query:

try it yourself in overpass-turbo
area[postal_code](if:number(t[postal_code])>="42103" &&
                     number(t[postal_code])<="42119")->.pc;

foreach.pc -> .a(
  .a out;
  (
    node(area.a)["addr:postcode"]["addr:postcode"](if: t["addr:postcode"] != a.u(t["postal_code"]));
    way(area.a) ["addr:postcode"]["addr:postcode"](if: t["addr:postcode"] != a.u(t["postal_code"]));
  );
  out geom;
);

The overpass turbo friendly version first determines all postal_code boundary relations in the current bounding box and checks for deviations in nodes and ways, comparing the postal_code with the addr:postcode tag.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
rel[boundary=postal_code][postal_code];
map_to_area;
foreach -> .a(
  (
  node(area.a)["addr:postcode"](if:t["addr:postcode"] != a.u(t["postal_code"]));
  way (area.a)["addr:postcode"](if:t["addr:postcode"] != a.u(t["postal_code"]));
//  rel(area.a)["addr:postcode"](if:t["addr:postcode"] != a.u(t["postal_code"]));
  );
  out geom;
);


Previously, this required a bash-script for postal codes 42103 - 42119

i=42103; 
while [[ $i -le 42119 ]];
do { 
   wget -O false_$i.osm "http://overpass-api.de/api/interpreter?data=area[postal_code=\"$i\"]->.a;(node(area.a)[\"addr:postcode\"][\"addr:postcode\"!=\"$i\"];way(area.a)[\"addr:postcode\"][\"addr:postcode\"!=\"$i\"];>;);out;";
   i=$(($i + 1));
};
done

When one replaces "out;" with "out meta;", than it becomes possible to read the data in the file "false_XXXXX.osm" into JOSM for editing.

The query becomes noticeably faster with a proper Bounding Box:

i=42103;
while [[ $i -le 42119 ]];
do {
   wget -O false_$i.osm "http://overpass-api.de/api/interpreter?data=area[postal_code=\"$i\"]->.a;(node(51,7,51.5,7.5)(area.a)[\"addr:postcode\"][\"addr:postcode\"!=\"$i\"];way(51,7,51.5,7.5)(area.a)[\"addr:postcode\"][\"addr:postcode\"!=\"$i\"];>;);out meta;";
   i=$(($i + 1));
};
done

Ways that are part of a "Bundesstraßenrelation", but do not have a ref-tag

Bundesstraßenrelation or National road network (in English)

Normally, one would expect that the properties of a relation are also applied to the member ways, so that it is not needed to set those tags explicitly on the ways. However, it turns out that the common practice is to set this ref also on each way. This query shows all ways that do not have the ref-tag.

try it yourself in overpass-turbo
rel({{bbox}})[type=route][route=road][ref~"^B."];
way(r)[!ref];
(._;>;);
out meta;

It is also possible to have a ref tag, but that the way does not belong to a relation.

try it yourself in overpass-turbo
area[name="Saarland"][type=boundary]->.a;
( 
  way(area.a)[highway][ref~"^B.*"]; - 
 (rel(area.a)[ref~"^B.*"][route=road][type=route];>;);
);
(._;>;);out;

For a selected area (in the example Saarland), the query retrieves all Ways whose ref-tag starts with a "B". From this collection, we remove all Ways that are part of a relation with type=route, route=road and that have a ref that starts with "B". The remaining federal streets, which are not part of a relation, are returned together with their nodes, in order to show them on a map.

POIs with websites but with incorrect opening hours

The following query returns institutions and shops, for which a website is tagged, but the opening hours are incorrect (i.e. the syntax is wrong). One should first try the first query, because it more likely to return results for which the opening hours can be found on the website. When the result of the first query is empty, one could try the second one.

First Query, Second Query

Objects with outdated or missing opening hours and collection times (for post boxes)

The below query is tailored to highlight objects with outdated or missing opening hours and collection times (for post boxes). You can use it to prepare a map with places to visit at a mapping party.

try it yourself in overpass-turbo
/* load all node/ways/relations with opening_hours set and being unequal 24/7 and store them*/
nwr[opening_hours][opening_hours!="24/7"]({{bbox}})->.oh_all;
/* remove younger entries from the previous result and store them again */
(.oh_all; - nwr.oh_all(newer:"2019-04-01T00:00:00Z");)->.oh_old;

/* do something similar as above with collection_times */
nwr[collection_times]({{bbox}})->.ct_all;
(.ct_all; - nwr.ct_all(newer:"2019-04-01T00:00:00Z");)->.ct_old;


/* unify previous results with further queries and store them */
(
  .oh_old;
  .ct_old;
  
  /* look for amenities without opening_hours and which are not private (exempt amenities that usually don't carry opening_hours)*/
  nwr[amenity][!"opening_hours"]["access"!="private"]["amenity"!~"waste_disposal|waste_basket|bench|vending_machine|post_box|fountain|kindergarten|parking_entrance|bus_station|shelter|drinking_water|watering_place|school|college|university|bicycle_parking|bbq|fire_station|hunting_stand|doctors|dentist|clock"]({{bbox}});
  
  /* shops without opening_hours */
  nwr[shop][!"opening_hours"]({{bbox}});
  
  /* post_boxes without collection times */
  nwr["amenity"="post_box"][!"collection_times"]({{bbox}});
);

out center meta qt;

Some known weaknesses:

  • The decision if an opening hour (or collection time) is outdated is done based on the date when any tag of this object was changed: I.e. an object may appear as not outdated even though the tag opening_hours=* was created a long time ago.
  • The date to consider objects outdated is both hardcoded and used in multiple places in the query.
  • Some amenities usually don't have opening hours (since they are open 24/7, e.g. benches). The query contains a (black-)list of such values and will never report them. There certainly are further (rare) amenity=* tags that are not included (yet).

Highlight Objects with a check_date older than X

The example above used a hard-coded date and searched for the time an object was edited for the last time. If a 'check_date' tag is present, this can be searched for as well.

This query uses the 'convert' feature of Overpass to add custom tags on objects that are older than a given date. These tags can then be used in a MapCSS to highlight certain ages of edits. Please note that the output of this query can be used only in Overpass Turbo - the added tags make the format non-standard and the data can't be loaded e.g. to JOSM.

Note: Source code shown is shortened to one age check and to use nodes only, see this link for the full version

try it yourself in overpass-turbo
[out:json][timeout:25];
nwr({{bbox}})[check_date]->.temp;
.temp out body;
.temp >;
out skel;               

node.temp;
convert node
  ::id=id(), 
  older365=date(t["check_date"])<date("{{date:365days}}")
;
out;
{{style:
node[older365=1]{
  color: yellow;
  }
}}
//[...]

Buildings that are taller than they are wide

The query below tries to find any building in Cincinnati, Ohio, and surrounding Hamilton County that is taller than it is wide. Overpass QL lacks an evaluator that evaluates to the area of a closed way; it only has an evaluator for the length of a way, or the perimeter in the case of a closed way. So this query finds the average width of one of the building's walls based on the perimeter and compares it to the building height. For simplicity, it only considers rectangular buildings. A more sophisticated query could inspect buildings with more vertices but divide the perimeter by only the vertices at approximately right angles.

This query finds much more than skyscrapers and high-rises. An import of government building data in the county included floor counts of many buildings, but the source data had incorrect floor counts for many small buildings. For example, it is rare for a backyard toolshed or garage to have more than one level, but many are tagged as having more than one level.

Elsewhere, extremely tall buildings due to typos have garnered amusement from end users and the media. [2][3][4] This query would easily catch such mistakes, though a simpler query for abnormally large numbers would likely perform better.

try it yourself in overpass-turbo
[out:json][timeout:25];

// Most buildings in Hamilton County, Ohio, were imported from CAGIS, which assigned questionable floor counts to small buildings in many cases
{{geocodeArea:Hamilton County, Ohio, United States}}->.hamco;

// Find rectangular buildings that are taller then they are wide
(
  // Compare the height to the average length of a side
  way["building"]["height"](area.hamco)(if:
    count_members() < 6 && is_closed() &&
    number(t["height"]) > length() / 4);
  // Assume a floor is 3 m tall
  way["building"]["building:levels"](area.hamco)(if:
    count_members() < 6 && is_closed() &&
    number(t["building:levels"]) * 3 > length() / 4);
);

// Print results
out body;
>;
out skel qt;

Case-insensitive search for suspicious names

It is using regexp for case insensitive matching (triggered by ",i").

Note that thanks to ^ (matching text start) and $ (matching text end) it will not find everything with "pond" within, just names that are such as "pond", "Pond", "pOnD"

Note that this query finds all cases worldwide.

try it yourself in overpass-turbo
[out:xml][timeout:250];
(
  nwr[natural=water]['name'~'^pond$',i];
);
out meta;
>;
out meta qt;

Building Blocks

These are examples that are not directly related to applications but rather support the language specification with examples.

Search objects with a certain tag A but without a tag B

Example: find all Nodes, Ways and Areas which are tagged with addr:city, but do not have addr:postcode. This makes use of the exists filter and not exists filter.

try it yourself in overpass-turbo
[out:json][timeout:25];
(
  node["addr:street"][!"addr:postcode"]({{bbox}});
  way["addr:street"][!"addr:postcode"]({{bbox}});
);
out skel;

Find nodes/ways with a given role in a relation

Find all nodes with role "label" or "admin_centre" in current bounding box:

try it yourself in overpass-turbo
rel({{bbox}})->.relations;

(  node(r.relations:"label");
   node(r.relations:"admin_centre");
);
out;


Find all "inner" ways, i.e. relation member ways with role 'inner':

try it yourself in overpass-turbo
rel({{bbox}});(way(r:"inner");>;);out;


Find all nodes and ways with role "via":

try it yourself in overpass-turbo
rel({{bbox}})->.relations;

( 
  node(r.relations:"via");
  way(r.relations:"via");>;
);out;

Source

Sum of a few defined OSM areas

This query is easily modified to get a sum of any OSM defined areas (geocodeArea) and extract any data for this sum of areas. See comments for details. The example just shows the chosen areas.

try it yourself in overpass-turbo
[out:json][timeout:900];
// get a few areas into .myArea
// you can add or remove an area by simply adding or removing
// one line here. 

(
{{geocodeArea:"Warszawa"}};
{{geocodeArea:"Grodzisk Mazowiecki County"}}; // "name:en" may be used as well as "name"
{{geocodeArea:"powiat pruszkowski"}};
{{geocodeArea:"powiat żyrardowski"}};
{{geocodeArea:"powiat warszawski zachodni"}}; 
{{geocodeArea:"powiat sochaczewski"}}; 
{{geocodeArea:"powiat nowodworski"}};
{{geocodeArea:"powiat legionowski"}};
{{geocodeArea:"powiat wołomiński"}};
{{geocodeArea:"powiat miński"}};
{{geocodeArea:"powiat otwocki"}};
{{geocodeArea:"powiat piaseczyński"}}; 
)->.myArea;
 
// display .myArea This can be replaced by any query
// on the objects in .myArea

rel(pivot.myArea);

// print results
out geom;

{{style:
  node{opacity:0;fill-opacity:0}
}}

« n » adjacent ways

The following example illustrates how to determine five adjacent ways for OSM way 111435507. The around statement with radius 0, which is used in this query not only filters directly connected ways, but also returns intersecting ways (without a common node). Possibly those intersecting ways need to be filtered out in a post-processing step.

try it yourself in overpass-turbo
(
  way(111435507);
  complete(4) {
    way(around:0)[highway~"."][highway!~"path|track|cycleway|footway"];
  };
);  
out geom;

To limit the overall data volume only ways with a highway tag (excluding path, track, cycleway and footpath) are considered.

Source

Search for nodes which belong to two different ways

How to find nodes, which belong to two different ways with certain tags?

Examples:

Returns nodes which are part of a building:

try it yourself in overpass-turbo
way["building"="yes"]({{bbox}});
node(w);

Returns nodes of tertiary highways:

try it yourself in overpass-turbo
way["highway"="tertiary"]({{bbox}});
node(w);

How can I combine those two queries so that both conditions are met?

try it yourself in overpass-turbo
way["building"="yes"]({{bbox}});
node(w)->.b;
way["highway"="tertiary"]({{bbox}});
node(w)->.t;
node.b.t;            // calculates set intersection of both variables .b and .t
out;

Source

If ways cannot be split into two distinct groups (e.g. building ways vs. highway=tertiary ways), it is necessary to iterate over each single way and determine the intersecting nodes with all other ways in a bbox:

try it yourself in overpass-turbo
way({{bbox}})->.allways;
foreach .allways -> .currentway(
  (.allways; - .currentway;)->.allotherways;
  node(w.currentway)->.e;
  node(w.allotherways)->.f;
  node.e.f;
  (._ ; .result;) -> .result;
);
.result out meta;

Search for nodes which belong to an exact number of ways (since 0.7.54)

To find out all nodes, which belong to an exact number of ways (rather than just more than one way as in the previous example), the following approach can be used:

Find out all nodes, which belong to exactly 3 distinct ways:

try it yourself in overpass-turbo
way({{bbox}})->.a;
foreach .a -> .b(
  (.a; - .b;)->.c;
  node(w.c)->.e;
  node(w.b)->.f;
  node.e.f->.f1;
  foreach .f1 -> .g(
    way(bn.g);
    way._(if:count(ways) == 3);
    node.g(w);
    (._ ; .result;) -> .result;
  );
);
.result out meta;

Caveat: Unfortunately, this query is extremely slow.

Retrieve full object history (since 0.7.55)

The following query example returns all versions of a given way.

try it yourself in overpass-turbo
timeline(way,561040198);
foreach(
  retro(u(t["created"]))
  (
    way(561040198);
    out meta geom;
  );
);

Note: Object history does not include object versions, which are not part of the first ODbL licensed planet or any later minutely diff (=cutoff date September 2012).

Limit results to areas only

The following query example returns specific tag (man_made=pier in this example), but limited to closed ways and multipolygon relations. Nodes, unclosed ways and other relations are not returned.

Example run in Kraków - as it is one of places with piers mapped both as lines and area.

try it yourself in overpass-turbo
[out:json][timeout:25];
{{geocodeArea:Kraków}}->.searchArea;
(
  way["man_made"="pier"](if: is_closed()==1)(area.searchArea);
  relation["man_made"="pier"]["type"="multipolygon"](area.searchArea);
);
out body;
>;
out skel qt;

Examples for Styles in overpass turbo (MapCSS)

Hiking routes

Simple way

The following query for Overpass Turbo shows all hiking-relations in the current bounding box (route=hiking and network=?wn), such as in the Lonvia-style. The color for the ways is taken from the relation.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
(
  relation[route=hiking][network~"^.wn$"];
  way(r);
  >;
);
out;

{{style:
way
{ color:green; fill-color:green; }

relation[network=lwn] way
{ color:blue; fill-color:cyan; }

relation[network=iwn] way
{ color:red; fill-color:red; }

relation[network=nwn] way
{ color:green; fill-color:green; }

relation[network=rwn] way
{ color:yellow; fill-color:yellow; }

}}

It is possible that this is not 100% correct, please test and adapt when needed. (received via osm-dev, MapCSS was corrected, Query simplified)

Advanced example

In this example apart from route geometry we output center point - and print route symbol (osmc:symbol=*, hotlinked to [5] tool). Working example can be some region of Poland: Overpass.

try it yourself in overpass-turbo
[bbox:{{bbox}}];

relation[route=hiking];
out geom center;
>;
out;

{{style:
relation {
  color:gray;
}

relation[colour] {
  color: eval("tag('colour')");
  text: ref;
}

way, node[!route] {
  fill-color: transparent;
  color:transparent;
}
node[route] {
  fill-color: eval("tag('colour')");
  color: eval("tag('colour')");
  text: eval("concat(tag('name'), ' - (', tag('from'), ' - ', tag('to'), ')  -  ', tag('ref'))");
  icon-image: eval("concat('url', '("', 'https://osm.janmichel.eu/osmc/generate.pl?osmc=', tag('osmc:symbol'), '")')");
}
}}

Textboxes with eval

The following MapCSS style displays all villages in the current bounding box with a combined German / Lower Sorbian textbox.

try it yourself in overpass-turbo
[bbox:{{bbox}}];
node[place=village];
out;

{{style:
node{
  text: eval('tag("name:de") . " - " . tag("name:dsb")');
}
}}

Mailboxes

This thema can be analysed with the queries below

Mailboxes, coloured depending on availability of the collection time tag

try it yourself in overpass-turbo
node[amenity=post_box]
    //[!"collection_times"]
  ({{bbox}});
out;

{{style:
node
{ color:red; fill-color: red;}

node[collection_times]
{ color:green; fill-color:green; }
}}


Alternative that also checks the syntax of the collection time

Overpass Turbo Link - valid for 2022

try it yourself in overpass-turbo
node[amenity=post_box] ({{bbox}});
out;

{{style:
  node{
    color: #ffffff;
    fill-color: #ff0000;
    fill-opacity: 0.8;
  }
  node[operator]{
    color: #0000ff;
    fill-color: #ff0000;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck], 
  node[last_check], 
  node[check_date], 
  node[last_checked], 
  node[lastcheck]{
    color: #ffff00;
    fill-color: #ffff00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck][operator],
  node[check_date][operator],
  node[last_check][operator],
  node[last_checked][operator],
  node[lastcheck][operator] {
    color: #0000ff;
    fill-color: #ffff00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2022-*./], 
  node[check_date=~/2022-*./], 
  node[last_check=~/2022-*./], 
  node[last_checked=~/2022-*./], 
  node[lastcheck=~/2022-*./]{
    color: #ffff00;
    fill-color: #00ff00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2022-*./][operator],
  node[check_date=~/2022-*./][operator],
  node[last_check=~/2022-*./][operator],
  node[last_checked=~/2022-*./][operator],
  node[lastcheck=~/2022-*./][operator]{
    color: #0000ff;
    fill-color: #00ff00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2021-*./],
  node[check_date=~/2021-*./],
  node[last_check=~/2021-*./],
  node[last_checked=~/2021-*./],
  node[lastcheck=~/2021-*./]{
    color: #ffff00;
    fill-color: #55aa00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2021-*.  /][operator],
  node[check_date=~/2021-*./][operator],
  node[last_check=~/2021-*./][operator],
  node[last_checked=~/2021-*./][operator],
  node[lastcheck=~/2021-*./][operator]{
    color: #0000ff;
    fill-color: #55aa00;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2020-*./],
  node[check_date=~/2020-*./],
  node[last_check=~/2020-*./],
  node[last_checked=~/2020-*./],
  node[lastcheck=~/2020-*./]{
    color: #ffff00;
    fill-color: #aa5500;
    fill-opacity: 0.8;
  }
  node[collection_times:lastcheck=~/2020-*./][operator],
  node[check_date=~/2020-*./][operator],
  node[last_check=~/2020-*./][operator],
  node[last_checked=~/2020-*./][operator],
  node[lastcheck=~/2020-*./][operator]{
    color: #0000ff;
    fill-color: #aa5500;
    fill-opacity: 0.8;
  }
}}

More complex recursion

Example: Simplest possible map call

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 Overpass Turbo because it requires all nodes of a way or members of a relation to be present.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  <;
);
out meta;


The operator "<" does here all the required backwards resolution of membership links of ways and relations. You could also break this up into step-by-step backwards recursion:

  • First, get all relations linking to the just found nodes: rel(bn);
  • Then, get all ways linking to the just found nodes: way(bn);
  • Finally, get all relations linking to the just found ways: rel(bw);

To complete the list of backwards membership resolution, rel(br); would find relations that have the just found relations as members.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  rel(bn)->.x;
  way(bn);
  rel(bw);
);
out meta;

Display result: (Overpass Turbo doesn't show), JSON, XML.

Completed ways, but not relations

This call includes all nodes in the bounding box, all ways in the bounding box, all member nodes of these ways whether these are inside the bounding box or not, and all relations that have such a node or such a way as members. For the moment, the call of way with a bounding box makes the query sometimes slow. I will work on it, but please be patient for the moment. Please observe that not all returned relations are displayed in Overpass Turbo because Overpass Turbo requires all nodes of a way to be present.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  rel(bn)->.x;
  way(50.746,7.154,50.748,7.157);
  node(w)->.x;
  rel(bw);
);
out meta;

Display result in an OpenLayers map OpenLayers map.

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.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  <;
  >;
);
out meta;

Display result: OpenLayers map.

Here "<" does backwards membership resolution and ">" does forward membership resolution. In particular, ">" collects for all just found relations their member nodes, their member ways, and the member nodes of these member ways. This again can also be broken down into its building blocks:

  • node(w) collects the nodes that are members of the just found ways
  • node(r) does the same with the just found relations
  • way(r) collects the ways that are members of the just found relations

The statement rel(r) collects the relations that are members of the just found relations, but it is not invoked here. Now, the same query as before in a more step-by-step fashion:

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  rel(bn)->.x;
  way(bn);
  rel(bw);
);
(
  ._;
  way(r);
);
(
  ._;
  node(r)->.x;
  node(w);
);
out meta;

Display result: OpenLayers map.

Also relations on relations

This call includes additionally all relations on relations that after five steps of descent arrive at members in the bounding box. Their members are deliberately not included because that might end up with a significant part of all map data of Germany; i.e., several hundred megabyte of data. Note also that five levels of descent usually is more than enough to get all backlinks. If you doubt you have all backlinks, just add another rel(br); statement and see whether more data comes back.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  rel(bn)->.x;
  way(bn);
  rel(bw);
);
(
  ._;
  way(r);
);
(
  ._;
  node(r)->.x;
  node(w);
);
(
  ._;
  rel(br);
  rel(br);
  rel(br);
  rel(br);
);
out meta;

Display result: OpenLayers map.

Server Status Queries

If you're self hosting an OverPass API server it can be useful to query it to check it's health.

Data Last Updated

Every query returns an `osm_base` timestamp which tells you the last time the data was updated (see this question on the OSM Help Forum for more details). In XML it's `<meta osm_base="2020-07-01T11:54:03Z"/>` and in JSON it's under `osm3s.timestamp_osm_base`. You can make any query to retrieve this date, use `out count;` to minimise the amount of data returned by not including any nodes.

try it yourself in overpass-turbo
(
  node(50.746,7.154,50.748,7.157);
  <;
);
out count;


See also

Internal links

External links