Building applications with map data

What is OpenStreetMap?

OpenStreetMap is a free database of labelled map data with over 9 billion labelled features. It’s used to power navigation apps, search for nearby restaurants and shops, finding campsites near National Parks, and infinitely more use cases.

Most of the web maps you see online are built entirely from OpenStreetMap data. One rule of thumb is if you can see it in person, it’s labelled on OpenStreetMap. The above picture shows a map of downtown San Francisco, where the following were extracted from OSM’s database:

  1. Highway, roads, and bridges
  2. Building outlines
  3. Coastline and parks

Finding the correct tags

Each feature in OpenStreetMap is tagged, often 10+ times. Each tag is a key and value combination in the form key=value. For example, the above features could be tagged:

  1. highway=primary, highway=residential, man_made=bridge
  2. building=*
  3. natural=coastline, leisure=park

We use * (asterisk) to signal any value should be accepted. This is especially useful for buildings, where building=yes and building=house could both be drawn as buildings, and names, to filter out unnamed items for labelling.

Finding the right combination of tags for the features you want to download starts with searching the TagInfo website for your target feature.

To help users find the right tag inside your application, you can embed an OpenStreetMap tag search in your map. This lets users search “National Park” and get served potential OSM tags that are relevant to their query.

Download features as GeoJSON

Once you’ve identified the right tags, you can download the features in an area. One type of feature you might want to download from OSM is hiking trails near a user. We can get a list of walking paths by exporting from OpenStreetMap with the tag highway=path and filter for named hiking trails by also asking for name=*.

We can download features by hitting the OSM extract API with our tags highway=path&name=*. Here’s an example searching in Australia’s state of Tasmania:

curl --get 'https://osm.buntinglabs.com/v1/osm/extract' \
     --data "tags=highway%3Dpath%26name%3D*" \
     --data "api_key=demo" \
     --data "bbox=142.987061,-43.874138,149.370117,-39.104489"

This will give us a GeoJSON FeatureCollection, which has an array of features.

Here’s a sample with the capital of Tunisia:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {
                "name": "Tunis"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [10.181667, 36.806389]
            }
        },
        // ... more features
    ]
}

features is an array of the downloaded features. Here’s one of those features from our hiking trail extract, the “Wilson Bight Track” hiking trail in Tasmania, Australia:

{
    "type": "Feature",
    "properties": {
        "highway": "path",
        "name": "Wilson Bight Track",
        "operator": "Parks and Wildlife",
        "source": "GPS",
        "surface": "sand"
    },
    "geometry": {
        "type": "MultiLineString",
        "coordinates": [[
            [146.1334686279297, -43.51723861694336],
            [146.1333770751953, -43.51741027832031],
            [146.13339233398438, -43.51757049560547],
            [146.13345336914062, -43.51802444458008],
            [146.13352966308594, -43.518333435058594],
            [146.13360595703125, -43.51850128173828],
            [146.12998962402344, -43.51995086669922],
            [146.12889099121094, -43.52079772949219]
        ]]
    }
}

This feature, like all features in our API, comes formatted as a GeoJSON. GeoJSON is a common JSON-derived geospatial feature format. Each feature object denotes an individual point, area, or line on the Earth’s surface. It comes with a number of properties as a JSON dictionary. Keys are typically lowercase and describe the geometry’s purpose on the map. The geometry contains coordinates in (longitude, latitude) order.

Mapping the features

If you are downloading these features to a browser, we recommend using the MapLibre project because it’s free and open source.

Here’s an example of rendering our downloaded features in the map. This could be useful for dynamically rendering features near a user.

Building the map

First, we’ll create a map. You can follow the MapLibre quickstart here.

// Create the map
var map = new maplibregl.Map({
    container: 'map',
    style: 'https://demotiles.maplibre.org/style.json',
    center: [146.1333770751953, -43.51741027832031],
    zoom: 5
});

Adding our hiking trails

We can insert the hiking trail GeoJSON we downloaded above directly as a GeoJSON source:

map.on('load', function () {
    // Show the hiking trail on top of the map
    map.addSource('hiking_trails', {
        'type': 'geojson',
        'data': {
            "type": "FeatureCollection",
            "features": [{
                "type": "Feature",
                "properties": {
                    "highway": "path",
                    "name": "Wilson Bight Track",
                    "operator": "Parks and Wildlife",
                    "source": "GPS",
                    "surface": "sand"
                },
                "geometry": {
                    "type": "MultiLineString",
                    "coordinates": [[
                        [146.1334686279297, -43.51723861694336],
                        [146.1333770751953, -43.51741027832031],
                        [146.13339233398438, -43.51757049560547],
                        [146.13345336914062, -43.51802444458008],
                        [146.13352966308594, -43.518333435058594],
                        [146.13360595703125, -43.51850128173828],
                        [146.12998962402344, -43.51995086669922],
                        [146.12889099121094, -43.52079772949219]
                    ]]
                }
            }]
        }
    });

    // Draw it as a line
    map.addLayer({
        'id': 'hiking_trails_as_line',
        'type': 'line',
        'source': 'hiking_trails',
        'layout': {},
        'paint': {
            'line-color': '#00008B',
            'line-opacity': 0.8
        }
    });
});

Finally, because MapLibre doesn’t render it automatically, we’ll draw it as a line.

Attribution

Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL.