Engineering Diary, Day 17: 211,153 Flights, 200+ Entity Links, and the SEO Web We Wove Through Our Insights Hub
Two Jobs, One Theme: Connection
Today had two distinct halves. The morning was about creating data — a 720-line TypeScript file encoding every metric from the February 2026 Global Business Aviation Report. The afternoon was about connecting that data — weaving links between every entity mention and its dedicated detail page, turning our Insights Hub into an interconnected knowledge graph.
Both halves serve the same goal: making our 200+ entity pages discoverable — by users clicking through, by Google crawling link paths, and by AI systems following structured data.
Part 1: February 2026 Report
The raw source was a 104-page HTML report from Avi-Go covering every business aviation departure worldwide. We distilled it into structured TypeScript data: market overview, regional breakdowns, 13-month rolling trends, airport rankings (30 airports across 3 regions), aircraft utilization for 15 models, operator market share, cross-border route corridors, flight range distribution, and narrative analysis for every section.
The Numbers
| Metric | February 2026 | Change |
|---|---|---|
| Total departures | 211,153 | -16.51% YoY |
| Daily average | 7,541 | -19.89% MoM |
| Active fleet | 16,958 | — |
| North America share | 77.35% | 163,330 flights |
| Europe share | 13.35% | 28,197 flights |
| Rest of World | 9.29% | 19,626 flights |
The most interesting story: the Bombardier Challenger 300 Series dethroned the Embraer Phenom 300 as the world's most-flown business jet. The Phenom 300 dropped -38.38% month-over-month while the Challenger 300 only fell -15.77%. The divergence suggests charter-heavy fleets (Phenom 300) are far more seasonal than fractional/corporate fleets (Challenger 300).
The busiest individual aircraft? SE-RVF, a Pilatus PC-24 operated by Swedish Air Ambulance — 128 flights in 28 days, or 4.6 flights per day. Not a billionaire's toy, but essential medical transport infrastructure.
Technical Implementation
The report file (february-2026.ts) follows the same ReportData type used by our 5 previous monthly reports. After creating the data, we updated the report registry (reports.ts) with SEO metadata, Chinese name mappings, and the report period. One commit, one next build, done.
Part 2: The Entity Linking Project
This is where the real SEO engineering happened. Our Insights Hub has 200+ entity detail pages — individual pages for airports like KTEB, aircraft like the Citation Latitude, operators like NetJets, routes like Miami-New York, and countries. These pages had been live for weeks, but they were orphans: nothing linked to them except the directory listing pages.
Every time a monthly report mentioned "Teterboro" or "Challenger 300 Series" or "NetJets Aviation," it was just plain text. No link. No way for Google to discover the entity page. No way for a user to click through and explore.
The Pattern
The solution was systematic: for every entity type (airports, aircraft, operators, routes, countries), we compute a Set of valid slugs at render time, then conditionally wrap entity names in <Link> components only when the entity has a dedicated page.
// Compute valid entity sets (server component, runs at build time)
const validAirports = new Set(extractAllAirports().map(a => a.slug));
const validAircraft = new Set(extractAllAircraft().map(a => a.slug));
const validOperators = new Set(extractAllOperators().map(o => o.slug));
// In render: conditional linking
{validAirports.has(airportSlug(r.icao)) ? (
<Link href={`/insights/airports/${airportSlug(r.icao)}`}>
{r.city}
</Link>
) : (
<span>{r.city}</span>
)}
This pattern ensures we never create broken links — if an entity appears in a report but doesn't meet our minimum-appearances threshold (2+ months of data), it stays as plain text.
11 Files, 408 Lines
We applied this pattern across:
- Monthly report page (
[slug]/page.tsx) — 8 render functions updated: country rankings, airport rankings, aircraft utilization, flights-by-model (2 tables), city pair routes, cross-border routes, operator rankings, plus 3 spotlight sections (featured route, featured aircraft, most popular model) - 5 topic pages — top-airports, top-operators, top-routes, aircraft-utilization, aircraft-types — each got conditional entity links in their RankingTable columns and monthly comparison tables
- 5 directory pages — airports, aircraft, operators, routes, countries — each got
ItemListJsonLdstructured data
Cross-Border Route Parsing
The trickiest part was cross-border routes. Report data stores these as strings like "Teterboro → Toronto" using the Unicode arrow character (U+2192). To generate a linkable slug, we split on the arrow and pass the two city names to routeSlug(from, to):
const parts = r.name.split(/\s*\u2192\s*/);
const rs = parts.length >= 2 ? routeSlug(parts[0], parts[1]) : "";
return validRoutes.has(rs) ? (
<Link href={`/insights/routes/${rs}`}>{r.name}</Link>
) : (
<span>{r.name}</span>
);
Part 3: Structured Data for Discovery
Internal links help Google discover entity pages when it crawls a report. But we also wanted to give search engines explicit signals about the directory structure. We added ItemListJsonLd to all 5 entity directory pages, generating Schema.org ItemList markup with every entity as a ListItem:
<ItemListJsonLd
items={allAirports.map((apt, i) => ({
name: `${apt.city} (${apt.icao})`,
url: `${baseUrl}/insights/airports/${apt.slug}`,
position: i + 1,
}))}
/>
This gives Google a machine-readable inventory of every entity we track — essentially saying "here are 60+ airport pages, ranked in this order, at these URLs."
Part 4: IndexNow
After deploying, we triggered our IndexNow cron job to submit all updated URLs for reindexing. The API accepted 1,034 URLs — every insight page, report page, entity page, and directory page across all 4 locales.
Why This Matters for SEO/GEO
Before today, our Insights Hub was a collection of well-designed but disconnected pages. A user landing on the February 2026 report could read about Teterboro's 7,821 flights but had no way to click through to Teterboro's full profile page. Google could find entity pages through the directory listings, but the monthly reports — our highest-value content — were dead ends.
After today:
- Link equity flows from high-value report pages to entity detail pages
- Crawl paths now connect reports → entities → directories in a dense web
- User journey depth increases — readers can explore from "Challenger 300 had 16,700 flights" to the Challenger 300's full profile page
- Structured data (ItemList + BreadcrumbJsonLd) gives search engines explicit entity relationships
- GEO signals — AI systems can now follow entity links to find authoritative, granular data about specific airports, aircraft, and operators
The Commit Log
Two commits today:
c5961cf— insights: add February 2026 Global Business Aviation Reporte915d5c— seo: add internal entity linking + ItemList JSON-LD to insights pages (11 files, +408/-85 lines)
What's Next
- Expand entity linking to EU/ROW city pair routes (currently only NA routes have entity pages)
- Add cross-entity-type links on entity detail pages (e.g., airport page links to top operators at that airport)
- Dataset JSON-LD on topic pages for Google Dataset Search
- Monitor Google Search Console for entity page indexing and click-through rates
Готовы к полёту? Получите персональную котировку чартера за секунды.
Будьте в курсе
Порожние рейсы, новые маршруты и аналитика авиации — прямо в вашу почту.