# FAA Airport Status - Airport Delays, Closures, Ground Stops (`neverempty/us-airport-delays`) Actor

Live FAA airport delays for the whole US National Airspace System: ground stops, ground delay programs, airport closures, arrival and departure delays, airspace flow programs and CTOP. Delay lengths parsed into minutes. Official FAA feed, no API key, no scraping.

- **URL**: https://apify.com/neverempty/us-airport-delays.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Travel, Developer tools, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 delayed airport returneds

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

## FAA Airport Status - Airport Delays, Closures, Ground Stops

**Every US airport the FAA currently reports a problem at - ground stops, ground delay programs, airport closures, arrival and departure delays - as clean rows, with delay lengths already turned into minutes.**

This reads the **FAA's own airport status feed** (`nasstatus.faa.gov`). It is a work of the US government: public domain, no API key, no rate-limit contract. `robots.txt` on that host is `User-agent: *` with nothing disallowed. Nothing here parses a web page. No proxies required.

### Why not just read the feed yourself

Because it is **XML**, and it has three traps that make a straightforward reader lose airports without any error appearing.

#### Trap 1: the same section appears more than once, and the second one is easy to lose

The feed is `Delay_type*` - a *repeating* element. The same `<Name>` can appear in several blocks. Here is a real response from 2026-08-31:

```
<Delay_type><Name>Ground Stop Programs</Name>  ... ORD ...
<Delay_type><Name>Airport Closures</Name>      ... SNA, LMT, HTS ...
<Delay_type><Name>Airport Closures</Name>      ... LFT, ASE ...      ← a second block
```

A reader that looks up "the section called Airport Closures" gets **3 of the 5 closed airports**. LFT and ASE simply are not in its output, and nothing looks wrong. This Actor walks every block and returned all 6 affected airports from that response.

#### Trap 2: airspace programs have no airport code, so filtering by airport hides the cause

`Airspace_Flow` and `CTOP` have no `ARPT` element at all - they are national programs. Filter naively by airport and they vanish, taking the *reason* your airport is delayed with them. Every row carries `scope` (`airport` or `airspace`), and **filtering by airport keeps the airspace-wide programs** and tells you it did.

#### Trap 3: one airport can have both an arrival delay and a departure delay

The FAA's own DTD says `Delay (ARPT, Reason, Arrival_Departure, Arrival_Departure?)` - up to **two** blocks per airport, distinguished only by a `Type` attribute. Take the first and you silently drop the other direction. This Actor fills `arrival*` and `departure*` on the same row.

#### And the smaller ones

- **Entity references arrive raw.** A real closure reason contained `&#xd;`. Left alone it ends up inside your text.
- **Delay lengths are prose** - `"45 minutes"`, `"1 hour and 30 minutes"`. Every one is parsed into `...Minutes` so you can threshold and sort. **A length that cannot be parsed becomes `null`, never `0`** - "no delay" and "could not read it" are different answers, and the raw string is always kept next to it. (Across 136 captured responses from 2003 to 2026, every duration the FAA has published takes one of three shapes: `N minutes`, `N hours`, `N hours and N minutes`.)
- **The FAA can add new sections, or rename the ones it has.** Anything not in the published DTD is reported in `RUN_UNKNOWN_LISTS`. And if a known section is present but its entries cannot be read - the sign that an element was renamed - that goes in `RUN_EMPTY_LISTS` and the log says so, **because the alternative is answering "no delays anywhere" while airports are shut**.
- **The published DTD does not match the live feed.** The DTD declares `FCA_Start_DateTime`; the feed actually sends `FCA_StartDateTime`. Checked against 136 captured responses spanning 2003-2026. A parser written from the specification alone returns `null` for every airspace program time. This Actor reads both.

### What you get

One row per affected airport, with the same columns every time.

| Field | Example | Notes |
|---|---|---|
| `rowType` | `delay` | `no-delays` on the single row returned when nothing is wrong |
| **`delayType`** | **`AIRPORT_CLOSURE`** | `GROUND_STOP`, `GROUND_DELAY`, `AIRPORT_CLOSURE`, `ARRIVAL_DEPARTURE_DELAY`, `AIRSPACE_FLOW`, `CTOP` |
| `delayTypeName` | `Airport Closures` | The FAA's own heading |
| **`airport`** | **`ORD`** | Validated as a 3-4 character code |
| `reason` | `thunderstorms` | For closures, the raw NOTAM text |
| `endTime` | `7:45 am CDT` | Ground stops |
| `averageDelay` / `averageDelayMinutes` | `45 minutes` / `45` | Ground delay programs, airspace flow, CTOP |
| `maximumDelay` / `maximumDelayMinutes` | `1 hour and 30 minutes` / `90` | |
| `closureStart` / `reopen` | `Aug 31 at 04:30 UTC.` | Closures |
| `arrivalMin/MaxMinutes`, `arrivalTrend` | `16` / `30` / `Increasing` | The FAA publishes these as 15-minute buckets |
| `departureMin/MaxMinutes`, `departureTrend` | `31` / `45` / `Decreasing` | Both directions on one row |
| **`scope`** | **`airport`** | `airspace` for national programs that have no airport code |
| `controlElement` | `FCAJX7` | Airspace flow programs, and the FCA name for CTOP |
| `programName` | | CTOP |
| `startTime` / `stopTime` | `20220513150000` | Airspace flow and CTOP |
| `afpStartTime` / `afpEndTime` | `1800` / `2359` | Airspace flow. **A different clock from `startTime`** - kept separate, not merged |
| `altitudeFloor` / `altitudeCeiling` | `200` / `500` | Airspace flow |
| `updateTime` | `Mon Aug 31 11:30:45 2026 GMT` | When the FAA last updated the feed |
| `source` | `FAA nasstatus.faa.gov airport status (official, public domain)` | |

#### A real row

```json
{
  "rowType": "delay",
  "delayType": "GROUND_STOP",
  "delayTypeName": "Ground Stop Programs",
  "airport": "ORD",
  "reason": "thunderstorms",
  "endTime": "7:45 am CDT",
  "updateTime": "Mon Aug 31 11:30:45 2026 GMT",
  "source": "FAA nasstatus.faa.gov airport status (official, public domain)"
}
```

#### When nothing is wrong

The National Airspace System is often completely clear. That is a real answer, not a failure, so you get one row saying so - **and you are not charged for it**:

```json
{
  "rowType": "no-delays",
  "ok": true,
  "delayCount": 0,
  "updateTime": "Mon Aug 31 12:00:00 2026 GMT",
  "note": "No delays anywhere in the US National Airspace System right now. This is a valid result, not an error."
}
```

### Input

```json
{
  "airports": [],
  "delayTypes": [],
  "maxRetries": 4
}
```

- **`airports`** - codes to keep, such as `ORD` or `KORD`. Empty means every airport the FAA is reporting.
- **`delayTypes`** - keep only `GROUND_STOP`, `GROUND_DELAY`, `AIRPORT_CLOSURE`, `ARRIVAL_DEPARTURE_DELAY`, `AIRSPACE_FLOW`, `CTOP`. Empty means all.
- **`maxRetries`** - retries when the FAA feed does not respond.

### Typical uses

- **Airline and charter operations** - poll on a schedule and alert when a ground stop starts at an airport you fly to.
- **Travel and booking products** - show the traveller why a flight is late, from the primary source rather than a mirror.
- **Freight and ground logistics** - a ground stop at ORD or a closure at a spoke airport changes your dispatch plan.
- **Delay analytics** - `...Minutes` fields are ready for thresholds and time series.

### What it does when something is wrong

- **If you name airports and none of them are usable, the run fails.** It does **not** quietly return the whole country and charge you for it.
- **A `4xx` from the FAA is reported as a rejected request, not an outage**, and is not retried.
- If the feed does not answer, or answers with something that is not the airport status document, the run is **retried and then fails with the reason** in `RUN_ISSUES` - never an empty dataset that reads as "no delays".
- Malformed XML - a tag that never closes, or a mismatched nesting - **throws** rather than being half-read.
- **A response that arrives truncated is retried**, not reported as a permanent failure. On a live operational feed that is the most common transient fault.
- If you set a maximum total charge and the run hits it, the run **stops and says the result is incomplete**.

### Pricing

Pay per result: one charge per delayed airport row. The "no delays" row and failed runs are **not charged**.

### Source and licence

All data comes from the **US Federal Aviation Administration** (`nasstatus.faa.gov`), a work of the US federal government and therefore in the public domain. The structure follows the FAA's published `AirportStatus.dtd`. This Actor adds the XML handling, the repeated-section fix, the minute parsing and the unknown-section reporting described above.

# Actor input Schema

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

Airport codes to keep, such as "ORD" or "KORD". Leave empty to get every airport the FAA currently reports a delay for. If you give codes and none of them are usable, the run fails rather than quietly returning the whole country.

## `delayTypes` (type: `array`):

Keep only these kinds: GROUND\_STOP, GROUND\_DELAY, AIRPORT\_CLOSURE, ARRIVAL\_DEPARTURE\_DELAY, AIRSPACE\_FLOW, CTOP. Leave empty for all of them.

## `maxRetries` (type: `integer`):

How many times to retry when the FAA feed does not respond. It is a live operational feed, so one retry is usually enough.

## Actor input object example

```json
{
  "airports": [],
  "delayTypes": [],
  "maxRetries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

One row per airport affected by a delay, plus a single row when nothing is delayed.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/us-airport-delays").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/us-airport-delays").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 '{}' |
apify call neverempty/us-airport-delays --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/us-airport-delays"
        }
    }
}

```

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/OnV3KzUkbbU6WmD8j/builds/JqmzUCqilKGaQRRCs/openapi.json
