Skip to content

NOTAM Integration Investigation for Vulture

Moved from vulture-ios/Docs/NOTAM-investigation.md

Status: On hold — waiting for an affordable European NOTAM data source. Date: 2026-08-12

The goal is to integrate NOTAMs into Vulture so pilots can see active airspace restrictions along their planned route and during flight. Currently pilots check NOTAMs outside the app, then mentally correlate them with airspace on the map — a safety and planning gap.

The codebase already has partial NOTAM scaffolding:

  • CubStyle.notam and AltStyle.notam enum cases exist in the CUB decoder
  • CubItem.swift has extraData and activeTime fields with TODO comments for NOTAM parsing
  • WeatherManager.DataType.notam is stubbed but unused
  • The inactiveAirspace field on Waypoints.Task is used by SoaringSpot competition tasks

SourceCoverageQuery by location?Geometry?AuthCost estimate (~1000 users)Verdict
FAA NOTAM APIUS (+ some intl)Yes (lat/lon + radius, max 100 NM)GeoJSONOAuth 2.0 (free registration)FreeBest for US coverage
NotamifyGlobalICAO codes only (no lat/lon)GeoJSON, AI summariesAPI key~$50-100/monthRichest data but expensive, no spatial query
SkyLinkUS-primary (via FAA SWIM)ICAO codes onlyParsed fieldsAPI keyFree tier 1K req/mo, $16+/moEU coverage unclear
ICAO APIGlobalYes (lat/lon/radius)LimitedAPI key~$0.275/call = very expensiveToo expensive at scale
Eurocontrol EADEuropeanYesFullLegal agreementThousands EUR/year + insuranceDesigned for ANSPs, not indie devs
AVWXWas globalN/AN/ABearer token (already have)N/ADeprecated/broken — pending new data source
openAIPEU-focusedN/AN/AAlready integratedN/ANot a NOTAM source — only airspace data
  • AVWX (already integrated for METAR) has deprecated its NOTAM endpoint — cannot be used.
  • openAIP does not provide NOTAMs at all — only static airspace data.
  • ICAO API is too expensive ($0.275/call) and updates only every 12 hours.
  • Eurocontrol EAD has the best European data but requires legal agreements, liability insurance, and thousands EUR/year — prohibitive for an indie app.
  • FAA NOTAM API is the best free option but is US-primary. It does include some international NOTAMs but European coverage is incomplete.
  • Notamify has the richest parsed data (GeoJSON geometry, AI summaries, 42 categories) but only queries by ICAO code (not lat/lon), and costs ~$0.20-0.30/call.
Section titled “Recommended Approach: Server-Side Caching Proxy”

A vulture.aero backend endpoint is essential regardless of upstream source:

  1. Caches NOTAMs by region — one upstream fetch serves all app users in that area
  2. Hides API keys — no secrets in the iOS app
  3. Combines sources — FAA for US + a commercial source for Europe
  4. Pre-filters — only glider-relevant Q-codes forwarded to clients
  5. Normalizes — consistent response format regardless of upstream source
  6. Estimated cost: $15-50/month with caching vs. hundreds without

The app would call vulture.aero/api/notams?lat=X&lon=Y&radius=Z and get a normalized JSON response.

AppNOTAM approach
SkyDemonLive NOTAM overlay on map, sourced from official national AIS (funded by $150+/year subscription)
XCSoar / LK8000No live NOTAMs — users manually import OpenAir files from sites like notaminfo.com

Vulture would sit between these: live NOTAMs via API, but filtered for glider relevance to manage data volume and cost.


Q) FIR/QCODE/TRAFFIC/PURPOSE/SCOPE/LOWER/UPPER/COORDS+RADIUS
A) Location (ICAO code)
B) Start validity (YYMMDDHHmm)
C) End validity (YYMMDDHHmm or PERM)
D) Schedule (e.g. "MON-FRI 0600-1800")
E) Description (free text)
F) Lower limit
G) Upper limit

Critical (airspace activation/restriction):

  • QRTCA — Temporary restricted area activated
  • QRRCA — Restricted area activated
  • QRDCA — Danger area activated
  • QRACA — Airspace reservation activated

Important (activity warnings):

  • QWELW — Military exercises
  • QWMLW — Missile/rocket firing
  • QWGLW — Glider flying/competitions
  • QWPLW — Parachute/paragliding activity
  • QWALW — Air displays

Filter criteria: Traffic type V or IV (VFR-relevant), Scope E or W (en-route/warning).

// In Packages/Airspace/Sources/Airspace/Models/
struct NOTAM: Identifiable, Hashable {
let id: String // e.g. "A0123/24"
let type: NOTAMType // .new, .replace, .cancel
let fir: String? // FIR identifier (e.g. "EBBU")
let qCode: String? // Q-code (e.g. "QRTCA")
let effectiveStart: Date
let effectiveEnd: Date? // nil = permanent/UFN
let schedule: String? // D) field
let location: CLLocationCoordinate2D? // Center point from Q-line
let radius: CLLocationDistance? // Radius in NM from Q-line
let lowerLimit: Airspace.Altitude?
let upperLimit: Airspace.Altitude?
let rawText: String // E) field
let geometry: [CLLocationCoordinate2D]? // Parsed polygon (if API provides)
let relevance: NOTAMRelevance // Categorized for glider pilots
let affectedAirspaceId: UInt64? // Link to existing Airspace.id
}

Integration pointFileHow
NOTAM modelPackages/Airspace/Sources/Airspace/Models/ (new files)Data types for NOTAM, alongside existing Airspace model
API clientPackages/Eagle/Sources/Eagle/Modules/NOTAM/ (new)Cara Request + CodableSerializer, following MetarRequest pattern
Route corridor queryPackages/Waypoints/ or Packages/Map/Compute bounding box from Task.waypoints with ~20km buffer
Map renderingModules/App/Sources/Components/Operations/MapDataManager.swiftAdd NOTAM airspaces to publishVisibleAirspaces() pipeline
Map stylingModules/App/Sources/Components/Map/Layers/Airspace/ (new layer)Orange/amber fill + hatched border for NOTAM-affected airspace
Task planningModules/App/Sources/Modules/Detail Map/Task/TaskMapViewModel.swiftTrigger NOTAM fetch on task load/edit, badge in banner
In-flightModules/App/Sources/Modules/Detail Map/In Flight/InFlightMapViewModel.swiftPeriodic refresh, feed into infringement detection
Infringement detectionModules/App/Sources/Modules/Detail Map/Flight/Flight/FlightViewModel.swiftInclude NOTAM-generated airspace in existing point-in-polygon pipeline
Detail UIModules/App/Sources/Modules/Detail/ (new NOTAM section)Table view with NOTAM text, validity, affected area
CUB parserPackages/Airspace/Sources/Airspace/Models/CUB/CubItem.swiftComplete TODO: parse extraData/activeTime for NOTAM activation
SoaringSpot tasksAlready uses inactiveAirspace field on Waypoints.TaskLink competition-deactivated airspace to NOTAM system
vulture.aero/api/notams (backend proxy)
↓
NOTAMRequest (Eagle, Cara) → NOTAMResponse → NOTAMMapper
↓
[NOTAM] cached locally (30-min TTL)
↓
NOTAMManager publishes via Combine
↓
┌─────────────────────┬──────────────────────┐
│ Task Planning │ In-Flight │
│ Route corridor → │ Current pos + radius →│
│ fetch along route │ periodic refresh │
└────────┬────────────┴──────────┬───────────┘
↓ ↓
Match to existing Airspace objects (by name/ICAO)
Create synthetic Airspace for unmatched NOTAMs with geometry
↓
MapDataManager.publishVisibleAirspaces()
↓
┌─────────────┬──────────────────┐
│ Map overlay │ Infringement │
│ (orange/amb) │ detection │
└─────────────┴──────────────────┘

  1. European data source gap — No affordable, high-quality European NOTAM API exists for indie developers. Eurocontrol EAD is the gold standard but prohibitively expensive. Options: (a) proxy a commercial source like Notamify, (b) scrape national AIS websites (fragile), (c) accept FAA API with partial international coverage as a starting point.

  2. Backend work required — The vulture.aero backend needs a new /api/notams endpoint with caching, source aggregation, and Q-code filtering. This is outside the iOS codebase.

  3. NOTAM text parsing — Extracting geometry from free-text E-field NOTAMs is notoriously hard. Phase 1 should rely on structured API fields (coordinates, radius from Q-line). Notamify’s AI-parsed GeoJSON is the cleanest option but costly.

  4. Data volume — A busy European FIR can have hundreds of active NOTAMs. Filtering for glider-relevant Q-codes and altitude ranges is essential to avoid information overload.

  5. Offline — Cached NOTAMs work offline but must clearly show staleness (“last updated 2h ago”).

  6. Legal/liability — NOTAM data is safety-critical. The app should clearly state that NOTAMs are provided for information only and that pilots must verify through official sources (AIS briefing).


  1. Backend first — Build vulture.aero/api/notams endpoint (start with FAA API as upstream, add European source later)
  2. Data model + API client — NOTAM struct in Airspace package, NOTAMRequest in Eagle
  3. Task planning map — Fetch NOTAMs along route, overlay on map with distinct styling
  4. In-flight — Periodic refresh + infringement detection
  5. Detail UI — NOTAM list panel with text, validity, affected area
  6. CUB NOTAM parsing — Complete the existing TODO in CubItem.swift