A few months ago, Sofia made a smart move — the city opened its public transport GTFS feeds to the public. Real-time vehicle positions, trip schedules, and route shapes are now freely available at gtfs.sofiatraffic.bg.
Before this, only Google Maps and Moovit had access (probably through some backroom deal).
I decided to turn that data into something genuinely useful — a real-time interactive map that shows buses, trams, trolleybuses, parking zones, and low-emission areas all in one place.
Try it live: sofiamap.vercel.app
What I Built
The live interactive map showing real-time vehicles, parking zones, and low-emission areas.
Core features:
- **Real-…
A few months ago, Sofia made a smart move — the city opened its public transport GTFS feeds to the public. Real-time vehicle positions, trip schedules, and route shapes are now freely available at gtfs.sofiatraffic.bg.
Before this, only Google Maps and Moovit had access (probably through some backroom deal).
I decided to turn that data into something genuinely useful — a real-time interactive map that shows buses, trams, trolleybuses, parking zones, and low-emission areas all in one place.
Try it live: sofiamap.vercel.app
What I Built
The live interactive map showing real-time vehicles, parking zones, and low-emission areas.
Core features:
- Real-time vehicle tracking — 300–500 active vehicles with 15-second updates
- Smart stop/route display — 3,000+ stops; click any stop for route lists and schedules
- Interactive route shapes — view both directions with night-route badges
- Parking zone polygons — blue and green zones (manually traced from city PDFs)
- Low-emission zones — visualized restricted areas
- Search & filters — search by route number, toggle layers, filter by vehicle type
View parking zones: Blue Zone (2 BGN/h) View emission zones: Orange & Red Zones
Why I Built It
Other transit maps existed (and some are better in certain ways), but they were missing crucial local information: parking zone rules, low-emission boundaries, and an easily searchable route interface.
The city’s published materials were either non-machine-readable PDFs or incomplete. I wanted a map that combined GTFS real-time data with locally curated overlays — focused on performance and practical, real-world usefulness.
💡 Why build it?
Existing maps lacked local features: parking info, emission zone boundaries, and easily accessible real-time data. This project fills those gaps with a focus on everyday usefulness.
When Everything Broke (And How I Fixed It)
My first deploy to Vercel sent 112 MB of data to every single user 🤦♂️
Why? I naively serialized and shipped the entire city’s transit dataset in one massive JSON payload.
The first version sent over 100MB of data to each visitor — everything in one payload.
The Fix: From 112MB to 80KB
- Send only what’s needed — stop pre-loading every single stop time
- Compact payloads — use short arrays instead of verbose JSON objects
- Cache aggressively — static data stays in
localStoragefor 24 hours - Delta updates — only send vehicles that moved or changed direction
Check Result
Initial payload: 112 MB → 3 MB → 80 KB (cached). Update messages: 2–8 KB. That’s a 99.9% reduction in bandwidth.
The Map Components
Smart Vehicle Markers
At zoom level 12, vehicles appear as simple colored dots. Zoom to level 16, and they transform into detailed badges with route numbers and direction arrows.
Icons adapt to zoom: from simple dots to detailed badges with route numbers and direction arrows.
Direction Arrows
Vehicle bearing is calculated from consecutive GPS positions — arrows visually show where each vehicle is heading in real time.
Arrows show live vehicle direction based on GPS bearing.
Click any vehicle to see live details: route number, vehicle manufacturer, next stops, current speed, and delay information.
Each popup shows vehicle type, route, speed, next stops, and delay info.
Route Shape Display
Clicking a vehicle reveals its complete route path in both directions overlaid on the map.
Click a vehicle to see its complete route in both directions.
Parking Zones
Manually traced from city PDFs — this is the only interactive, machine-readable version available online.
Blue zones (2 BGN/h) and green zones (1 BGN/h), rendered as interactive polygons.
Alert Why manual tracing?
The city only provided raster PDFs and images. I used QGIS to trace every boundary and converted them into GeoJSON by hand using Google Maps as reference.
Settings Panel
All controls and filters live in a clean sidebar — easily show or hide vehicles, zones, and features.
Toggle everything: vehicle types, zones, stop info, and search filters.
The Weird Bugs I Had to Fix
GTFS data is powerful but messy. Here are some of the gems I encountered:
- Vehicles occasionally spawned in the Black Sea (invalid coordinates)
- Some vehicles reported negative speeds
- GTFS times exceeded 24 hours (trips that “start yesterday”)
Alert GTFS quirks
Always normalize times, clamp coordinates, and filter impossible data. GTFS is great — but requires defensive programming.
Some of the amusing bugs encountered while parsing GTFS data.
Some of the amusing bugs encountered while parsing GTFS data.
What’s Next
There are several improvements on the roadmap:
- Fix idle vehicle handling — currently, vehicles disappear from the map when idle
- Complete zone mapping — finish tracing all parking and emission zones (time-consuming manual work)
- Bug fixes — refine edge cases and improve data validation
- Performance optimizations — further reduce update payload sizes
Tech Stack
- Next.js 14 (App Router with Server-Sent Events)
- React 18 + Leaflet (mapping library)
- Protocol Buffers (efficient data serialization)
- Server-Sent Events (real-time updates)
- localStorage (aggressive caching strategy)
- Data source: gtfs.sofiatraffic.bg
⚠️ Disclaimer
This app is not officially affiliated with the Urban Mobility Center, Sofia Traffic, or any other transport operator. It’s an independent project using publicly available data.
Questions or Feedback?
Built something similar? Have suggestions? Get in touch — I’m always happy to discuss transit data, mapping challenges, or performance optimization techniques.
Try It Yourself
Live map: sofiamap.vercel.app
Stay up to date
Get notified when I publish something new, and unsubscribe at any time.