303,525 datasets indexed1,419 publishers
Open Data IndexThe index of open data about the Netherlands
Open Data Index›Build›What is flying over my house right now?
AppGetting startedTraffic and transport

What is flying over my house right now?

A small app that shows every few minutes which aircraft are within 25 km of your address, how high, how fast and whether they are climbing or descending, using OpenSky's live positions and without an account.

Your AI assistantOpen Data Index MCP on
The Open Data Index MCP server is on in your chat, so the assistant reads this project and its sources itself.
You paste this project's prompt
The assistant fetches from Open Data Index
  • geef_project("vliegtuigen-boven-je-huis")
  • geef_bron("opensky")
  • geef_bron("schiphol-vluchten")
The assistant

I have the project, the tested calls and the pitfalls. I'll build a app with OpenSky Network and Schiphol flight data. This is how it could look:

You build this yourself. Copy the prompt into Claude, ChatGPT or Cursor, with the MCP server on, or follow the steps below.

Follow the steps
SkywatchAMSTELVEEN · 25 KM23:34:14
N09018027010 km20 kmSCHIPHOL4 on groundRYR275K11,400 mTRA16M381 m ↓LIFELN1381 mWMT54310,759 m
38over NL
28airborne
8within 25 km
397credits left
callsigndist.alt.km/hhdg
RYR275K13.611,400848093°level
TRA16M14.6381253057°desc
LIFELN116.6381193044°level
WMT54324.710,759847101°level
Mockup

This is a mockup, not a working version, with a real OpenSky reading on Saturday 17 October 2026 at 23:34 around the point in Amstelveen from the project. Turn the MCP server on with the address on For AI.

Who it's for

People living near Schiphol and other airports who want to know what is flying over, children and hobbyists, and local media covering aircraft noise complaints.

What you get

A page (or a widget on a Raspberry Pi with a screen) listing the aircraft within 25 km of your home: callsign, distance, altitude, speed, heading and whether they are climbing, descending or cruising, plus the number of aircraft over the whole country. Click an aircraft for the route it flew today.

Test run on Friday 16 October 2026 at 23:50:54 for a point in Amstelveen, east of Schiphol: 38 aircraft over the Netherlands, 29 of them airborne. Within 25 km: 4 aircraft. Transavia TRA7X descending at 152 metres and 252 km/h, 10.4 km away, TRA81H at 2,934 metres and 510 km/h also descending, and two aircraft on the ground at Schiphol (KLM1682 and THY3EZ). The route of TRA81H came from southern Italy (first point 37.49 N 15.23 E, near Catania). The script used 2 of the 400 free daily credits.

Flights to and from Schiphol: 478 thousand in 2025, 37% more than in 1997

Flights to and from Schiphol, 1997 – 2025, in thousand. The highest point was 2018 (499).

Source: CBS, tabel 37478hvv (Luchtvaart; maandcijfers Nederlandse luchthavens van nationaal belang) · opgehaald 25 oktober 2026Open the table Single block

How you could start5 steps

  1. 1

    Request positions inside a box

    Without an account OpenSky returns the current state vectors of all aircraft inside a box (lamin, lomin, lamax, lomax in degrees). Each state is a list, not an object: [0] icao24, [1] callsign (padded with spaces to 8 characters), [2] country of registration, [5] longitude, [6] latitude, [7] barometric altitude in m, [8] on ground, [9] speed in m/s, [10] heading, [11] vertical rate in m/s, [13] GPS altitude. Fields can be null. The robots.txt of opensky-network.org returns 403 to everyone; the API itself does answer and is documented at openskynetwork.github.io/opensky-api.

    https://opensky-network.org/api/states/all?lamin=52.1&lomin=4.5&lamax=52.5&lomax=5.2
    x-rate-limit-remaining: 392
    {"time":1792187264,"states":[["4bb101","THY3EZ  ","Turkey",1792187253,1792187253,4.7303,52.3232,null,true,10.8,317.81,null,null,null,null,false,0],
     ["48520b","TRA7X   ","Kingdom of the Netherlands",1792187264,1792187264,4.5078,52.209,899.16,false,118.85,90.99,-7.15,null,1036.32,"1000",false,0],
     ["486258","KLM1682 ","Kingdom of the Netherlands",1792187264,1792187264,4.6969,52.2736,91.44,false,65.93,5…
  2. 2

    Count your credits

    Anonymously you get 400 credits a day for /states. A box up to 25 square degrees costs 1 credit (the whole Netherlands is 11.9), larger costs 2 to 4. The X-Rate-Limit-Remaining header says how many are left; at 0 you get 429 with X-Rate-Limit-Retry-After-Seconds. Two requests every 5 minutes is 576 a day: too many. So ask every 4 minutes, only during the day, or create a free account (4,000 a day, OAuth2 client credentials).

  3. 3

    Filter on distance and work out climbing or descending

    The box is rectangular; then compute the real distance with the haversine formula and keep only what falls within your radius. Vertical rate below -2 m/s = descending, above 2 = climbing. Speed is in m/s: multiply by 3.6 for km/h. Use the GPS altitude when present; the barometric altitude depends on air pressure. Aircraft on the ground often have no altitude.

  4. 4

    Show where an aircraft came from

    /tracks/all with icao24 and time=0 returns the route of the current flight as a list of points [time, latitude, longitude, altitude, heading, on ground]. It has its own allowance (separate from /states). The flight lists (/flights/arrival, /flights/departure) return 403 anonymously: 'You cannot access historical flights'.

    https://opensky-network.org/api/tracks/all?icao24=48683e&time=0
    {"icao24":"48683e","callsign":"TRA81H  ","startTime":1.792178801E9,"endTime":1.792187882E9,
     "path":[[1792178801,37.4879,15.2291,1219,82,false],[1792178801,37.4879,15.2291,1219,82,false],
             [1792178828,37.4923,15.2694,1828,79,false], … ]}
    (160 punten; het laatste: [1792187882, 52.2609, 4.6641, 0, 57, false])
  5. 5

    Departure and arrival times? Only with a Schiphol account

    OpenSky doesn't know about gates or delays. Those are in Schiphol's Public Flight API, but that needs an account, an application and an OAuth2 token (valid 30 minutes) and has strict terms: only to help travellers, nothing kept longer than 24 hours, no statistics or historical analysis and no passing on to third parties. A 'what is flying over my house' counter does not fit that. Without a token the API returns 401. We have no account and did not test further.

    https://api.schiphol.nl/public/public-flights/v4/flights?scheduleDate=2026-10-16&flightDirection=A&page=0
    {
      "message":"Unauthorized",
      "request_id":"ba1cf8526ebba40cf84f856b56520549"
    }
    (HTTP 401)

How the sources fit together

  • OpenSky NetworkSchiphol flight datavia roepnaam (callsign 'KLM1682') ≈ vluchtnummer (flightName 'KL1682', IATA-code in plaats van ICAO)

    OpenSky uses the ICAO callsign (KLM1682), Schiphol the IATA flight number (KL1682). Converting needs an airline table (/airlines in the Schiphol API). For traveller information only; storing for statistics is not allowed.

  • OpenSky NetworkCBS StatLinevia maand (CBS 37478hvv, luchthaven Schiphol)

    For trends (aircraft movements per month), use CBS table 37478hvv instead of hoarding live positions.

Let AI build it

Paste this prompt into Claude, ChatGPT, Cursor or Lovable. It names the real endpoints, the join keys and the pitfalls, so the assistant writes working code straight away. Always check the result against the source itself.

Build a small web app 'What is flying over my house?' with Python 3 (FastAPI or Flask) or Node 20, plus one HTML page with a Leaflet map.

Data: OpenSky Network REST API, anonymous, docs at https://openskynetwork.github.io/opensky-api/rest.html
- Positions: GET https://opensky-network.org/api/states/all?lamin=…&lomin=…&lamax=…&lomax=…
- Route of one aircraft: GET https://opensky-network.org/api/tracks/all?icao24=<hex>&time=0

What you need to know:
- Each state is a list: [0] icao24, [1] callsign (strip spaces), [2] country of registration, [3] time_position, [4] last_contact, [5] lon, [6] lat, [7] baro_altitude (m), [8] on_ground, [9] velocity (m/s), [10] true_track (degrees), [11] vertical_rate (m/s), [13] geo_altitude (m), [14] squawk. Almost anything can be null.
- Anonymous: 400 credits a day for /states; a box up to 25 square degrees costs 1. /tracks has its own allowance. Read X-Rate-Limit-Remaining and show it. On 429: respect X-Rate-Limit-Retry-After-Seconds.
- Refresh at most once every 4 minutes (or let the user click 'refresh now') and cache the response on the server: all visitors share one call.
- /flights/* returns 403 anonymously. Don't scrape the website (robots.txt returns 403).
- Licence: non-commercial use only. Credit 'Data: OpenSky Network'.
- Compute the real distance to the house with haversine and filter on a 25 km radius. Climbing/descending from vertical_rate (±2 m/s). Speed × 3.6 = km/h.
- Don't show departure or arrival times: those are only in the Schiphol Public Flight API (account, OAuth2, travellers only, keep at most 24 hours, no statistics).

Output: an input for an address or coordinates (don't geocode via Nominatim without reading its usage policy; let the user click on the map), a map with the aircraft as arrows in their direction of flight, a list sorted by distance (callsign, altitude, km/h, climbing/descending), and on click today's route as a line. At the bottom: time of the data, number of aircraft over the Netherlands and remaining credits.

Try it yourself

The core of the project in a small script. Needs: Python 3.9+ en requests. Tested on 2026-10-16; below is the real output of that run.

# Wat vliegt er nu boven mijn huis? OpenSky Network, anoniem (400 credits per dag, dit script kost er 2).
# Python 3.10+ en requests. Gebruik alleen niet-commercieel (voorwaarden OpenSky).
import math, requests
from datetime import datetime
from zoneinfo import ZoneInfo

UA = {"User-Agent": "mijn-vliegtuigradar/1.0 (+jij@voorbeeld.nl)"}
API = "https://opensky-network.org/api/states/all"
HUIS = (52.3017, 4.8640)   # breedte, lengte: Amstelveen, ten oosten van Schiphol; vul je eigen adres in
STRAAL_KM = 25

def toestanden(lamin, lomin, lamax, lomax):
    r = requests.get(API, params={"lamin": lamin, "lomin": lomin, "lamax": lamax, "lomax": lomax},
                     headers=UA, timeout=30)
    if r.status_code == 429:
        raise SystemExit(f"Dagtegoed op, wacht {r.headers.get('X-Rate-Limit-Retry-After-Seconds')} s")
    r.raise_for_status()
    return r.json(), r.headers.get("X-Rate-Limit-Remaining")

def afstand_km(a, b):   # haversine
    p1, p2 = math.radians(a[0]), math.radians(b[0])
    d = math.sin((p2 - p1) / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(math.radians(b[1] - a[1]) / 2) ** 2
    return 6371 * 2 * math.asin(math.sqrt(d))

# 1. Heel Nederland (11,9 vierkante graad = 1 credit)
nl, _ = toestanden(50.75, 3.2, 53.7, 7.22)
lucht = [s for s in nl["states"] or [] if not s[8]]
tijd = datetime.fromtimestamp(nl["time"], ZoneInfo("Europe/Amsterdam")).strftime("%d-%m-%Y %H:%M:%S")
print(f"{tijd}: boven Nederland {len(nl['states'] or [])} toestellen, {len(lucht)} in de lucht")

# 2. Rond mijn huis: vak van ruim 50 bij 50 km (1 credit), daarna precies op afstand filteren
dlat, dlon = STRAAL_KM / 111, STRAAL_KM / (111 * math.cos(math.radians(HUIS[0])))
hier, over = toestanden(HUIS[0] - dlat, HUIS[1] - dlon, HUIS[0] + dlat, HUIS[1] + dlon)
rijen = []
for s in hier["states"] or []:
    icao, roep, land, _, contact, lon, lat, baro, grond, snelheid, koers, stijg = s[:12]
    if lat is None or lon is None:
        continue   # geen positie in de laatste 15 seconden
    km = afstand_km(HUIS, (lat, lon))
    if km > STRAAL_KM:
        continue
    hoogte = s[13] if s[13] is not None else baro      # geo_altitude, anders barometrisch
    fase = "aan de grond" if grond else ("daalt" if (stijg or 0) < -2 else "stijgt" if (stijg or 0) > 2 else "kruist")
    rijen.append((km, (roep or "?").strip(), icao, land, hoogte, (snelheid or 0) * 3.6, koers, fase))

print(f"Binnen {STRAAL_KM} km van {HUIS}: {len(rijen)} toestellen (nog {over} credits vandaag)")
for km, roep, icao, land, h, v, k, fase in sorted(rijen)[:8]:
    hoogte = f"{h:,.0f} m".replace(",", ".") if h is not None else "? m"
    print(f"  {km:5.1f} km  {roep:8} {icao}  {land:15.15} {hoogte:>8}  {v:4.0f} km/u  koers {k or 0:3.0f}  {fase}")
Output
16-10-2026 23:50:54: boven Nederland 38 toestellen, 29 in de lucht
Binnen 25 km van (52.3017, 4.864): 4 toestellen (nog 389 credits vandaag)
    6.8 km  KLM1682  486258  Kingdom of the       ? m    32 km/u  koers 239  aan de grond
   10.4 km  TRA7X    48520b  Kingdom of the     152 m   252 km/u  koers  58  daalt
   10.7 km  THY3EZ   4bb101  Turkey               ? m    25 km/u  koers 222  aan de grond
   12.2 km  TRA81H   48683e  Kingdom of the   2.934 m   510 km/u  koers 268  daalt

Where it goes wrong

  • The allowance runs out fast. 400 credits a day is one request every 3.6 minutes, all day. A page refreshing every 10 seconds is out within an hour. Cache on the server and refresh only when someone is looking.
  • Country is the country of registration, not the airline. SAS1804 showed up as 'Ireland' in our first test, THY3EZ as 'Turkey'. The country follows from the transponder's ICAO24 address.
  • Not everything is visible. OpenSky only hears aircraft picked up by a receiver nearby; low aircraft and aircraft without ADS-B (some military, small planes) are missing. At 23:50 there were 38 over the Netherlands; during the day many more.
  • Altitude and position can be missing. Aircraft on the ground had no altitude; positions older than 15 seconds become null. Skip aircraft without a position and show '?' for an empty altitude.
  • Schiphol data may not be used for this. The Public Flight API forbids statistics, historical analysis and storing longer than 24 hours. A nuisance counter or an archive of flights over your house is built with OpenSky, not with Schiphol.

Take it further

  • Add noise: count per hour how many aircraft below 1,000 metres come within 5 km of your house and put that next to the noise measurements of an airport monitoring station.
  • An e-ink display on the window sill: a Raspberry Pi showing the nearest aircraft every 5 minutes with callsign, altitude and the city of departure (first point of /tracks).
  • Monthly trends: for aircraft movements per month use CBS table 37478hvv (Schiphol and the other airports of national importance) instead of storing live data.
  • Free account: with 4,000 credits a day you can refresh every minute and, with extended=1, also see each aircraft's category (light, heavy, helicopter).

The sources2

OpenSky Network

OpenSky NetworkWorld, aircraft

Aircraft positions picked up by a global network of receivers. Without an account, limited to current positions.

OpenAPIReal timeTraffic and transport
Up to date
updated less than an hour ago

Schiphol flight data

Royal Schiphol GroupNetherlands, flight

Schiphol's Public Flight API gives per flight the scheduled and expected times, status, gate, terminal, baggage belt, aircraft type and route, plus lists of airlines, destinations and aircraft types. Free after registration, but the terms are strict: only to help travellers, nothing stored for more than 24 hours and no statistics.

Free keyAPIReal timeTraffic and transport
Reachable
every minute

More to build