US Airline On-Time & Flight Delay Statistics by Route (BTS)
Pricing
from $4.40 / 1,000 route climatology results
US Airline On-Time & Flight Delay Statistics by Route (BTS)
Historical US flight delay, cancellation and on-time statistics from official BTS data. Rollups by route, airline or airport and month with full delay-cause breakdowns — carrier, weather, NAS, security, late aircraft — honest denominators, cancellation causes and data-vintage on every row.
Pricing
from $4.40 / 1,000 route climatology results
Rating
0.0
(0)
Developer
Kyle Maloney
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Airline On-Time & Delay-Cause Climatology (BTS)
Historical US airline on-time performance, flight delay statistics and delay-cause decomposition by route, airline or airport — computed straight from the US Department of Transportation's official BTS TranStats "Reporting Carrier On-Time Performance (1987-present)" monthly bulk files. Keyless, no scraping, no API key.
Real-time trackers tell you a flight is late today. This actor answers the question the money actually rides on: how often is this route/airline/airport late, how bad is it when it is late, and WHY — air-carrier problems vs extreme weather vs National Aviation System congestion vs security vs late-inbound aircraft — month by month, from the government dataset the airlines themselves are legally required to file. Nobody else on the Store sells the historical, cause-decomposed rollup.
Who this is for
- Air-passenger-rights claim firms (EU261 / ANAC / DOT refunds): establish whether a delay pattern on a route is habitual and carrier-caused (compensable operational issues) or weather/NAS-driven — with the official CancellationCode (A=carrier, B=weather, C=NAS, D=security) counted per month.
- Travel insurers and underwriting analysts: price delay/cancellation cover per route and season from actual disruption base rates, not anecdotes.
- Corporate travel managers and TMCs: pick the reliably-on-time carrier and connection airport per city pair before signing preferred-carrier deals.
- Journalists and analysts: "which airline blames weather the most", "worst day at EWR in June", "cancellation causes at DEN" — one run, official numbers.
- Airport / airline ops and consultants: benchmark on-time performance and the cause mix against competitors, monthly.
- AI agents (MCP): a clean, typed, chainable rollup tool over a 39-year federal dataset that agents cannot practically download and parse themselves (each month is a ~30 MB zip holding a ~277 MB CSV).
What one run costs — read this first
Pricing is pay-per-result: one dataset row = one (group x month) rollup. At $8 per 1,000 rows a row costs $0.008.
| Run | Typical rows | Typical cost |
|---|---|---|
One airline, one month, by route (airlines:["WN"]) | ~600 routes | ~$4.80 (cap with maxResults) |
| All airlines, 2 months, by airline | ~26 | ~$0.21 |
One airport's routes, 2 months (origins:["DEN"]) | ~200-400 | ~$1.60-$3.20 |
One route, 12 months (origins:["DEN"], dests:["LGA"]) | 12 | ~$0.10 |
| Default prefill (WN routes, 2 months, maxResults 500) | 500 | $4.00 |
maxResults (default 500) is a hard billing cap enforced in one audited
code path for every grouping mode. When it bites, rows are dropped
smallest-groups-first and every emitted row carries results_truncated: true —
a capped answer is never passed off as a complete one. A run that cannot answer
(bad input, BTS outage, missing month without allowPartial) fails loudly and
bills nothing.
A single run is capped at 12 months (each month is a ~30 MB download from BTS). Split longer histories across runs.
Example input
{"sinceMonth": "2026-05","untilMonth": "2026-06","airlines": ["WN"],"groupBy": "route","minFlights": 30,"maxResults": 500}
Or a single route across a year, all carriers:
{"sinceMonth": "2025-07","untilMonth": "2026-06","origins": ["DEN"],"dests": ["LGA"],"groupBy": "airline_route","minFlights": 10,"maxResults": 100}
Leave sinceMonth/untilMonth blank and the run defaults to the two most
recent published months — discovered live: BTS publishes with a ~2-3 month
lag, and the actor probes backward from the current month until a file answers.
The month it lands on is reported on every row as latest_month_available.
Grouping modes
groupBy | One row per | Use it for |
|---|---|---|
route (default) | origin-dest x month, across airlines | "How is DEN-LGA overall?" |
airline | reporting carrier x month | League tables, carrier benchmarking |
origin_airport | departure airport x month | Airport ops, connection choice |
dest_airport | arrival airport x month | Inbound reliability |
airline_route | carrier x origin-dest x month | Claims and carrier-level route analysis |
Output fields (the important ones)
Every row is one (group x month). All fields are nullable and documented in the dataset schema; the key ones:
- Identity:
group_by,month,airline,origin,dest,route,airlines_included - Volumes:
total_flights(scheduled, incl. cancelled/diverted),completed_flights,cancelled_flights,diverted_flights,arr_assessed_flights(the arrival-performance denominator) - Rates:
on_time_rate_pct,arr_delay_rate_pct(>=15 min, over assessed flights),cancellation_rate_pct,disrupted_rate_pct(late + cancelled + diverted over ALL scheduled flights — the passenger's-eye number) - Severity:
avg_arr_delay_all_min(early arrivals count negative),avg_arr_delay_delayed_only_min,avg_dep_delay_all_min - Cancellation causes:
cancelled_carrier_count(code A),cancelled_weather_count(B),cancelled_nas_count(C),cancelled_security_count(D),cancelled_unknown_code_count - Delay-cause decomposition:
carrier_delay_minutes,weather_delay_minutes,nas_delay_minutes,security_delay_minutes,late_aircraft_delay_minutes,total_cause_delay_minutes, and the five*_share_pctcolumns — with the denominator published on the row (delayed_flights_with_cause_data/delayed_flights_without_cause_data, see the honesty section below) - Worst day:
worst_day(YYYY-MM-DD) andworst_day_disrupted_flights - Provenance & completeness:
months_requested,months_fetched,months_missing,data_complete,month_rows_scanned,groups_suppressed_below_min_flights,results_truncated,latest_month_available,data_source(the exact BTS zip URL),data_vintage(the file's HTTP Last-Modified — BTS revises files in place),retrieved_at
How the numbers stay honest
This dataset has traps, and the actor is built around them rather than on top of them:
- Blank is not zero. BTS populates the five delay-cause columns ONLY on
flights that arrived 15+ minutes late. Measured on the live May-2026 file:
exactly the 129,511 delayed flights of 611,735 carry all five; every other
row carries five blanks. A naive
Number(x) || 0would fabricate ~482,000 zero-cause flights per month. Here a blank isnull, cause columns arenull(never 0) for a group with no cause data, and every row publishes its own cause denominator. - Cancelled and diverted flights carry NO arrival-delay figures (measured:
all 5,655 cancelled and all 1,734 diverted rows have blank ArrDel15). They
are counted in their own columns and excluded from arrival-performance
denominators —
disrupted_rate_pctis the all-in view. - Delay-cause data only exists from June 2003. A pre-2003 month still rolls
up delays and cancellations correctly; its cause columns read
nullanddelayed_flights_without_cause_datasays why. - A live drift gate runs before anything billable, per month: the real header must contain every column this actor reads (a renamed column fails the run, never emits nulls); the file must hold >=50,000 rows, >=5 carriers and >=100 origin airports; at least one pinned mega-hub (ATL/ORD/DFW/DEN) must appear as an origin; the file's own Year/Month columns must match the month requested (a stale or mislabeled file fails instead of billing); and a negative-control carrier code must match zero rows.
- A missing month never silently vanishes. If BTS hasn't published a
requested month (or the download fails), the run FAILS by default with the
per-month status. Opt in with
allowPartial: trueand every row then reportsmonths_missinganddata_complete: false. - Cheap trap coverage: the BTS 404 page is HTML at a real 404; a
maintenance page at HTTP 200 is detected by byte shape (a zip must start
with
PK) and treated as an outage, never parsed. The zip's month is probed with a ranged GET, not HEAD. The zip's CSV entry is selected by extension because the archive also contains areadme.html.
Use as an MCP tool
This actor works as a chainable MCP tool via https://mcp.apify.com — the
input schema is fully described, month strings are validated with actionable
error messages (an agent sending "Jan 2026" or "2026-13" gets a named
reason, not a silent empty dataset), and a filter that matches nothing fails
with the list of carrier codes actually present in the window. Billing is
unchanged when called as a tool; a run that cannot answer fails without
billing.
Example agent prompt: "Using the BTS on-time climatology tool, compare Southwest and United on Denver routes for the last two published months, grouped by airline_route, and tell me which routes have the worst late-aircraft share."
FAQ
How fresh is the data? BTS publishes with a ~2-3 month lag (measured
2026-08-31: latest file is June 2026, published mid-August). The run discovers
the latest month live and reports it on every row. BTS also revises files in
place — data_vintage carries each file's Last-Modified.
Which airlines are covered? The carriers required to report on-time data — 13 as of 2026-05: AA, AS, B6, DL, F9, G4, MQ, NK, OH, OO, UA, WN, YX. Regional partners report under their own codes (OO = SkyWest, MQ = Envoy, OH = PSA, YX = Republic).
Is this per-flight data? No — this is the climatology rollup (one row per group per month). If you need raw per-flight records, download the BTS PREZIP file directly; it is free.
Can I get 5 years of history? Yes, 12 months per run (each month is a ~30 MB federal download). Loop runs across windows; months back to 1987-10 work, with cause columns starting June 2003.
Why do on_time_rate + delay_rate not include cancellations? They are
arrival-performance rates over flights that actually arrived, matching how
DOT reports them. disrupted_rate_pct gives the all-in probability a
scheduled flight was late, cancelled or diverted.
What do the delay-cause shares mean? Shares of cause-attributed delay minutes on flights that arrived 15+ min late, as filed by the carriers under DOT rules: carrier (maintenance, crew, ops), extreme weather, NAS (airspace congestion, non-extreme weather, airport ops), security, late inbound aircraft. The denominator is on the row.
Data source
US DOT Bureau of Transportation Statistics, TranStats "Reporting Carrier
On-Time Performance (1987-present)", monthly PREZIP bulk files at
transtats.bts.gov/PREZIP/ — public domain, keyless. Each output row names
the exact source zip (data_source) and its Last-Modified (data_vintage).