OpenStreetMapbuilding:levelsGeoJSONFeatures APIShadows

How to get building heights and calculate shadows from OpenStreetMap

Get building footprints from OpenStreetMap by querying closed ways tagged building. Read height from the height tag, or estimate it from building:levels when it is missing. Then compute shadows. Vector tiles clip footprints and drop height tags, so they are the wrong input.

Try a building queryJoel Sten · Aug 7, 2026How to get building heights and calculate shadows from OpenStreetMap

Short answer: query closed ways tagged building from the OSM Features API to get footprints as polygons. Read height from the height tag, or estimate it from building:levels when that is missing. Keep the result as GeoJSON and compute from there.

Want to grab a beer on a sunny terrace? First you need building footprints and heights, unfortunately. Urban Sun Finder does this for pubs, cafes, and restaurants in Nordic winter: fetch building polygons, read height from OSM tags, then test whether a neighbour's shadow reaches the seat.

Vector tiles for basemaps can include building heights, but they are the wrong input. They clip polygons at tile edges, simplify vertices by zoom, and drop important tags. That is fine for drawing a map. It is useless for shadow math. See Features API vs vector tiles for the full comparison. The rest of this post covers the building data first, then checks sun.

Fetch building polygons from OSM

Query closed ways tagged building as unclipped polygons. In the OSM Features API, that would be type=way&way_shape=polygon&tags=building. Height is not a required OSM tag, so mappers record it in different ways. Usually it is a single height tag. Sometimes it is only a floor count, in building:levels or building:floors. If you need to measure distance from a venue to nearby buildings, ask for centroid=true.

curl Python
curl "https://api.maplark.com/v3/osm_features?bbox=18.06,59.33,18.08,59.34&type=way&way_shape=polygon&tags=building&centroid=true&limit=10000" \
  -H "Authorization: Bearer swHAvOmreIm_uew6eqbn1UbIsVQT6p8PRohmqmAJiu4"

The above query gets building polygons and their tags from the bounding box as GeoJSON. You can run this same query on the OSM Features playground or copy the curl into a terminal. The demo key is shared and rate limited; get a free key if you hit 429.

Derive building height from OSM tags

OSM has no single required height tag. Walk the tags in this order and record whether the result is measured or estimated:

  1. Listed height: Check the height and building:height tags. Ground to roof top, metres by default.
  2. Floor count: Estimate height by counting floors. building:levels is facade floors only; roof space is roof:levels. Use 3 to 3.5 m per floor. Check additional tags like levels or building:floors if needed.
    • Formula: (building:levels + roof:levels) * metres_per_level.
  3. Rough guess: est_height when the mapper only estimated.
  4. Your default (for example 10 m) when nothing parses. Flag it as fully estimated.

Three buildings, same block:

  • height=18: 18 m (measured).
  • building:levels=5: height is 17.5 m if you use 3.5 m per floor.
  • building only: your default, fully estimated. Many buildings look like this.

Prefer height when it disagrees with building:levels. Ignore ele (terrain elevation above sea level) and maxheight (vehicle clearance). Bridges use min_height for the gap underneath; height is still ground to top. Split volumes use building:part. Rooftop bars are a separate query: look for outdoor_seating=roof or location=roof on amenities inside the footprint, then check access=*. A flat roof is not a public terrace.

How do I count buildings in an area?

Use the count endpoint before you download anything. The same filters apply, and the response is a single total: GET /v2/osm_features/count?bbox=18.06,59.33,18.08,59.34&type=way&way_shape=polygon&tags=building. Count first to see how large the result will be.

Frequently asked questions

How do I get building footprints from OpenStreetMap?
Query type=way with way_shape=polygon and tags=building. Add centroid=true if you need a point for each building.

How do I get the height of a building from OpenStreetMap?
Read the height tag first, then building:levels times a floor height, then a default for buildings with no height data. Mark which values are measured and which are estimated.

What is the difference between height and building:levels?
height is the ground to roof top distance in metres. building:levels is the number of floors above ground. Floors give an estimate, not a measurement.

Why are some buildings missing height?
Many OSM buildings only have the building tag. There is no height data to read, so use a default and flag it as estimated.

Check if a place is in sun or shadow

Direct sun is a geometry-and-weather check. Each input answers one question:

  • Horizon: if solar elevation is zero or negative, there is no daylight.
  • Azimuth: does the sun face the seating? If the cafe sits on the north wall and the sun is in the south, the building itself blocks it. Nearby buildings only matter if they sit in that sun direction.
  • Elevation: does not make a place "more sunny." It only sets shadow length: shadow_length = height_above_venue / tan(elevation). Low sun, long shadows. If a taller neighbour is closer than that length, it shades the seat.
  • Cloud cover: a chance of beams, not a guarantee. Geometry can be wide open and still overcast. Clouds never change shadow length.
  • Rain: even with a clear line of sight, outdoor seating is a poor bet.

Takeaway

Fetch full OSM polygons and tags once, derive height in your own code, then compute shadows. That is the gap a basemap tile cannot fill, and why MapLark returns unclipped geometry instead of a pre-rendered layer. Docs for the query parameters are on the developer page.

Run the building query

Open the Features playground, then grab a free API key for your own bbox.

Try it live Get your API key