Case Study

Open-source side project

SkyTrace — Live Flight Tracking

Live ADS-B flight tracking built around a hard API budget: one shared poller, WebSocket fan-out, and a canvas map that keeps moving between updates.

React 19TypeScriptNestJSSocket.IOLeafletPostgreSQLVite
1
Shared poller for every viewer
10s → 60fps
Dead-reckoned motion
4,000
Credits/day budget respected

Overview

  • SkyTrace is a live flight-tracking web app: a landing page, a full-screen live map, and per-aircraft detail pages. Positions come from the OpenSky Network's ADS-B feed, stream to the browser over Socket.IO, and render on a custom Leaflet canvas layer. Aircraft type, airline, and typical route arrive a moment later from adsbdb and are cached in PostgreSQL.
  • It is a non-commercial portfolio project, and the full source, tests, and architecture notes are public on GitHub.

The problem

  • A registered OpenSky account gets 4,000 API credits per day. A global query costs 4 credits, and the data only refreshes every 5–10 seconds — so polling globally every 10 seconds would burn the daily budget in under three hours, and one request per browser tab would burn it far faster. The challenge was to make a map that feels live for any number of viewers without exceeding that budget.

My role

  • Sole developer — architecture, NestJS backend and WebSocket gateway, React frontend and canvas rendering, shared TypeScript contracts, and the test suite.

Approach & architecture

  • One TrackingService poller for every connected client, instead of one upstream request per browser tab.
  • Viewport-derived bounding boxes, merged when the union costs no more than separate queries, and capped per poll cycle.
  • Poll interval widens automatically as the remaining credit balance falls, and polling stops entirely when nobody is watching.
  • Clients receive a snapshot and then deltas over Socket.IO; client-side dead reckoning interpolates between updates for 60fps motion.
  • Custom Leaflet canvas layer with rotated sprites, viewport culling, zoom level-of-detail, and spatial-grid hit-testing.
  • Rate-limited enrichment queue for aircraft and route data that never blocks the position stream.
  • Replay fallback loops a recorded fixture when the feed is down — and the UI labels it as demo data, never as live.

What I learned

  • Treating the API budget as the core design constraint shaped the whole architecture — shared polling, coalesced queries, and idle shutdown came directly from it. Being honest in the UI about what the data can and can't tell you (typical routes, demo data) builds more trust than pretending to know more.

Want to build something like this?

I'm open to full-stack and real-time projects. Let's talk.