Last Updated: April 21, 2023.
This document is for publishers of GTFS data and developers of real-time API services.
See the Help page for assistance using this Web service.
The purpose of specifications is to allow software to place reliable expectations on data so applications can be disigned for the best possible user experience. Nonsense is compliant usability is what matters. Be consistent with naming and identifiers across datasets and don't second guess design.
service_id
.) trip_headsigns
per schedule trip block when direction_id
is used. The change avoids possibly misleading results when only the first trip_headsign
is used. Use trip_headsign
to model direction names identical to official publications. If trip_headsign
changes along a trip, use stop_headsign
to indicate the change. See GTFS Best Practices, Direction Names below. Here's a quick start to avoid common mistakes.
trip_headsign
is used as the direction name. Too many can be confusing. Use direction names identical to official publications. If a trip headsign changes along a trip, use stop_headsign
. It's designed for that purpose. route_ids
Across Service Updates. The route_id
is designated as the unique identifier for routes and should not change to denote a change in service. Publish data that supports tracking route schedules by keeping route_ids
the same. If you have legacy software, update it. See Support Tracking Route Schedules (GTFS Best Practices) below for tips if you're locked into changing route_ids
.
content-length
and last-modified
headers don't exist, are incorrect, or fluctuate, updates to the data are not processed timely and unnecessary downloads can result. When automated processes regenerate data, the resulting file size is unlikely to be size identical after compression. Avoid scheduled processes that regenerate the file even when the data is unchanged. route_ids
For Each Direction. Tempting simplicity but it disrupts user interfaces designed for GTFS. Use the route_id
, route_short_name
, and route_long_name
to identify routes and trip_headsign
to identify direction. User interfaces were designed expecting this pattern, disrupting it is counter productive. stop_code
in stops.txt even if they are used as stop_id
and don't append them to stop_name
. The stop_code
flags whether your system uses public stop codes and triggers useful features. If you use them, they're worth including. Use the same calendars, routes, direction names, and times in your data as you use in print. Identical print and data publications promote trust and use of your data. For an unsure public, it's a relief to find identical information.
If arrival and departure times differ, specify them both. The public is interested in arrivals and not just departures.
Don't leave departure_time
or arrival_time
empty or times will be interpolated and results may differ among publications.
Use the preferred calendaring method to best reproduce official publications. If schedules do not vary by day too much, use calendar.txt with modifications in calendar_dates.txt. If schedules are highly variable by day, use only calendar_dates.txt.
If you use calendar_dates.txt only, try to keep days of the week consistent within each service date range. The result is a user friendlier experience with fewer calender entries to choose from.
The trip_headsign
is used as the direction name for a group of trips. Use the same names as official publications to create familiar direction names and time blocks.
Too many trip_headsigns
can cause confusion because arrival and departure times get listed in separate time blocks. It's difficult to identify the next arrival or departure when times are listed under separate directions.
If trip headsigns vary along a trip, use stop_headsign
. That's it's purpose.
We no longer coerce trip blocks into two trip_headsigns
when direction_id
is used. The change avoids possibly misleading results when only the first trip_headsign
is used.
If you use direction_id
, limit trip_headsigns
to reflect official publications and use stop_headsign
to reflect changes along a trip.
Make the major stops that appear in print publications an exact timepoint
so the publication can be reproduced without a tomb of stops. See the reference publication for timepoint
guidance.
If you change your route_ids
, your data does not support tracking route schedules. The little utility left is a small return on your investment and you could benefit greatly by keeping them the same.
Remember, your data describes things in the real world and if they haven't changed neither should their identifiers.
If route_ids
change, we identify routes between updates by route_id
patterns or the route name on a per dataset basis using settings we assign. For example, 2-BMT-sj2-1
may be recognized as 2-BMT-sj2-
. The route short name or complete route name may also be used. The route_id
with the latest service period is used to interoperate with other systems.
If you're using legacy software that changes route_ids
, update it if you can. Otherwise, your data works as a common pattern and not as a rule (very bad). If you must change route_ids
, pay special attention to keep route_short_name
and route_long_name
the same.
last-modified
and content-length
headers in GET
and HEAD
requests. One of these, preferrably both, is required for updates to be detected and posted automatically. Note: If you want to restict access, use HTTPS
with basic authentication. This allows restricted access while supporting automatic updates.
During the update process never allow the last-modified date of the old file to be later than the new file. If this happens, the new file may be ignored.
Finally, don't edit your file while it's at the static URL. If bad data gets processed, nonsense can become widespread and not automatically undoable.
If the GTFS data file is invalid or at any time doesn't describe current service, nonsense may result and your data may be excluded from this Service.
stop_code
and not stop_id
or appended to stop_name
. We have no way of knowing if stop_id
is stop_code
parsimonious or exactly which part of stop_name
is really stop_code
. The presense of stop_code
activates many useful features and is worth including. route_short_name
, route_long_name
, and trip_headsign
match their well known equivalents. If routes are published by a short name and a long name, always include trip_headsign
so the public can tell which direction you're talking about. Best practices follow logically from the specification but may not be obvious. Many are critical to avoiding nonsense.
Remember GTFS and GTFS-R are designed to work together and should always be a snapshot of your service. All data used by GTFS-R must always be contained in the dataset pointed to at the static GTFS URL.
If your static GTFS URL at any time does not contain data used by GTFS-R, expect real-time to stop working.
Always post new data in a merged dataset at your static URL that uses the same identifiers as your GTFS-R. Please remember that maintaining a snapshot is the only way software can track your schedules and work as a rule (GTFS is a cacheless specification).
If you run GTFS-R and publish a non-merged dataset early, the update will not be processed until the earliest date in calendar.txt or calendar_dates.txt of the new dataset (this is necessary to maintain GTFS and GTFS-R synchronization).
We have updated our system to track changing route_ids
, but any such system must rely on heuristics and will therefore not work as a rule. If you run GTFS-R, update your software to generate data that does not change route_ids
(and is therefore suitable for general application use).
Please remember to support the General Transit Feed Specication (GTFS).
Model your data as intended by the specficiation to include all trips in each calendar.txt entry with any modifications in calendar_dates.txt. If trips vary day to day, use the calendar dates only method.
Using the specification as intended means less work and a better user experience. See the GTFS documentation for the recommended approach.
The .pb files should be updated at an interval by a background service or process that is fully decoupled from GET or POST requests for the .pb file.
Updating .pb files in a separate process eliminates any latency issues. The service scales with high volume since no additional execution time is required per request.
The smaller the update interval the better the user experience, especially for vehicle locations. Use the smallest interval possible given your hardware resources.
For example, updating vehicle positions every 3-5 seconds allows users to watch and move from a sheltered area to the stop just in time.
In general, populate all attributes if data is available. Code paths increase exponentially with each optional attribute and GTFS-R has many. You can promote quality software and the best possible user experience by simply populating all attributes.
Specifically, TripDescriptor
should always include trip_id
where available. Otherwise, scheduled times and direction may not be discernable and user experience will suffer in the extreme. In VehiclePositions
, include stop_id
, current_stop_sequence
, and current_status
so stop predictions and trip inquiries can resolve to vehicles to the extent possible. Also, include bearing
for visual directional cues.
If you follow best practices, treat a vehicle assignment as a trip update so predictions can be coupled to the vehicle even when it is "on time". It's also a pleasure to see the system is up and working and the trip is "on time".
Don't drop past StopTimeEvents
too soon. If so, users could see a trip status showing vehicle departure as scheduled 15 minutes ago and the vehicle just leaving the station.
'Reply-To'
Address'Reply-To'
address header if present. Anti-abuse configurations for email servers often reject email sent from a different domain, which means relayed requests can't be 'From'
the user and responses must be sent to 'Reply-To'.
If your system responds to the Reply-To
address if present, mention it so feature support is known. Publish other information that might be helpful to consuming applications, such as alert sources and types. It can be difficult to monitor publications to figure out what information is published where so it can be properly configured into a user interface. Also consider publishing information about the update frequency of vehicle locations and trip updates, non-abusive request frequencies, or any special or additional meaning attached to attributes.
Successful services always make sense. Fine tune your system. Watch and compare to confirm it never displays nonsense or contradicts itself. Final testing is where work pays of the most.
Don't rely on the public to discover an outage. By that time there may be thousands of frustrated users. Maintain a notification system so you can discover outages and promptly restore service.
To publish more than what's in the specification, maximize application support by doing it the same way others do.
At present, most efforts to go beyond the basic specification focus on:
Many GTFS publishing services implement GTFS-Fares, GTFS-Flex, GTFS-ContinousStops and other extensions for stops, pathways, and facilities. Do not break the specification by publishing separate GTFS files for your on demand service. The specification is updated to describe on demand service--use it to your advantage. You can see the new files and attributes and official documentation for GTFS-Flex.
We've attempted to fully support these extensions but new ones arise. As of now, GTFS-Flex and GTFS-Fares have partial support with complete support in progress. Periodally we evaluate support of all bona fide GTFS extensions. If you've implemented a non-standard solution, you are encouraged to migrate to these new popular formats to describe your services.
The dominate classification for additional route types is the Hierarchical Vehicle Type (HVT) codes from the European TPEG. You can see a list of the codes and their support by Google here. However, new route_types
will create backward incompatibilies into the future. Future support at RideSchedules depends on the extent to which the codes are incoporated into publications.
To include fares for different types of passengers, include a rider_categories.txt file and fare_rider_categories.txt in addition to the fare attributes and fare rules.
The rider_categories.txt files assigns a unique integer to a string public name.
rider_category_id,rider_category_description
2,Senior
6,Disabled
15,K-12
The fare_rider_categories.txt file keys the rider_category_id
to a fare_id
and a separate price
.
fare_id,rider_category_id,price
2491,2,0.35
2491,6,0.35
2491,15,0.70
The above example results in:
$1.00 upon boarding (includes 1 transfer), Senior $0.35, Disabled $0.35, and K-12 $0.70.
Note: Always specify route_id
in fare_rules.txt so the fare can be associated with a route. At present, that means an entry in fare_rules.txt for each route_id.
Disambiguting the location of a stop can be done with the cardinal_direction
and cardinal_position
fields in stop_attributes.txt or by using the vender specific method of direction
and position
in stops.txt. You can create results such as: "Stop located Fareside traffic direction South". The stop_address
in stops.txt and stop_city
in stop_attributes.txt is also available.
You can specify the name of fare zones in a way familiar to the public by including farezone_attributes.txt with zone_id
keyed to a zone_name
.
Passengers using GTFS frequently need non-GTFS information, such as system maps, rider guides, fare brochures, etc.
Note: As of this writing, the mobile segment currently has insufficient resources for system maps created from GTFS data but that's changing slowly.
Follow a few simple rules to keep your resources visible and up to date.
jpegoptim
and optipng
are popular). If you publish PDFs, consider the optimize features in your editing software. /*
GTFS-R is recommended as the emerging standard,
but for RESTful services, here's some
sample API requests using URL naming schemes
with JSON/XML response
*/
/* stop arrivals/departures */
http://transitagency.com/realtime.html?route=[route_id|route_short_name]&stop=[stop_id|stop_code]&response=json|xml
/* trip updates */
http://transitagency.com/tripupdates.html?trip=[trip_id]&stop=[stop_id|stop_code|stop_sequence]&response=json|xml
/* alerts */
http://transitagency.com/alerts.html?agency=[agency_name|agency_id]&route=[route_id|route_short_name]&stop=[stop_id|stop_code]&response=json|xml
/* news */
http://transitagency.com/news.html?agency=[agency_name|agency_id]&route=[route_id|route_short_name]&stop=[stop_id|stop_code]&response=json|xml
/* vehicle locations */
http://transitagency.com/cgi-bin/wherenow.pl?agency=[agency_id|agency_name]&route=[route_id|route_short_name]&direction=[direction_id|trip_headsign]&stop=[stop_id|stop_code|stop_sequence]&trip=[trip_id]&vehicle=[vehicle_id]&response=json|xml
XML or JSON
Aside from GTFS-Realtime, there is generally no uniform request or response format for stop predictions and vehicle locations. SIRI has recently enjoyed implementation by a few major providers but most often developers still need to write separate code to interact with the service. If your system is in development, here's some time saving suggestions.
XML and JSON are simple, mainstream, and reliable APIs, but not write once for all when it comes to predictions and vehicle locations. SIRI ("Service Interface for Real Time Information") is a template adopted by the European Commission on Standardization that offers at least the possibility of write once for all. However, in practice most implementations require custom code to interact with the service. You can learn more about SIRI from the official home page at http://www.siri.org.uk/.
If you decide to develop your own API, be sure to include the DTD or Schema in the API documentation. Example responses are not enough. Developers need to know whether attributes are optional or required and whether they appear once or repeated as well as the data type and how errors are handled. Without this information, reponses cannot be parsed reliably. Do not use the HTTP layer to convey meaning within your API or software handling HTTP communications may not interact with your service as expected.
route_id
, stops to stop_id
or stop_code
and directions to direction_id
or trip_headsign
. If your real-time identifiers cannot be resolved from your GTFS data, your service will very likely not be implemented. stop_id
or stop_code
and narrowing by route and direction. If you support vehicle locations, also by vehicle_id
. Vehicle location requests should support narrowing by route, direction, and vehicle id with per stop inquiries handled by coordinates included in prediction responses. Alerts, notifications, advisories, news, etc. should support requests per stop, route, route type, and agency, if appropriate. Always support narrowing where possible for convenience and when data volumn is high. route_id
, trip_headsign
, stop_id
, stop_code
, or vehicle_id
and always vehicle coordinates if available. Responses to prediction requests based on vehicle id should return data for all future stops on the trip. Vehicle location responses should identify each vehicle by vehicle id, route, direction, and trip_id
and include status and next stop information (early/late next stop X mins) and all available positional information, such as lat lons, speed, heading, etc.
For example, if you specify next_stop_sequence
or next_stop_id
include next_stop_name
. If you specify trip_id
or direction_id
, include route_short_name
and trip_headsign
.
trip_id
. Responses should include the same information as in the model vehicle locations response. Be sure your RSS files are indeed RSS! Frequently, software inserts custom tags and outputs non-compliant files. Select strict RSS as the output format. If your file is not valid RSS, do not publish it as such or it may be read incorrectly or not at all.
All behavior is as designed to the extent known.
Note:
Multi-agency GTFS-R Alerts without a limiting agency query parameter is now supported. If you notice your file not properly displaying, notify the Webmaster.
Static GTFS with date ranges covering many decades now auto-update normally. The displayed date ranges will roll a sensible date range without re-fetch until the data file expiration date.
▲ Some input is required.
▲ Invalid Reply-To Email address.
Please remember to include your email address if a reply is needed.
Mobile Site | My | Plan Trip | Search Schedules By Name | Help | About |
Company Website © 2010-2023. All rights reserved.