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).
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. We currently feature realtime feeds from the following:
- 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.
- BAS.MY (opens in a new tab): Stage bus services across Malaysia, run by various operators. Endpoints for Johor Bahru, Kangar, Alor Setar, Kuala Terengganu, Kota Bharu, and Kuching are currently available. We plan to expand the feed to cover Melaka, Seremban, and Ipoh by 15 November 2025.
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>
It should be noted that continuous validation of realtime bus feeds may raise E028 (opens in a new tab), indicating that the vehicle's reported position falls outside the coverage area defined in the static feed. For buses specifically, users should note that there is no error in the underlying static data. The root cause of the error is occasional erroneous GPS data reported by transponders, resulting in vehicle positions temporarily appearing outside the agency's defined service area.
Frequency of Data Update
- All Vehicle Position feeds are updated every 30 seconds.
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.
BAS.MY Johor Bahru
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-johor
# .proto file is returned
BAS.MY Kangar
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-kangar
# .proto file is returned
BAS.MY Alor Setar
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-alor-setar
# .proto file is returned
BAS.MY Kuala Terengganu
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-kuala-terengganu
# .proto file is returned
BAS.MY Kota Bharu
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-kota-bharu
# .proto file is returned
BAS.MY Kuching
GET https://api.data.gov.my/gtfs-realtime/vehicle-position/mybas-kuching
# .proto file is returned
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)