Wheels Up Get the app

Blog

Your plane is somewhere else right now

I am 19 and I fly across 3 continents for 4 months in 1 week. Around 2 months ago, I tried to find a flight tracker to help me with this, however nothing was quite what I needed. Most of them were very pretty but lacked function, or vice versa.

So I made one.

The most useful thing I learnt

If your flight is delayed, there's a good chance the delay started somewhere else. The plane flying your 6pm flight is going to be doing a lot of different flights in the morning. If there is any delay to any of its legs, there is a high chance you will be delayed.

In 2025, late-arriving aircraft caused about 40% of US delay minutes, more than any other cause (US Bureau of Transportation Statistics).

Airlines will usually not update your departure time until they know roughly how late your plane will be. So for a while, the information is public, but it isn't on your boarding pass yet.

This is what I based my application on.

The obvious solution

FlightAware's AeroAPI provides a flight with an inbound_fa_flight_id. We can just look up this flight and see if it is delayed.

But it's not that straightforward.

The inbound flight is often not known until shortly before the flight. This is why we get the tail number. Each plane has a registration (ZK-NZE), so by finding this we can find out everything the aircraft is doing today. This includes any flights besides the last leg of the flight. Track the tail.

We can do this by basing the application around tracking the tail, and only using the inbound flight ID as a last resort.

Where is this aircraft?

For a flight departing in the next 48 hours that already has a tail number assigned, we can do the following steps:

  1. Look up the recent and upcoming flights using the registration.
  2. Exclude our flight, along with any cancelled/diverted ones.
  3. Exclude any flights that have not started (progress 0%), as we don't know where the aircraft is physically yet.
  4. Only include flights that are departing before ours. Take the latest flight.
  5. If the flight is airborne, then get the current location. If it has landed, then the last location it was reported at will be where it is parked. This will usually be the exact stand.

This is the whole idea. In Kotlin it looks like:

api.getFlightsByRegistration(registration).flights
    .filter { it.fa_flight_id != ownFaFlightId && !it.cancelled && !it.diverted }
    .filter { (it.progress_percent ?: 0) > 0 }          // Has actually departed
    .filter { it.scheduledOut.isBefore(ownDepartureUtc) } // Departing before ours
    .maxByOrNull { it.scheduledOut }                      // Latest flight

The code itself was easy, the actual implementation was harder.

Where I got stuck

0,0 locations. Occasionally the API will return a flight with 0 lat/long. This means there is no real location. This will place the plane in the Gulf of Guinea on the map. I have now made this show as unknown.

Flickering planes. Each location lookup can fail (timeouts, rate limiting, bad data). This meant that the plane would disappear and then appear again after a minute. I now save the last location of the plane and display that for up to 30 minutes. It's better to have an old response than a flickering one.

Cached based on state. The map is checked once every minute. This can result in up to 2 extra API calls per lookup. How long I cache the data depends on the flight:

Costing a couple of cents per flight per user.

Gate departure delay. During departure, the API can lag by a few minutes. There is also no indication of an aircraft being queued for the runway. Due to this I use the aircraft's own location and ground speed to determine if it is at the stand, taxiing or holding short.

Alerts

The background check runs every 15 minutes using Android's WorkManager. This is the shortest interval Android allows for recurring tasks. This means the alerts won't be instant. Sometimes the airport displays will win.

There are 3 one-off alerts for the inbound flight:

Each only triggers once. Once the inbound flight has landed, I stop looking up the flight, as there is nothing new to find.

Where it goes wrong

This is more important than the clever part.

It is an indicator, not a confirmation.

The one that hurt the most: battery optimisation (Android)

To help conserve battery, Android will delay running any processes in the background when either the phone is idle or the internet connection is weak. In my case, nothing crashed or failed. It just delayed the notifications, and they all came through at once as soon as we had a strong signal on Wi-Fi.

On landing I connected to the airport Wi-Fi. All of a sudden 3 notifications came through (gate change, delay, your plane has landed). Some of these had been delayed by an hour.

Reality check

I am a one-man dev in New Zealand. I made this for myself, and all the alerts for all the flights I take in the next 4 months will come from this code. It's called Wheels Up, on Android.

I really believe in this tool and would love to see it scale so that people can reduce their anxiety when it comes to flying.

I am happy to answer any questions about the AeroAPI, tail logic, or WorkManager side in the comments.

Sources