Using QGIS actions to add buildings from OpenStreetMap to a map

QGIS actions and an OpenStreetMap API

In april of this year I went to the 2023 QGIS User Conference in ‘s-Hertogenbosch. At that conference there was a very interesting workshop on using actions in QGIS by Ujaval Gandhi of Spatial Thoughts. At the time I decided to attend another workshop and talk that were also very interesting, but luckily Ujaval shared his workshop notes online, so I tried all his examples after the conference and I was really impressed with the possibilities of actions in QGIS. You should really check them out.

A couple of weeks ago I read a blog post by Brendan Ashworth of Bunting Labs about their API to download from OpenStreetMap. The thing that caught my attention was the fact that this API delivers GeoJSON data as a result of a request. So I wondered if it would be possible to use this API in QGIS actions. In this blog post I will show you how I did just that.


The thing I tried to achieve is that if I activate the QGIS action and I click on a point in a point type layer, all buildings from OpenStreetMap in a radius of 100 meter show up on the map in a Temporary Scratch Layer, including all the data from tags in the Attribute Table.

Where to put the QGIS action code?

First I added a point layer with addresses to my QGIS Project. Any point layer will work for this example. If you would like to do the same for a polyline or a polygon layer, you would need to change code below to do so. If you have added your point layer, you should open its properties and select “Actions” in the left panel of the Properties window.

There you click on the button with the green plus sign below the (probably empty) Action List.

A new window pops up where you can set the settings for your action. Make sure you set the Type to “Python” and add at least a Description. You can also add a Short Name and an Icon. The Action Scopes Canvas and Feature should be checked.

You can now add the code in the “Action Text” text area.

The code for the QGIS action

The following code is the one I created to achieve the above objective. In the comments I describe what each step does.

# Import the necessary packages
import requests
import json
from qgis.core import Qgis, QgsVectorLayer, QgsJsonUtils, QgsProject

# Get the coordinates of the point you clicked on in the map.  The parts between [% %] are QGIS Expressions. Those work the same as if you would use them in the Field Calculator.  Python interprets it as the resulting value.
pointxy = "[%replace(to_string(x(transform($geometry, @layer_crs ,'EPSG:4326'))),',','.')%],[%replace( to_string(y(transform($geometry, @layer_crs ,'EPSG:4326'))),',','.')%]"

# The parameters of the request to the API. Replace MY_API_KEY with your own key, that you can get at  We request all buildings within a radius of 100 meter around the current point.
params = {
  "tags": "building=*",
  "api_key": "MY_API_KEY",
  "center": pointxy,
  "radius": "100"

# Make the request to the extract-in-radius endpoint of the API
response = requests.get("", params=params)

# Convert the response to a JSON string
geoj = json.dumps(response.json())

# Find the attribute fields in the GeoJSON 
fields = QgsJsonUtils.stringToFields(geoj)

# Get the features from the GeoJSON and use the previously found attribute fields
feats = QgsJsonUtils.stringToFeatureList(geoj,fields, None)

# If the API returns 1 or more features, execute the code below else print a message to the console log
if len(feats) > 0:
    # Get the geometry type of the result of the request.  For our buildings example it will always be a Multipolygon, but if you request something else from the API, it could be another type.
    geom_type = feats[0].geometry().type()
    if geom_type == QgsWkbTypes.PointGeometry:
        geotype = "MultiPoint"
    elif geom_type == QgsWkbTypes.LineGeometry:
        geotype = "MultiLineString"
    elif geom_type == QgsWkbTypes.PolygonGeometry:
        geotype = "MultiPolygon"
        print("geometry type not defined in the result")
    # Create an empty Temporary Scratch Layer called "Buildings" of the previously found geometry type
    layer = QgsVectorLayer(geotype, "Buildings", "memory")
    # Add the attribute fields to the Temporary Scratch Layer
    # Add the empty Temporary Scratch Layer to the map 
    registry = QgsProject.instance()
    # Add each feature from the API request to the Temporary Scratch Layer
    for feature in feats:
    print("no features found in the geoJSON")   

# Reload the visualisation of the Temporary Scratch Layer

The result

This action results in a Temporary Scratch Layer with the polygons of the buildings 100 meter around the clicked point.

One Reply to “Using QGIS actions to add buildings from OpenStreetMap to a map”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.