A Working Example: Tracking Flights With The OpenSky Network Using VB.NET

Updated September 8, 2026

After searching for a example using the OpenSky Network to track flights in Windows using a program built with VB.NET, I became aware that none of what was available was a “complete” working solution. I believe there were five or six partial solutions which gave hints as to what was required. This full VB.NET solution, while a bit short on the features of much larger viewers, works to present the basic data for flights within a user-defined bounding box, updated every 15 seconds. The features available within this example are:

  • A default bounding box centered on Springfield, Massachussetts. Its 16:9 aspect ratio include Windsor, CT to the south, Northampton, MA to the south, Stockbridge, MA to the west, and Spencer, MA to the east.
  • The bounding box coordinates can be modified by changing the minimum longitude (the westerly edge) and the minimum latitude (the southerly edge). The easterly and northerly edges are then calculated to maintain the 16:9 aspect ratio.
  • A timer set for 15 seconds refreshes the flight list. If there are no flights within the bounding box coordinates, a message in the listbox says so. Refreshing, however, will continue every 15 seconds.
  • A button will disable the timer so the flight list can be examined. The same button can then be used to re-enable the timer.

Bounding box coordinates for a certain area can be found using the tool at: https://boundingbox.klokantech.com/

The real meat of this solution is in module 1, which is listed below. This uses the OAuth2 authorization method which is now used by OpenSky effective March 2026. This code also includes necessary error handling for times when no flights are within the defined bounding box.

Prior to using this solution, go to https://opensky-network.org/ and click Sign In at the top right. Follow the instructions there to create an account to retrieve a clientid and clientsecret. These can then be added to the module containing the code below.
' OpenSky flight tracker example for VB.NET
' Dave Liske
' September 8, 2026
' http://www.cuisinology.com
'
' As of March 2026, the OpenSky Network deprecated old username/password basic authentication.
' All authenticated programmatic access must now request a short-lived OAuth2 Access Token from OpenSky's Keycloak authorization server.

Imports System.Net.Http
Imports System.Net.Http.Headers
Imports Newtonsoft.Json.Linq

Module Module1

    ' To use the OpenSky Network, go to https://opensky-network.org/ and click Sign In at the top right.
    ' Follow the instructions there to create an account to retrieve a clientid and clientsecret.
    Private Const ClientId As String = "lunapiercook-api-client"
    Private Const ClientSecret As String = "5VyyUexkHDrE9TiklTkP8kNaHEFrlqzC"
    Private Const TokenUrl As String = "https://auth.opensky-network.org/auth/realms/opensky-network/protocol/openid-connect/token"

    Public Async Sub GetOpenSkyDataAsync()

        Form1.ListBox1.Items.Clear()

        Using client As New HttpClient()
            Try
                ' Fetch the OAuth2 Access Token
                Dim accessToken As String = Await GetAccessTokenAsync(client)
                If String.IsNullOrEmpty(accessToken) Then
                    Form1.ListBox1.Items.Add($"Failed to retrieve access token.")
                    Return
                End If

                ' Configure the HTTP client to use the Bearer Token
                client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", accessToken)

                ' read the current bounding box from the labels, removing the degree character
                Dim lonmin As String = Form1.LongMinLabel.Text
                Dim lonmax As String = Form1.LongMaxLabel.Text
                Dim latmin As String = Form1.LatMinLabel.Text
                Dim latmax As String = Form1.LatMaxLabel.Text

                Dim lon_min As String = lonmin.TrimEnd("°"c)
                Dim lon_max As String = lonmax.TrimEnd("°"c)
                Dim lat_min As String = latmin.TrimEnd("°"c)
                Dim lat_max As String = latmax.TrimEnd("°"c)

                ' OpenSky REST API endpoint for all current aircraft states within the bounding box
                Dim apiUrl As String = "https://opensky-network.org/api/states/all?lamin=" & lat_min & "&lamax=" & lat_max & "&lomin=" & lon_min & "&lomax=" & lon_max

                ' Send GET request asynchronously
                Dim response As HttpResponseMessage = Await client.GetAsync(apiUrl)

                If response.IsSuccessStatusCode Then
                    Try
                        ' Read the JSON response string
                        Dim jsonResult As String = response.Content.ReadAsStringAsync().Result

                    ' Parse the JSON string
                    Dim apiData As JObject = JObject.Parse(jsonResult)
                    Dim timestamp As Long = CType(apiData("time"), Long)

                    Dim statesArray As JArray = CType(apiData("states"), JArray)

                    Form1.ListBox1.Items.Add($"Data Timestamp (Unix): {timestamp}")
                    Form1.ListBox1.Items.Add($"Total Flights Found: {statesArray.Count}")
                    Form1.ListBox1.Items.Add(New String("-"c, 50))

                        ' Loop through the aircraft
                        For i As Integer = 0 To (statesArray.Count) - 1
                            Dim flight As JArray = CType(statesArray(i), JArray)

                            ' Available states and data types
                            ' Index   Property		    Type
                            ' 0       icao24			string
                            ' 1       callsign		    string
                            ' 2       origin_country	string
                            ' 3       time_position	    int
                            ' 4       last_contact	    int
                            ' 5       longitude		    float
                            ' 6       latitude		    float
                            ' 7       baro_altitude(m)  float  
                            ' 8       on_ground 		boolean
                            ' 9       velocity (m/s)	float
                            ' 10      true_track (deg)  float
                            ' 11      vertical_rate	    float
                            ' 12      sensors			int[]
                            ' 13      geo_altitude	    float
                            ' 14      squawk			string

                            ' OpenSky states returns arrays where indexes represent specific values
                            Dim icao24 As String = flight(0).ToString()
                            Dim callsign As String = flight(1).ToString().Trim()
                            Dim country As String = flight(2).ToString()
                            Dim longitude As String = If(flight(5) IsNot Nothing, flight(5).ToString(), "N/A")
                            Dim latitude As String = If(flight(6) IsNot Nothing, flight(6).ToString(), "N/A")
                            Dim baroaltitude As String = If(flight(7) IsNot Nothing, flight(7).ToString(), "N/A")
                            Dim velocity As String = If(flight(9) IsNot Nothing, flight(9).ToString() & " m/s", "N/A")
                            Dim truetrack As String = If(flight(10) IsNot Nothing, flight(10).ToString(), "N/A")
                            Dim geoaltitude As String = If(flight(13) IsNot Nothing, flight(13).ToString(), "N/A")
                            Dim squawk As String = flight(14).ToString()

                            Form1.ListBox1.Items.Add($"ICAO24:   {icao24}")
                            Form1.ListBox1.Items.Add($"Callsign: {callsign}")
                            Form1.ListBox1.Items.Add($"Country:  {country}")
                            Form1.ListBox1.Items.Add($"Position: Lat {latitude}, Lon {longitude}")
                            Form1.ListBox1.Items.Add($"Barometric Altitude: {baroaltitude} m")
                            Form1.ListBox1.Items.Add($"Speed:    {velocity}")
                            Form1.ListBox1.Items.Add($"Bearing: {truetrack} deg.")
                            Form1.ListBox1.Items.Add($"Geometric Altitude: {geoaltitude} m")
                            Form1.ListBox1.Items.Add($"Squawk: {squawk}")
                            Form1.ListBox1.Items.Add(New String("-"c, 30))

                        Next

                    Catch ex As Exception
                        ' Form1.ListBox1.Items.Add($"An error occurred: {ex.Message}")
                        Form1.ListBox1.Items.Add($"Total Flights Found: 0")
                        Form1.ListBox1.Items.Add($"Recommend moving the bounding box edges.")
                    End Try
                Else
                    ' Form1.ListBox1.Items.Add($"API Request failed: {response.StatusCode} - {response.ReasonPhrase}")
                    Form1.ListBox1.Items.Add($"Total Flights Found: 0")
                    Form1.ListBox1.Items.Add($"Recommend moving the bounding box edges.")
                End If

            Catch ex As Exception
                Form1.ListBox1.Items.Add($"An error occurred: {ex.Message}")
            End Try
        End Using

    End Sub

    Private Async Function GetAccessTokenAsync(client As HttpClient) As Task(Of String)
        Try
            ' Set up the form parameters required for OAuth2 Client Credentials flow
            ' "grant_type" and "client_credentials" only need to be changed for higher levels within Opensky
            Dim tokenRequestData As New List(Of KeyValuePair(Of String, String)) From {
            New KeyValuePair(Of String, String)("grant_type", "client_credentials"),
            New KeyValuePair(Of String, String)("client_id", ClientId),
            New KeyValuePair(Of String, String)("client_secret", ClientSecret)}

            Dim requestContent As New FormUrlEncodedContent(tokenRequestData)
            Dim response As HttpResponseMessage = Await client.PostAsync(TokenUrl, requestContent)

            If response.IsSuccessStatusCode Then
                Dim jsonResponse As String = Await response.Content.ReadAsStringAsync()
                Dim jsonObjects As JObject = JObject.Parse(jsonResponse)

                ' Extract and return the access token
                Return jsonObjects("access_token")?.ToString()
            Else
                Return Nothing
            End If

        Catch ex As Exception
            ' Form1.ListBox1.Items.Add($"An error occurred: {ex.Message}")
            Form1.ListBox1.Items.Add($"Total Flights Found: 0")
            Form1.ListBox1.Items.Add($"Recommend moving the bounding box edges.")
        End Try

    End Function

End Module