GTFS Realtime API Endpoint
GET https://api.data.gov.my/gtfs-realtime/<feed>/<agency>
What does GTFS Realtime do?
GTFS Realtime is an extension of the GTFS Static API that enables public transportation agencies to share live trip updates, service alerts and vehicle positions. At present, our GTFS Realtime API only offers vehicle position data - service alerts and and trip updates are in our pipeline for 2024-25. For more details on GTFS Realtime and its broader functionalities, please refer to https://gtfs.org/realtime/ (opens in a new tab).
Important note: We are building iteratively
This is the first time that Malaysia has had an official and freely-usable GTFS API. It is the result of months of hard work and collaboration between the data.gov.my developer team and various public transport operators. It is by no means complete; there are plenty of services that will only be integrated over the coming months and years. Furthermore, the Realtime API in particular needs a lot of work; the documentation for each endpoint transparently details known errors so that developers using the API are aware of its current limitations (and are aware that we are aware!).
However, we felt that it was time to go live - so that the private sector and public transport community could begin building from it, and most crucially, giving us feedback on how to improve it. If you have any feedback on the GTFS API, please write to us at data.dtsa@jdn.gov.my - we welcome any and all constructive feedback!
Note: The validation errors specific to each feed in the Vehicle Position section were generated using using the GTFS Realtime Validator (opens in a new tab).
Source of GTFS Realtime Data
The GTFS Realtime API incorporates data from various transport agencies in Malaysia. Currently, the following agencies contribute their transit data:
- myBAS Johor Bahru (opens in a new tab): A bus service operator in Johor Bahru, Malaysia, providing bus transportation on 19 routes across 5 corridors, including Kota Tinggi, Masai, Kulai, Gelang Patah, and Pontian.
- KTMB (Keretapi Tanah Melayu Berhad) (opens in a new tab): A railway operator providing train services across the country.
- Prasarana (opens in a new tab): A public transport operator responsible for managing various modes of transportation, including LRT (Light Rail Transit), MRT (Mass Rapid Transit), monorail, and bus services.
Request Query & Response Format
The GTFS Realtime API adheres to the standard GTFS Realtime protobuf format (.proto
).
The detailed format is available in the official GTFS Realtime reference (opens in a new tab), and you can access the protobuf files through the following endpoints:
Vehicle Position
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/<agency>
Frequency of Data Update
- All Vehicle Position feeds are updated every 30 seconds.
myBAS Johor Bahru
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-johor
# .proto file is returned
- Known errors:
- E003 (opens in a new tab): GTFS-rt
trip_id
does not exist in GTFS data- ~50% of trips are undefined in GTFS Static.
- E004 (opens in a new tab): GTFS-rt
route_id
does not exist in GTFS data- ~15% of the routes are undefined in GTFS Static.
- E023 (opens in a new tab) - trip
start_time
does not match first GTFSarrival_time
start_time
is invalid; this requires minor fixes to operational systems.
- E028 (opens in a new tab) - Vehicle position outside agency coverage area
- Does not invalidate the feed per se, but implies that improvements to the static endpoint are needed.
- E003 (opens in a new tab): GTFS-rt
KTMB
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/ktmb
# .proto file is returned
Prasarana
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/prasarana?category=<category>
# .proto file is returned
- Possible
<category>
values arerapid-bus-kl
,rapid-bus-mrtfeeder
,rapid-bus-kuantan
andrapid-bus-penang
.rapid-rail-kl
, for which static endpoint is available, does not yet have stable realtime feeds.
- Known errors affecting
rapid-bus-kuantan
andrapid-bus-penang
:- E003 (opens in a new tab): GTFS-rt
trip_id
does not exist in GTFS data - E004 (opens in a new tab): GTFS-rt
route_id
does not exist in GTFS data- These errors are due to issues with legacy operational systems (some more than a decade old) which cannot support tracking trips and routes properly, yet. Our team is actively working to alleviate these constraints to make the feed meaningful and compliant.
- E003 (opens in a new tab): GTFS-rt
- Known issue with
rapid-bus-penang
:- Developers need to match trip IDs in the realtime feed with existing trip IDs in the static schedule. This can be achieved by comparing the portion of the ID that comes after the service ID prefix.
- For example, the GTFS Realtime trip ID
30000001_1000000855_053000_02
corresponds to trip IDs in the static schedule such as:weekend_30000001_1000000855_053000_02
weekday_30000001_1000000855_053000_02
23102302_30000001_1000000855_053000_02
- We took the decision not to modify the realtime feed received from operational systems to avoid jeopardising performance; a deeper fix will be deployed in future to ensure out-of-the-box synchronicity between the realtime and static trip IDs.
- For example, the GTFS Realtime trip ID
- Developers need to match trip IDs in the realtime feed with existing trip IDs in the static schedule. This can be achieved by comparing the portion of the ID that comes after the service ID prefix.
Understanding the data
To properly parse the protobuf data, refer to the official GTFS Realtime language bindings (opens in a new tab) for guidance on decoding the information. Below is a concise Python example illustrating how to read RapidKL (bus) vehicle position data from the GTFS Realtime API:
# pip install gtfs-realtime-bindings pandas requests
from google.transit import gtfs_realtime_pb2
from google.protobuf.json_format import MessageToDict
import pandas as pd
from requests import get
# Sample GTFS-R URL from Malaysia's Open API
URL = 'https://api.data.gov.my/gtfs-realtime/vehicle-position/prasarana?category=rapid-bus-kl'
# Parse the GTFS Realtime feed
feed = gtfs_realtime_pb2.FeedMessage()
response = get(URL)
feed.ParseFromString(response.content)
# Extract and print vehicle position information
vehicle_positions = [MessageToDict(entity.vehicle) for entity in feed.entity]
print(f'Total vehicles: {len(vehicle_positions)}')
df = pd.json_normalize(vehicle_positions)
print(df)