If you build transit applications, GTFS needs no introduction — it is the format most of the world's public transport schedules are published in, and tooling for it is mature. The useful question about any country is simply which agencies publish it, how complete the feeds are, and what local quirks will break your parser.
Turkey publishes GTFS through municipal open data portals, and several major cities are covered. This guide is for developers who know GTFS and want to know what is specific here.
Which cities publish GTFS
| City | Operator | Portal | Notes |
|---|---|---|---|
| İstanbul | İETT | İBB Open Data | Largest network by far |
| İzmir | ESHOT | İzmir Open Data | Well-maintained municipal portal |
| Konya | Municipal transport | Konya Open Data | Includes tram alongside bus |
| Kocaeli | Municipal transport | Kocaeli Open Data | Regional coverage |
İstanbul İETT, İzmir ESHOT, Konya and Kocaeli each publish independently.
There is no national feed
The structural fact that shapes everything else: public transport in Turkey is operated municipally, and each city publishes its own data on its own portal on its own schedule.
There is no national aggregator, no shared identifier scheme and no common update cadence. If your application covers more than one Turkish city, you are integrating each one separately and normalising the differences yourself.
Practically, this means designing for heterogeneity from the start. Namespace every identifier by city — a route with ID 12 exists in several feeds and means something different in each. Track each feed's publication date independently, because they will drift apart. And expect one city's feed to be updated while another sits unchanged for months.
It also means coverage is uneven. The cities above are the well-established feeds, but Turkey has many municipalities and most do not publish GTFS at all. Do not assume a city is covered without checking.
Encoding is the first thing that will break
Before anything else in your pipeline, handle character encoding. This is the single most common failure with Turkish GTFS data, and it fails silently.
Turkish stop and route names contain characters outside ASCII — ç, ğ, ı, İ, ö, ş, ü. Read the files with the wrong encoding and every one of these becomes mojibake. Your parser does not crash; it produces a feed full of stop names like Kad�k�y, and you discover it when a user searches for their stop and finds nothing.
Read GTFS files explicitly as UTF-8 rather than relying on your platform's default, which on some systems is still a legacy code page.
The second encoding-adjacent trap is the dotted and dotless i. In Turkish, the uppercase of i is İ and the uppercase of ı is I. A culture-insensitive lowercase operation turns İstanbul into ıstanbul, and a search for istanbul then matches nothing. If you build stop search — and any transit app does — normalise using Turkish culture rules, and index a diacritic-stripped variant alongside the original so that a user typing uskudar finds Üsküdar.
These two issues cause more support tickets in Turkish transit apps than anything else in the data.
Feed quality varies, so validate before you trust
GTFS is a specification, but real-world feeds vary in how strictly they follow it and in how complete the optional fields are.
Run every feed through a GTFS validator before building against it, and re-run on each update. Common findings across municipal feeds generally include optional files being absent, sparse or missing accessibility information, and stops without parent station groupings.
Missing parent stations deserve specific attention because it affects user experience directly. Without them, a large interchange appears as several unrelated stops with similar names rather than one station with multiple platforms. Your journey planner will happily suggest a walk between two stops that are actually the same building. If a feed lacks parent stations, clustering stops by proximity and name similarity is a common mitigation, though it needs manual review for the large interchanges.
Also check calendar and calendar_dates carefully. Turkish transit schedules differ on public holidays and during Ramadan in some cities, and these variations are expressed through service exceptions. An application that ignores calendar_dates will confidently show a weekday schedule on a public holiday.
İstanbul is a scale problem
İstanbul's network is large enough that it changes the engineering, not just the data volume.
A journey planner over İstanbul's full feed is a meaningfully harder computation than over a mid-sized city. Naive graph traversal over every stop and trip will be too slow for an interactive interface. This is a solved problem — established routing engines handle GTFS at this scale — but it means you should reach for one rather than writing your own traversal.
Ferries and rail are also part of how İstanbul moves, and they are operated separately from the bus network. A journey plan that only knows about buses will produce routes that no local would take. Consider what your application promises: covering only buses is a legitimate scope, but the interface should be honest about it rather than presenting incomplete plans as complete.
Real-time data
Static GTFS describes the planned schedule. What a user actually wants to know — when the bus will really arrive — is a separate specification and a separate data source.
Real-time coverage across Turkish municipalities is uneven and should be verified per city rather than assumed. Some operators expose arrival information through their own interfaces rather than as a standard real-time feed, which means a custom integration per city if you want it.
Design your application so that real-time is an enhancement rather than a requirement. Show scheduled times reliably everywhere, and layer live information where it is available, labelled as such. An app that shows nothing without real-time data is useless in most of the country; one that shows the schedule and marks live updates where available works everywhere.
Be careful about how you present scheduled times, too. Users interpret a displayed time as a prediction. Labelling it as scheduled rather than expected is a small wording choice that prevents a lot of disappointment.
Update strategy
Static feeds change when schedules change — seasonally, or when routes are revised. There is no fixed cadence and no notification mechanism.
Check the publication date on each portal rather than downloading on a timer. When a new feed appears, validate it before swapping it in. A malformed update that replaces a working feed takes your application down, and this happens often enough to be worth guarding against.
Keep the previous feed until the new one is verified, and make the swap atomic rather than deleting and rebuilding in place. Rebuilding a large feed in place leaves your application serving partial data for the duration.
Store the feed version and publication date alongside your data, and show it somewhere in the interface. When a user reports that a route is wrong, knowing which feed version they were looking at is the difference between a five-minute investigation and an unanswerable question.
Licence and attribution
These feeds are published through municipal open data portals and are generally available without registration. Licence terms are set per portal and per dataset rather than nationally, so check the specific dataset page before commercial use.
Attribution to the operating authority is good practice regardless, and some portals require it. Naming the source also helps your users understand where the data comes from and why it might occasionally be out of date.
Portal locations and dataset availability in this article reflect the official sources at the time of publication. Municipal portals reorganise periodically, so verify current URLs when you build.
Related API Deposu entries
Sources
Frequently Asked Questions
›Is Turkish GTFS data free to use?
These feeds are published through municipal open data portals and are generally available without registration or payment. Licence terms are set per portal, so check the specific dataset page before commercial use.
›Is there a single national feed for Turkey?
No. Public transport is operated at the municipal level, and each city publishes its own feed independently. Covering multiple cities means integrating each one separately and normalising the differences yourself.
›Does Turkish GTFS include real-time vehicle positions?
Coverage varies by city and should be verified per feed. The static GTFS files describe planned schedules; real-time arrival data is a separate specification and is not published uniformly across Turkish municipalities.
›What breaks most often when parsing these feeds?
Character encoding. Turkish stop and route names contain characters that render as garbage if the file is not read as UTF-8, and the dotted and dotless i can also break case-insensitive matching. Both are silent failures rather than crashes.
›How often should I refresh the data?
Static GTFS changes when schedules change — typically seasonally or when routes are revised. Check the feed's publication date rather than downloading on a fixed timer, and always validate a new feed before replacing a working one.