Guide

Height, slope and sun side for property listings

In hilly places, buyers ask how high a house stands, how steep the plot is and when it gets the sun. Five lookups give the answers when you save a listing: the height at the house and at four points around it.

Sun
Loading the map…
Click a place or anywhere on the map: the page asks our API for the five heights, as your server would. The shores of Lake Zürich face opposite ways: the east shore to the south-west, the west shore to the north-east. Switch the sun between morning and evening to see which shore gets the light.

How it works

The function asks for the height at the house and at four points 90 m to the north, south, east and west, the spacing of the data. North against south and east against west give the rise in each direction; together they give the slope in percent and the direction in which the ground falls away, which is the side a house there faces. Below a slope of 3 %, the ground counts as flat.

Run it on your server when an agent saves a listing, and store the three values with it. The key stays on the server, and the listing pages make no requests to us.

Python

import math, requests

API = "https://api.overpass.ch/v1/YOUR_API_KEY/elevation"
STEP = 90  # metres to the four neighbours, the grid of the data
SIDES = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west"]

def terrain(lat, lon):
    """Height, slope and the side the ground faces at lat, lon: 5 lookups."""
    dlat = STEP / 111_320
    dlon = STEP / (111_320 * math.cos(math.radians(lat)))
    here = [[lat, lon], [lat + dlat, lon], [lat - dlat, lon], [lat, lon + dlon], [lat, lon - dlon]]
    r = requests.post(API, json={"locations": here}, timeout=30)
    r.raise_for_status()
    h, n, s, e, w = (res["elevation"] for res in r.json()["results"])
    east, north = (e - w) / (2 * STEP), (n - s) / (2 * STEP)  # rise per metre
    slope = math.hypot(east, north) * 100
    downhill = math.degrees(math.atan2(-east, -north)) % 360  # 0 north, 90 east
    return {
        "height_m": round(h),
        "slope_pct": round(slope),
        "faces": SIDES[round(downhill / 45) % 8] if slope >= 3 else "flat",
    }

if __name__ == "__main__":
    print(terrain(47.2760, 8.6530))  # Meilen, above the lake

It prints {'height_m': 529, 'slope_pct': 10, 'faces': 'south-west'}.

PHP

<?php
const ELEVATION_API = 'https://api.overpass.ch/v1/YOUR_API_KEY/elevation';

// Height, slope and the side the ground faces at $lat, $lon: 5 lookups.
function terrain(float $lat, float $lon): array {
    $step = 90; // metres to the four neighbours, the grid of the data
    $dlat = $step / 111320;
    $dlon = $step / (111320 * cos(deg2rad($lat)));
    $here = [[$lat, $lon], [$lat + $dlat, $lon], [$lat - $dlat, $lon], [$lat, $lon + $dlon], [$lat, $lon - $dlon]];
    $answer = file_get_contents(ELEVATION_API, false, stream_context_create(['http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\n",
        'content' => json_encode(['locations' => $here]),
        'timeout' => 30,
    ]]));
    if ($answer === false) {
        throw new RuntimeException('The elevation API did not answer');
    }
    [$h, $n, $s, $e, $w] = array_column(json_decode($answer, true)['results'], 'elevation');
    $east = ($e - $w) / (2 * $step); // rise per metre
    $north = ($n - $s) / (2 * $step);
    $slope = hypot($east, $north) * 100;
    $downhill = fmod(rad2deg(atan2(-$east, -$north)) + 360, 360); // 0 north, 90 east
    $sides = ['north', 'north-east', 'east', 'south-east', 'south', 'south-west', 'west', 'north-west'];
    return [
        'height_m' => (int) round($h),
        'slope_pct' => (int) round($slope),
        'faces' => $slope >= 3 ? $sides[(int) round($downhill / 45) % 8] : 'flat',
    ];
}

print_r(terrain(47.2760, 8.6530)); // Meilen, above the lake

It needs no extension; allow_url_fopen must be on, as it is by default. In WordPress, call it when a listing is saved (the save_post hook) and keep the values in custom fields.

In the listing

Show the values, for example “529 m above sea level, faces south-west”, or turn the side into words about the sun. For the northern half of the Earth:

FacesSun
southmost of the day
south-eastin the morning and at midday
south-westin the afternoon and evening
eastin the morning
westin the evening
north-east, north, north-westless direct sun, above all in winter

In the southern half, swap north and south. Stored as numbers, the values also work in a search: height_m >= 1000 for holiday homes in the mountains, faces IN ('south', 'south-east', 'south-west') for the sunny side.

What it costs

Five lookups per listing, once. For the listings you already have, send the points of up to 2,000 listings in one request of 10,000 locations. The free plan includes 1 million lookups a month, for personal and non-commercial use. For an agency or a portal, the Elevation plan costs €5 a month plus VAT and covers 50 million lookups: 10 million listings.

Good to know

  • The slope is that of the hillside over about 200 m. A single garden can be steeper or flatter: a house on a flat terrace in a steep hillside gets the slope of the hillside.
  • The data measures the surface: in a forest or between large buildings, part of their height is in it. In villages and towns, heights are typically within a few metres. See accuracy.
  • Use the position of the building, for example from your address search or from the map of the listing. Five metres off makes no difference; a few hundred metres can.
  • Where you show the values, credit the elevation data as described in the documentation, for example in the footer of the listing pages.