# Live Aircraft Position Tracker (`apt_marble/live-aircraft-position-tracker`) Actor

Track every aircraft flying right now over a region, a map box, an airport, a callsign or a tail number. One row per aircraft with position, altitude, speed, heading, climb rate, route, aircraft type, operator and the tail number most trackers hide.

- **URL**: https://apify.com/apt\_marble/live-aircraft-position-tracker.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 aircraft position collecteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Live Aircraft Position Tracker

See what is flying right now — over a whole region, over a box you draw yourself, into and out of one airport, or a single aeroplane you name. Every aircraft comes back as one clean row with its position, altitude, speed, heading, climb rate, route, aircraft type, operator and **tail number**, which most public trackers hide. Point it at Europe and get thousands of live aircraft; point it at one tail number and find out exactly where that aeroplane is this minute. No account and no login are needed — just run it.

### What you can do with it

- **Power a live map or dashboard.** Pull every aircraft over your region on a schedule and drive a map, a flight board or an internal ops screen.
- **Find one aeroplane.** Give a tail number and get its position, altitude, route and speed right now — the fleet-tracking question that ordinary flight lookups cannot answer because they hide the registration.
- **Watch an airport.** Everything currently flying to or from JFK, LHR or DXB, inbound and outbound, with how far each arrival still has to go.
- **Follow a specific flight.** Track by callsign and get only that flight — near-matches such as BAW1170 when you asked for BAW117 are counted and thrown away, never handed to you as your flight.
- **Build a movements dataset.** Run it every few minutes and keep the rows to build your own history of who flew where, on what aircraft, and when.
- **Spot business and private aviation.** Turn on aircraft details and each row names the registered owner, manufacturer and full model — the only way to tell whose jet just landed.
- **Feed a research or logistics model.** Altitude bands, climb rates, ground speed, routes and aircraft types for a whole region in one table.

### What you get

One row per aircraft. A real, abridged record — every value below is what this actor produced from one collected answer, with aircraft details switched off:

```json
{
  "callsign": "UAL1",
  "registration": "N81107",
  "flightNumber": "UA1",
  "airlineIcao": "UAL",
  "aircraftType": "B789",
  "originIata": "SFO",
  "originAirport": "San Francisco International Airport",
  "originCity": "San Francisco",
  "destinationIata": "SIN",
  "destinationAirport": "Singapore Changi Airport",
  "destinationCity": "Singapore",
  "latitude": 18.6769,
  "longitude": 155.3201,
  "altitudeFt": 38004,
  "altitudeM": 11584,
  "groundspeedKt": 516,
  "groundspeedKmh": 955.6,
  "verticalSpeedFpm": 0,
  "headingDeg": 253,
  "onGround": false,
  "squawk": null,
  "kmToDestination": 5912.9,
  "icao24": "ab0f8b",
  "positionSource": "satellite",
  "isIdentityWithheld": false,
  "hasFullDetail": false,
  "detailStatus": "not_requested",
  "trackedBy": "callsign",
  "trackedValue": "UAL1",
  "observedAt": "2026-08-16T15:37:36.000Z",
  "collectedAt": "2026-08-16T12:57:41.208Z"
}
```

Coordinates are passed through exactly as the source published them — it gives two decimal places on some answers and four on others, and neither is rounded off nor padded out here. `kmToDestination` is the straight-line distance from that position to the destination airport: this 787 was 5,912.9 km short of Singapore when it was seen.

Switch aircraft details on and three more fields are filled in from the aircraft registry: `operator`, `manufacturer` and `aircraftDescription`. For the Virgin Atlantic 787 in the same run those read `Virgin Atlantic Airways`, `Boeing` and `Boeing 787 9`.

Alongside the table you get a **run summary**: how many aircraft were collected, how many reads were made, how many reads found genuinely nothing, and how many reads could not be completed. Those last two are never merged — see *Limits* below.

### Input reference

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `mode` | choice | `area` | What to track: a map area, an airport, a flight callsign, or a tail number. |
| `region` | choice | `europe` | For map areas: Europe, North America, South America, Africa, Middle East, Asia, Oceania, North Atlantic, the whole world, or a custom box. |
| `north`, `south`, `west`, `east` | number | — | The four edges of your own box, in degrees. Used when `region` is *Custom box*. |
| `airports` | list | `["JFK"]` | For airport mode: three-letter airport codes. Unknown codes are refused before the run starts. |
| `callsigns` | list | — | For callsign mode: radio callsigns such as `BAW117`. Only exact matches are returned. |
| `registrations` | list | — | For tail-number mode: registrations such as `G-VNYL` or `N154QS`. |
| `coverage` | choice | `standard` | *Standard* returns the fullest record per aircraft. *Wide* adds a second, broader observation network so aircraft the first does not report still appear, with route and tail-number fields left empty on those extras rather than guessed. Those extras never take the place of a fuller record: every aircraft the first network reported is delivered first, and the second network is only asked for what is left of your row limit. Applies to map areas and callsigns. |
| `includeOperatorDetail` | boolean | `false` | Add the registered owner, manufacturer and full model to every aircraft. Charged separately. |
| `maxDetailLookups` | number | `250` | Ceiling on how many aircraft get those extra details. |
| `includeGroundAircraft` | boolean | `true` | Keep aircraft taxiing or parked as well as airborne ones. |
| `minAltitudeFt` | number | — | Keep only aircraft at or above this altitude. |
| `maxAltitudeFt` | number | — | Keep only aircraft at or below this altitude. |
| `airlines` | list | — | Keep only these three-letter operator codes, e.g. `BAW`, `DLH`. |
| `aircraftTypes` | list | — | Keep only these short type codes, e.g. `A320`, `B789`. |
| `maxRows` | number | `500` | The run stops once this many aircraft have been collected. |
| `tileSizeDegrees` | number | `20` | For map areas: the size of each square the region is read in. Smaller squares give more complete coverage of busy airspace and take longer. |
| `maxAreaTiles` | number | `12` | Ceiling on how many squares are actually read. If the area needs more than this, the run reads this many squares spread evenly across the whole area and the summary records the rest as not read — Europe at the default square size needs 8, the whole world needs 162. |
| `parallelReads` | number | `3` | How much the run does at once. Three suits almost every job. |

### Output fields

| Field | What it is |
| --- | --- |
| `icao24` | The aircraft's unique transponder address — the safest key to join rows on. |
| `registration` | The tail number painted on the aircraft. |
| `callsign` | The radio callsign the flight is operating under. |
| `flightNumber` | The commercial flight number, where the flight has one. |
| `airlineIcao` | Three-letter operator code. |
| `operator` | The registered owner or operator, in words. Filled in when aircraft details are switched on. |
| `operatorCode` | The operator's short code, from the same lookup. |
| `aircraftType` | Short aircraft type code, e.g. `B789`. |
| `aircraftDescription` | Manufacturer and model in words, e.g. `Boeing 787 9`. With aircraft details on. |
| `manufacturer` | Aircraft manufacturer. With aircraft details on. |
| `latitude`, `longitude` | Position at the moment it was observed. |
| `altitudeFt`, `altitudeM` | Altitude, in feet and in metres. |
| `groundspeedKt`, `groundspeedKmh` | Speed over the ground, in knots and km/h. |
| `verticalSpeedFpm` | Climb or descent rate in feet per minute; negative is descending. |
| `headingDeg` | Direction of travel in degrees. |
| `squawk` | Transponder code, where it is published. |
| `onGround` | True when the aircraft is on the ground rather than airborne. |
| `isGlider` | True for gliders. |
| `originIata`, `originAirport`, `originCity`, `originCountry` | Where the flight started, with the airport named in full. |
| `destinationIata`, `destinationAirport`, `destinationCity`, `destinationCountry` | Where it is going, named in full. |
| `kmToDestination` | Straight-line distance still to fly, where the destination is known. |
| `registrationCountry` | The country the aircraft is registered in, where it is stated. |
| `positionSource` | How the position was observed, where the source states it — for example `satellite` for space-based reception. Empty when it is not stated. |
| `isIdentityWithheld` | True when the aircraft publishes no identity at all. Roughly one aircraft in nine is in this state: its tail number, flight number and route are withheld and only the position, altitude and type remain. |
| `hasFullDetail` | True when the owner and model lookup succeeded for this aircraft. |
| `detailStatus` | Why a row has no extra detail: not requested, nothing published, or the limit was reached. |
| `trackedBy`, `trackedValue` | Which of your inputs produced this row. |
| `observedAt` | When the position itself was observed. |
| `collectedAt` | When this actor collected it. |

### Pricing

You pay per event, so a small run costs a small amount.

| What you pay for | Price |
| --- | --- |
| Each aircraft returned | **$2.00 per 1,000** |
| Each aircraft you asked for full owner and model details on | **$0.80 per 1,000** |

Aircraft with nothing published in the registry are never charged the detail price.

**Worked example.** You track everything over Europe twice an hour and cap each run at 500 aircraft, with aircraft details switched off. Each run returns about 500 aircraft, so it costs about **$1.00**. Over a day that is 48 runs — roughly **$48**. Turning aircraft details on for all 500 adds **$0.40** a run.

A second example: you watch a fleet of 20 tail numbers every ten minutes with details on. A run returns at most 20 rows, so it costs about **$0.04 plus $0.016** — **$0.056 a run**. Every ten minutes is 144 runs a day, so that is about **$8 a day**, or roughly **$240 a month**. Halve the frequency and you halve the bill: every twenty minutes is about **$4 a day**.

### Limits & what this actor cannot do

- **Positions are a snapshot at the moment of collection.** An aircraft moving at 500 knots covers about 15 km in a minute, so a position is already history by the time you read it. Run it more often for a fresher picture; there is no live stream.
- **Positions can lag the aircraft.** What is published is what was last received from the aircraft, which is not always this second — `observedAt` tells you exactly how old each position is, and you should use it rather than assuming the row is current.
- **Coverage is not uniform.** Reception is dense over Europe, North America and East Asia and thin over oceans, deserts and polar regions. Some aircraft over water are reported from space and some are not reported at all. An aircraft missing from the results has not necessarily landed.
- **A very large area returns what the source publishes, not everything airborne.** Any single square has a ceiling on how many aircraft it will report, so busy airspace read in one big square comes back truncated. The run summary tells you which squares hit that ceiling; smaller squares fix it, at the cost of a longer run.
- **When you cap the number of aircraft, the cap is shared out across the area.** Ask for 300 aircraft over Europe and you get roughly the same number from each part of it, not 300 from whichever corner answered first. Squares with less to give do not waste their share.
- **A big area is read in squares, and a limit on the squares is a limit on the coverage.** If the area needs more squares than `maxAreaTiles` allows, the squares that are read are spread evenly across the whole area and the rest are reported as not read. The whole world at the default square size needs 162 squares, so a world run on the default limit of 12 is a sample of the planet, not a census of it — the summary says so in numbers, and an unread square is never reported as an area with no aircraft.
- **Wide coverage cannot reach across the 180° meridian.** A map square that spans it can only be given to the second observation network as two areas, which it does not accept, so those squares get no second read. The main read covers them normally, and the run summary counts them rather than passing over them in silence.
- **Not every aircraft carries every field.** Military, private and some general-aviation aircraft publish no tail number, no route and sometimes no callsign — about one aircraft in nine in a wide sweep. Those rows are flagged with `isIdentityWithheld` and the missing fields are left empty. Nothing is filled in from anywhere else, nothing is estimated, and a placeholder the source puts where a callsign should be is never passed off as one.
- **A read the source refuses is reported as a failed read, never as "no aircraft".** This source answers a large share of reads with a valid, well-formed document containing nothing at all, and the actor detects it, retries, and — if it still cannot get a live answer — records the read as failed. It will never tell you an area is empty when it could not confirm that it is. The same rule covers a change in the shape of what the source publishes: aircraft that arrive in a form this actor cannot read are counted in the summary and the read is reported as failed, so a format change can never be delivered to you as an empty sky.
- **It cannot look backwards.** This is a "where is it now" actor. It does not return where an aircraft was an hour ago, its flight path, or its history.
- **It cannot tell you about the flight's commercial status.** No delays, no gates, no scheduled or estimated times, no bookings.
- **Tail-number and callsign lookups only find aircraft that are currently flying or on the ground with their transponder on.** An aeroplane in a hangar is not visible to anyone.
- **Owner and model details come from an aircraft registry.** Registries lag reality: an aircraft sold last month may still show its previous owner, and some airframes have nothing published at all.
- **Speed depends on the size of the job and on the source's own response times**; no fixed throughput is promised.
- **The source's terms govern automated access.** You are responsible for using the data lawfully and in line with those terms, and for handling any personal data in line with applicable privacy law.

### FAQ

**Do I need an account on the source site?**
No. Nothing to sign up for and nothing to configure.

**Does it need my login or password?**
No. It never asks for credentials of any kind.

**Can I schedule it?**
Yes. Scheduling every few minutes is the normal way to use it — that is how you build a live map or a movements history.

**Are these positions live?**
They are the most recent published positions at the moment the run collected them. Every row carries `observedAt` so you can see for yourself how fresh it is, and a fast-moving aircraft has already travelled some distance by the time you read the row.

**Why does an aircraft I can see on a map not appear in my results?**
Three ordinary reasons: it was outside the area or filters you set; the square it is in hit the source's per-square ceiling; or nothing in the observation network can hear it right now. The run summary distinguishes the first two.

**Why do some rows have no tail number or route?**
Because the aircraft does not publish them. Military and many private aircraft withhold their identity — those rows are marked `isIdentityWithheld` — and the wide-coverage setting adds aircraft that are only reported as a position and a callsign. Those fields are left empty rather than guessed.

**What happens if the source will not answer?**
The run retries, and any read it still cannot complete is counted as a failed read in the summary. A run where nothing could be read finishes as a failure — you will never get a green run with an empty table that quietly means "we could not look".

**Can I get every aircraft in the world in one run?**
Yes, but you must raise the map-square limit, and the exact numbers matter. At the default square size of 20 degrees the whole world is **162 squares**, while `maxAreaTiles` defaults to 12 — so a world run on the defaults reads 12 squares, spread evenly across the planet, and the run summary reports the other 150 as not read. For full coverage set `region` to the whole world, **keep `tileSizeDegrees` at 20, set `maxAreaTiles` to 162** and raise `maxRows`. Making the squares *smaller* is counterproductive here: no run may read more than 200 squares, and below 18 degrees the world needs more squares than that, so smaller squares mean less of the world, not more. Smaller squares are the right tool for one busy region, not for the planet.

**Why does my run say some squares were not read?**
Because the area you chose needs more squares than the map-square limit allows. The run reads squares spread evenly across the whole area rather than working from one corner, and the summary tells you how many squares the area needs (`areaSquaresNeededForFullCover`), how many were read, and how many were not. Nothing is claimed about the squares that were not read — an unread square is never reported as an area with no aircraft.

# Actor input Schema

## `mode` (type: `string`):

Pick how the aircraft you want should be selected. Track everything flying over a map area, everything flying to or from one airport, one specific flight by its radio callsign, or one specific aeroplane by its tail number.

## `region` (type: `string`):

Used when you track a map area. Choose a ready-made part of the world, or choose "Custom box" and set the four edges below. Larger regions are read as a grid of squares, because the source publishes only so many aircraft for any single square. A region that needs more squares than the square limit below allows is sampled — the squares that are read are spread evenly across the whole region and the summary reports the rest as not read. At the default square size Europe needs 8 squares and the whole world needs 162.

## `north` (type: `integer`):

Latitude of the top edge of your box, between -90 and 90. Only used when the region is set to "Custom box".

## `south` (type: `integer`):

Latitude of the bottom edge of your box, between -90 and 90, and below the northern edge.

## `west` (type: `integer`):

Longitude of the left edge of your box, between -180 and 180.

## `east` (type: `integer`):

Longitude of the right edge of your box, between -180 and 180.

## `airports` (type: `array`):

Used when you track airports. Three-letter airport codes such as JFK, LHR or DXB. Every aircraft currently flying to or from each one is returned. Unknown codes are refused before the run starts rather than coming back as an empty result.

## `callsigns` (type: `array`):

Used when you track callsigns. The radio callsign a flight is flying under, such as BAW117 or UAL1. Only an exact match is returned — near-matches such as BAW1170 are counted in the run summary and never sold to you as your flight.

## `registrations` (type: `array`):

Used when you track tail numbers. The registration painted on the aircraft, such as G-VNYL or N154QS. Returns that aeroplane's current position if it is flying.

## `coverage` (type: `string`):

Standard returns the fullest record for every aircraft: tail number, aircraft type, operator, route and position. Wide additionally sweeps a second, broader observation network so aircraft the first one does not report still appear — those extra aircraft carry position and callsign only, with the route and tail-number fields left empty rather than guessed. Wide applies to map areas and callsigns. Extra aircraft never take the place of a fuller record: every aircraft the first network reported is delivered first, and the second network only fills what is left of your row limit.

## `includeOperatorDetail` (type: `boolean`):

Look up the registered owner, the manufacturer and the full model name for every aircraft returned — the fields a plain position feed does not carry, and the only way to tell whose business jet you are looking at. Charged separately per aircraft; aircraft with nothing published are never charged for.

## `maxDetailLookups` (type: `integer`):

A ceiling on the extra detail work, so a broad run cannot cost more than you expect. Set it to the number of aircraft whose owner and model you actually need.

## `includeGroundAircraft` (type: `boolean`):

Keep aircraft that are taxiing or parked at a stand as well as those in the air. Turn this off for airborne traffic only.

## `minAltitudeFt` (type: `integer`):

Leave empty for no lower limit. Set, for example, 20000 to keep only aircraft at cruise. Aircraft whose altitude is not published are dropped when a limit is set, never treated as zero.

## `maxAltitudeFt` (type: `integer`):

Leave empty for no upper limit. Set, for example, 10000 to keep only aircraft in the approach and departure phase.

## `airlines` (type: `array`):

Leave empty for every operator. Three-letter operator codes such as BAW (British Airways), UAL (United) or DLH (Lufthansa).

## `aircraftTypes` (type: `array`):

Leave empty for every type. Short type codes such as A320, B789 or E75L.

## `maxRows` (type: `integer`):

The run stops adding aircraft once it reaches this number. This is the main control on what a run costs you.

## `tileSizeDegrees` (type: `integer`):

Used when you track a map area. The source publishes only so many aircraft for a single square, so a busy square comes back truncated. Smaller squares mean more complete coverage and a longer run; 20 is a good balance and 5 to 10 suits busy airspace such as western Europe.

## `maxAreaTiles` (type: `integer`):

A ceiling on how many squares are actually read, so a large region with a small square size cannot run away with your run. If the region needs more squares than this, the run reads this many spread evenly across the whole region and the summary reports the rest as not read — nothing is claimed about a square that was not read. Europe needs 8 squares at the default square size; the whole world needs 162.

## `parallelReads` (type: `integer`):

Higher finishes sooner; lower is gentler on the source and slightly more reliable. Three suits almost every run.

## Actor input object example

```json
{
  "mode": "area",
  "region": "europe",
  "north": 52,
  "south": 50,
  "west": -1,
  "east": 1,
  "airports": [
    "JFK",
    "LHR"
  ],
  "callsigns": [
    "BAW117"
  ],
  "registrations": [
    "G-VNYL"
  ],
  "coverage": "standard",
  "includeOperatorDetail": false,
  "maxDetailLookups": 250,
  "includeGroundAircraft": true,
  "airlines": [
    "BAW",
    "DLH"
  ],
  "aircraftTypes": [
    "A320",
    "B789"
  ],
  "maxRows": 500,
  "tileSizeDegrees": 20,
  "maxAreaTiles": 12,
  "parallelReads": 3
}
```

# Actor output Schema

## `aircraft` (type: `string`):

Every aircraft found, one row each, with position, altitude, speed, route and aircraft identity.

## `aircraftCsv` (type: `string`):

The same table as a CSV download.

## `runSummary` (type: `string`):

Counts of aircraft collected, reads made, reads that found nothing, and reads that could not be completed — kept apart, never merged.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "airports": [
        "JFK"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/live-aircraft-position-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "airports": ["JFK"] }

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/live-aircraft-position-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "airports": [
    "JFK"
  ]
}' |
apify call apt_marble/live-aircraft-position-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apt_marble/live-aircraft-position-tracker"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HyxBSZhW1dQMoWoUC/builds/ovLbY14Hq5tANh2p3/openapi.json
