Files
Flights/notes/tsa_research.md
Trey T ba0688a412 Search: FlightAware backbone, blob catalog, diagnostic infra
route-explorer's /api/token sits behind invisible Cloudflare Turnstile
that requires Apple's Private Access Token attestation. Third-party
iOS apps don't qualify for PAT issuance, and Linux Docker containers
can't pass it either (cross-OS fingerprint, even with patchright /
Camoufox). Migrates direct-flight search to FlightAware; multi-stop
and where-can-I-go remain via embedded SFSafariViewController.

- FlightAwareScheduleClient — scrapes route.rvt + trackpoll JSON for
  real schedules without auth. T+0..2 day window. Tests against
  captured HTML fixtures.
- BlobRouteClient — pulls the public Vercel blob route catalog
  route-explorer's frontend reads (no auth, no Turnstile).
- DiagnosticLogger + LoggingURLSessionDelegate + DiagnosticsView —
  device-shareable forensic trace. Boot header captures device, OS,
  locale, UA; share-sheet export of session logs.
- TurnstileDebugView — live WKWebView gate inspector. Used to prove
  the PAT-entitlement gap on a real device.
- RouteExplorerBrowserView — SFSafariViewController wrapper. Real
  Safari clears Turnstile naturally; the in-app browser opens at
  pre-filled search URLs. Surfaced from Search ("Open in
  route-explorer") and Settings → Tools.
- RouteExplorerTokenStore + RouteExplorerSetupView — bookmarklet
  capture flow (token round-tripped via flights://routeexplorer-token
  URL scheme). Kept dormant for future use.

backend/ — Docker proxy attempts (Playwright, patchright, Camoufox).
All fail on Linux because Cloudflare auto-denies before the Turnstile
widget renders. Documented; kept as scaffolding for a future paid-
solver integration.

scripts/probe_flightaware.py — reference algorithm for the FA path.
scripts/probe_nodriver.py — local-Mac sanity check confirming the
gate clears with real macOS Chrome (proves the blocker is
fingerprint-level, not network-level).
2026-06-06 01:09:59 -05:00

7.2 KiB
Raw Permalink Blame History

TSA Wait-Times Data Feasibility Research

Date: 2026-05-31 Project: Flights iOS app Question: Is there a real, free, key-less, server-less source of TSA wait-time data we can ship? Short answer: No. Recommend Option B — keep the bundled baseline and honestly relabel the UI.


URLs investigated

URL Status Notes
https://www.tsa.gov/travel/security-screening/whatcanibring 403 to WebFetch Page is the "What Can I Bring" tool; not a wait-time source.
https://www.tsa.gov/mobile 200 Marketing page for MyTSA app. No public API surface.
https://apps.tsa.dhs.gov/MyTSAWebService/GetTSOWaitTimes.ashx 302 → tsa.gov The historically documented endpoint (used by GitHub taitcha/tsa-mashup and others) no longer returns data. Confirmed via curl -sI -L: BigIP load balancer issues a 302 Moved Temporarily to http://www.tsa.gov with Content-Length: 0. The MyTSAWebService is effectively retired.
https://www.tsa.gov/data/apcp.xml 404 Not Found Companion airport-checkpoint metadata file the legacy API depended on. Confirmed dead via curl: HTTP/2 404 Not found.
https://www.dhs.gov/mytsa-api-documentation 403 to WebFetch Documentation page still indexed but the underlying service is gone.
https://catalog.data.gov/dataset/tsa-wait-times-january-2006-to-december-2015 200 Archive only — Jan 2006 through Dec 2015. No real-time component. Useful for historical research, not for live wait estimates.
https://catalog.data.gov/dataset/tsa-foia-reading-room-weekly-passenger-throughput-data 200 Weekly throughput (passenger counts), not wait minutes. Lagged. Not appropriate for "wait at checkpoint right now."
https://www.tsawaittimes.com/api/ 200 Third-party paid API run by TayTech LLC (Wisconsin). $49.95/mo, $479.52/yr. Requires API key + paid sub. Self-disclaimer: "this website is not owned or affiliated with the TSA" and "wait times are estimates and may not be reflective of the actual experience." Data source is a mix of "government data, traveler contributions, and internal data." Violates the project's no-paid-API constraint.
https://apps.apple.com/us/app/mytsa/id380200364 200 MyTSA v4.5.0, last updated 2024-12-09. App itself still available but consumes the same dead internal feed.
https://www.dhs.gov/check-wait-times 200 Marketing landing page. Points to MyTSA app only.
https://github.com/taitcha/tsa-mashup 200 Open-source Python 2.7 demo. Hardcodes the now-dead GetTSOWaitTimes.ashx endpoint. Repo is unmaintained.
https://www.ksat.com/news/local/2026/03/25/where-to-find-airport-security-wait-times-while-tsa-app-is-down/ 200 News article (March 2026): TSA website and MyTSA app currently show "no longer being updated" warnings due to government shutdown / staffing. Even the official channel is unreliable right now.
https://developer.apple.com/wallet/ 200 PassKit boarding-pass integration with iOS 26 Maps gives walking-time-to-gate, not security wait time. No PassKit/Maps API exposes TSA queue data to third-party apps.

What does and does not exist

Does not exist:

  • A free, key-less, public, real-time TSA wait-times API for general developer use.
  • A data.gov real-time feed (only historical archives through 2015 + weekly throughput counts).
  • An Apple system framework that exposes TSA wait times to third-party apps (PassKit/Maps surface gate-walk timings only).
  • A working successor to GetTSOWaitTimes.ashx.

Does exist (but unusable for this project):

  • tsawaittimes.com — paid, third-party, partially crowdsourced, not affiliated with TSA. Violates the no-paid-API rule and would mislead users with non-official data branded as TSA.
  • Historical data.gov archive (20062015) — possibly useful for refining the bundled baseline once, but not for live use.
  • MyTSA consumer app — only useful when a human reads the screen, not as a programmatic source. Also currently warning users that its own data is stale.

Recommendation: Option B — keep the bundled baseline, relabel honestly

Reasons to keep rather than drop:

  1. The current tsa_wait_baseline.json already gives a reasonable order-of-magnitude estimate for ~25 hubs by hour-of-day and weekday/weekend. For an airline employee planning a standby trip, "Tuesday 6am at ATL averages ~22 min" is genuinely useful context even if it isn't live.
  2. A nonrev traveller looking at a flight detail benefits from any signal about checkpoint pressure, provided it is clearly labelled as a historical typical-value rather than a live measurement.
  3. Dropping the feature would lose information that we do have honestly. The fix is in the wording, not in the data.

What must change in the UI (Phase 3 fix, not this phase):

The basis string surfaced by TSAWaitTimesClient.waitEstimate(...) is what LiveFlightDetailSheet displays. Today it says "baseline (weekday)", "baseline (weekend)", or "estimated". These are not clear enough about provenance. Replace with exact wording:

Current basis Replace with (verbatim)
"baseline (weekday)" "Typical wait — weekday avg, not live"
"baseline (weekend)" "Typical wait — weekend avg, not live"
"estimated" "Rough estimate — no live TSA feed"

And in LiveFlightDetailSheet, the section header or footnote near the TSA row should read:

Wait times are historical typicals. TSA does not publish a public real-time feed; values shown are hour-of-day averages, not live measurements.

That sentence is the honest disclaimer to surface in the sheet. It can be a .footnote under the TSA row or part of an info Label.


Assumptions the reviewer should verify

  1. The tsa_wait_baseline.json file shipped in Flights/Resources/ is hand-curated per the TSAWaitTimesClient docstring. I did not verify the actual numbers in that JSON against historical TSA reports. If you want defensibility, the next pass should re-source the buckets from the data.gov 20062015 archive (or the weekly throughput dataset's recent values, used as a busyness proxy rather than literal wait minutes) and add a source: field to the JSON.
  2. The GetTSOWaitTimes.ashx endpoint redirects to the TSA homepage as observed today (2026-05-31) from this network. There is a small chance this is a transient outage tied to the ongoing shutdown rather than permanent retirement — but the airport-metadata XML being 404, plus public reporting that TSA's own app is showing "not being updated" warnings, makes me confident this is structural, not transient. If you want to be doubly safe, code the rewrite to try the endpoint with a short timeout and fall back to baseline silently — but I would not recommend spending the effort given how unreliable the upstream has proven.
  3. The tsawaittimes.com pricing was scraped from their public marketing page. If you ever reconsider, re-verify current pricing before paying.

File summary

  • /Users/m4mini/Desktop/code/Flights/notes/tsa_research.md — this report (new)
  • /Users/m4mini/Desktop/code/Flights/Flights/Services/TSAWaitTimesClient.swift — read only, not modified (per task instructions; Phase 3 will apply the relabel based on this recommendation)