An open API service indexing awesome lists of open source software.

https://github.com/bellingcat/adsb-history

Collect and query ADS-B data to find aircraft and trends based on geographic region(s), altitude, bearing, aircraft type and more.
https://github.com/bellingcat/adsb-history

ads-b aircraft flight-tracking osint

Last synced: about 1 month ago
JSON representation

Collect and query ADS-B data to find aircraft and trends based on geographic region(s), altitude, bearing, aircraft type and more.

Awesome Lists containing this project

README

          

Turnstone logo

Turnstone is a full-stack application for collecting, storing, and querying historical ADS-B aircraft tracking data. This system enables spatial and temporal queries on aircraft positions, with support for filtering by geographic regions, altitude, speed, bearing, aircraft type and more.

![The search interface](docs/images/1.png)
![A graph of search results over time](docs/images/2.png)
![Results aggregated by aircraft](docs/images/3.png)

For more information and background, see [the associated presentation at WHY2025](https://media.ccc.de/v/why2025-242-eye-on-the-sky-building-investigative-journalism-tools-for-analyzing-airplanes).

## Overview

This project consists of three main components:

1. **Backend Data Loading** - Processes tar1090 heatmap binary files and loads them into PostgreSQL
2. **Backend API** - Flask-based REST API with Firebase authentication
3. **Frontend** - Vue.js web application with interactive maps and query builder

## Architecture

### Database Schema

The main `adsb` table contains:
- `t` - Timestamp with timezone
- `hex` - Aircraft ICAO hex identifier
- `flight` - Flight number/call sign
- `alt` - Altitude in feet
- `gs` - Ground speed in knots
- `geom` - PostGIS geometry (point) for location
- `bearing` - Heading in degrees
- `registration` - Aircraft registration number
- `typecode` - Aircraft type code
- `category` - Aircraft category (e.g., "Airliner", "General Aviation", "UAV")
- `military` - Boolean flag for military aircraft

The `modes` table provides additional aircraft metadata based on ICAO hex codes. This file is identical to the data distributed in the https://github.com/wiedehopf/tar1090-db repo, with the addition of a column for category, and boolean flag for military use, both generated from the aircraft type information with a large language model. This is distributed in `backend-data-loading/modes.csv`. See below for more information about generating this file.

## Prerequisites

### Backend Data Loading
- Python 3.x
- PostgreSQL with PostGIS extension
- Required Python packages (see `backend-data-loading/requirements.txt`)

### Backend API
- Python 3.x
- PostgreSQL database (configured)
- Firebase project with authentication enabled
- Required Python packages (see `backend-api/requirements.txt`)

### Frontend
- Node.js (v16+)
- npm or yarn
- Firebase project (matching backend)

## Installation

### 1. Backend Data Loading

```bash
cd backend-data-loading
pip install -r requirements.txt
```

**Database Setup:**

```sql
-- Create database
CREATE DATABASE adsb;

-- Enable PostGIS
CREATE EXTENSION postgis;

-- Create main table
CREATE TABLE adsb (
t TIMESTAMP WITH TIME ZONE,
hex TEXT,
flight TEXT,
alt BIGINT,
gs DOUBLE PRECISION,
geom GEOMETRY(Point, 4326),
bearing DOUBLE PRECISION,
registration TEXT,
typecode TEXT,
category TEXT,
military BOOLEAN
);

-- Create temporary loading table
CREATE TABLE adsb_temp (
t DOUBLE PRECISION,
hex TEXT,
flight TEXT,
squawk TEXT,
lat DOUBLE PRECISION,
lon DOUBLE PRECISION,
alt BIGINT,
gs DOUBLE PRECISION,
type INTEGER
);

-- Create modes table for aircraft metadata
CREATE TABLE modes (
hex TEXT PRIMARY KEY,
registration TEXT,
typecode TEXT,
category TEXT,
military BOOLEAN,
owner TEXT,
aircraft TEXT
);

COPY modes FROM 'modes.csv' DELIMITER ',' CSV HEADER;

-- Create indexes
CREATE INDEX adsb_t_idx ON adsb (t);
CREATE INDEX adsb_hex_idx ON adsb (hex);
CREATE INDEX adsb_geom_idx ON adsb USING GIST (geom);
CREATE INDEX adsb_category_idx ON adsb (category);
```

### 2. Backend API

```bash
cd backend-api
pip install -r requirements.txt
```

**Environment Variables:**

Create a `.env` file in `backend-api/`:

```env
# Database Configuration
DB_HOST=localhost
DB_NAME=adsb
DB_USER=your_db_user
DB_PASS=your_db_password
DB_PORT=5432

# Firebase Configuration
FIREBASE_PROJECT_ID=your-firebase-project-id

# Logging
LOG_FILE=adsb_api.log
```

**Firebase Setup:**

1. Create a Firebase project at https://console.firebase.google.com
2. Enable Authentication (Email/Password, Google, etc.)
3. Download service account credentials JSON
4. Place credentials in `backend-api/` directory (referenced in `firebase_utils.py`)

### 3. Frontend

```bash
cd frontend
npm install
```

**Firebase Configuration:**

Update `frontend/src/firebase.js` with your Firebase project credentials:

```javascript
const firebaseConfig = {
apiKey: "your-api-key",
authDomain: "your-project.firebaseapp.com",
projectId: "your-project-id",
storageBucket: "your-project.appspot.com",
messagingSenderId: "your-sender-id",
appId: "your-app-id"
};
```

## Usage

### Data Loading

Process tar1090 binary files and load into the database:

```bash
cd backend-data-loading
python process_adsb_data.py /path/to/data/directory

# Options:
# --connection-string: Custom database connection string
# --cleanup-files: Delete files after successful processing
# --skip-finalize: Skip finalization (for batch processing)
# --verbose: Enable verbose logging
```

Data can be downloaded from [adsb.lol's data releases](https://github.com/adsblol/globe_history_2025/releases).

For example, data for October 28th, 2025, once downloaded from Github and extracted, can be imported into the database as follows:

```bash
python process_adsb_data.py v2025.10.28-planes-readsb-prod-0/heatmap
```

### Running the API

```bash
cd backend-api
python flask-adsb-api.py
```

The API will start on `http://localhost:5000` by default.

### Running the Frontend

**Development:**
```bash
cd frontend
npm run dev
```

**Production Build:**
```bash
cd frontend
npm run build
```

Built files will be in `frontend/dist/`.

## API Endpoints

### Authentication

All endpoints require Firebase authentication. Include the Firebase ID token in the Authorization header:

```
Authorization: Bearer
```

### GET `/api/adsb/bbox`

Query aircraft positions within a bounding box with optional filters.

**Query Parameters:**
- `bbox` - Bounding box: `min_lon,min_lat,max_lon,max_lat`
- `hex` - Aircraft ICAO hex code
- `flight` - Flight number/call sign
- `start_time` - ISO 8601 timestamp (e.g., `2024-01-01T00:00:00Z`)
- `end_time` - ISO 8601 timestamp
- `min_alt`, `max_alt` - Altitude range in feet
- `min_bearing`, `max_bearing` - Bearing range in degrees (0-360)
- `min_speed`, `max_speed` - Ground speed range in knots
- `military` - Filter military aircraft (`true`/`false`)
- `category` - Aircraft category
- `typecode` - Aircraft type code
- `limit` - Max records (default: 1000, max: 1000000)
- `offset` - Pagination offset (default: 0)

**Response:**
```json
{
"count": 100,
"results": [
{
"t": "2024-01-01T12:00:00Z",
"hex": "a12345",
"flight": "UAL123",
"lat": 37.7749,
"lon": -122.4194,
"alt": 35000,
"gs": 450.5,
"bearing": 270.5,
"registration": "N12345",
"typecode": "B738",
"category": "Airliner",
"military": false,
"owner": "United Airlines",
"aircraft": "Boeing 737-800"
}
]
}
```

### GET `/api/adsb/intersect_bboxes`

Find aircraft that were present in two different bounding boxes within a time period.

**Query Parameters:**
- `bbox1`, `bbox2` (required) - Two bounding boxes
- `min_time_diff`, `max_time_diff` - Time difference constraints in seconds
- All other parameters from `/api/adsb/bbox`

**Response:** Same format as `/api/adsb/bbox` but returns positions from both bounding boxes.

## Frontend Features

### Query Builder
- Interactive map for drawing bounding boxes
- Comprehensive filter controls
- Date/time range selection
- Aircraft type filters
- Altitude, speed, and bearing constraints

### Results Visualization
- Interactive map showing aircraft positions
- Data table with sorting and pagination
- Aggregate statistics by aircraft
- Charts showing temporal distribution
- CSV export functionality

### Query History
- Automatic saving of queries to browser IndexedDB
- Quick replay of previous queries
- Query naming and organization

## Augmenting tar1090-db

The tar1090 project distributes an [aircraft database](https://github.com/wiedehopf/tar1090-db) that has information about each aircraft, including its type designation. For example, the database says that the aircraft with hex code `004014` is a Boeing 777-200 (code B772).

This is augmented by adding ownership information queried from [hexdb.io](https://hexdb.io/). In order to allow searching by natural aircraft type categories (e.g. "business jet" vs. "airliner"), this dataset was further augmented using a large language model (Anthropic Claude 4.0 Sonnet) which takes the aircraft type and typecode as an input (e.g. "B772 BOEING 777-200"), and returns a category ("airliner") and a military true/false value (false). The large language model is only used to produce the category and military values. All other search query values in Turnstone are directly from ADS-B data or tar1090-db.

The augmented file is distributed in `/backend-data-loading/modes.csv`. For more information about this data augmentation process, including the full large language model prompt, see the Jupyter notebook in `/backend-data-loading/augment-aircraft.ipynb`.

*Logo modified from CC licensed photo by [Alberto_VO5](https://www.flickr.com/photos/albertovo5/4646590020).*