Realtime APIs
Transport API (GTFS-R)

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 are rapid-bus-kl , rapid-bus-mrtfeeder, rapid-bus-kuantan and rapid-bus-penang.
    • rapid-rail-kl, for which static endpoint is available, does not yet have stable realtime feeds.
  • Known errors affecting rapid-bus-kuantan and rapid-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.
  • 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.

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)