Explainer · Feeds & Standards
TIDES: the specification for archived transit operations data, and who actually publishes it
GTFS-Realtime says where the bus is now. TIDES is the eleven-table format for where it was, who boarded, and what they paid, once the service day is over. We counted the spec and read the one public dataset.
A GTFS-Realtime feed is a statement about now. Every few seconds the vehicle positions message is rebuilt and the previous one is gone. The arrival predictions built on it are gone faster. By the end of the service day a large agency has produced millions of position reports, a boarding and alighting count at every stop from its passenger counters, and a fare transaction for every tap, and none of it is in a format anyone outside the vendor’s database has agreed on.
TIDES is the format for that leftover. It stands for Transit Integrated Data Exchange Specification, per the project’s own site, and it defines eleven tables that hold what the vehicles actually did on a service date rather than what the schedule said they would do. The three source systems it draws on are the ones most fixed-route agencies already run: automatic vehicle location (AVL), automatic passenger counters (APC), and automated fare collection (AFC). Version 1.0 was released on 2025-12-23, and the first major revision is being assembled on GitHub as this is written.
The name gets three different expansions depending on who is writing. The specification’s site and repository say Integrated. MobilityData’s March 2024 announcement that it would take over management called it the Transit ITS Data Exchange Specification. Caltrans’s data portal, which hosts the largest public dataset, calls it the Transit Integrated Data Exchange Standard. Search all three if you are looking for it.
Where TIDES sits next to GTFS
The relationship is easiest to see as three layers with the same keys. GTFS Schedule says what is supposed to happen: trips, stop times, calendars. GTFS-Realtime says what is happening, keyed back to those trips. TIDES says what happened, keyed back to both.

Those shared identifiers are what tie an archive row back to the schedule. A
vehicle_locations row carries trip_id_scheduled,
which the spec says should match the GTFS trip_id when the performed trip was
in the published schedule, and trip_id_performed, which is the agency’s own
identifier for what the vehicle actually ran. The two diverge exactly when the
interesting things happen: a trip that was cut, a bus that ran as directed, an
extra that was never in the feed. Ghost buses are a
trip_id_scheduled with no trip_id_performed behind it, and TIDES gives an
agency a place to count them after the fact.
We counted how much of the spec is borrowed. Of the 157 field definitions in
the schema files,
27 describe themselves as referencing a GTFS field and 8 mention
GTFS-Realtime. The vehicle_locations table holds six of the eight: latitude,
longitude, heading, speed, odometer, and current_status are lifted
from the realtime vehicle position message, and the trip, vehicle, stop, stop
sequence, and timestamp have realtime counterparts too, which is how Cal-ITP
fills them from its feed archive. Where the archive earns its keep is the
fields the realtime message has no place for: service_date,
schedule_deviation in seconds, headway_deviation in seconds, gps_quality,
and device_id for the box that produced the ping.
The eleven tables
The tables fall into three groups. Event tables hold one row per thing that happened. Summary tables hold one row per stop visit, trip, or station period, built from the events. Reference tables describe the fleet and the equipment.
| Table | Group | What one row is | Fields | Required |
|---|---|---|---|---|
vehicle_locations |
Event | One AVL ping: timestamp, position, speed, deviation | 22 | 3 |
passenger_events |
Event | One APC event: a boarding, an alighting, a door or ramp action | 15 | 6 |
fare_transactions |
Event | One fare action: purchase, entry, exit, transfer, with amount and capping flag | 24 | 6 |
stop_visits |
Summary | One vehicle at one stop on one trip: arrival, departure, dwell, loads, ramp and lift times | 31 | 3 |
trips_performed |
Summary | One performed trip: vehicle, operator, scheduled and actual start and end, NTD mode | 21 | 3 |
station_activities |
Summary | One stop or station over one time period, for events with no trip | 12 | 4 |
devices |
Reference | One measurement device, tied to a vehicle, stop, or station | 8 | 1 |
vehicles |
Reference | One vehicle, including a train consist | 10 | 1 |
train_cars |
Reference | One car that can be part of a consist | 9 | 1 |
vehicle_train_cars |
Reference | One car-to-consist relationship | 4 | 2 |
operators |
Reference | One vehicle operator, by identifier only | 1 | 1 |
That is 157 fields, of which 31 are marked required within their table. No
table is required. The package descriptor marks all eleven as optional, and the
getting-started guidance says outright that adopting TIDES does not mean
producing every table at once. An agency doing on-time performance can stop at
vehicle_locations and stop_visits. One doing ridership reporting needs
passenger_events or the boarding columns of stop_visits. One with fare gates
rather than on-board validators needs station_activities, which exists
precisely because a gate entry has no trip.
stop_visits is the table an analyst will spend the most time in, and its 31
fields show the spec’s ambition. Alongside scheduled and actual arrival and
departure it carries boarding_1 and boarding_2 for front and rear doors,
departure_load, dwell, door_open and door_close timestamps,
ramp_deployed_time, ramp_failure, kneel_deployed_time,
lift_deployed_time, bike_rack_deployed, bike_load, and revenue. Most of
that comes from event tables that do not exist yet at most agencies, which is why
the table is a summary rather than a source.
trips_performed carries the one field that names a regulator: ntd_mode,
referencing the mode codes in the National Transit
Database reporting policy manual. NTD
reporting is the use case the spec’s own site leads with, and it is the one the
implementations below are actually chasing.
The reference tables are thinner than the rest, and one of them is a stub.
operators has a single field, operator_id. The architecture diagram groups
vehicles, train_cars, and vehicle_train_cars under a “proposed GTFS”
heading, and vehicle_id is meant to match the GTFS-Realtime vehicle
descriptor where it can; the Transit Operational Data
Standard has its own three-field
vehicle table with the same alignment note. The two specifications are
siblings: TODS describes the schedule as the garage runs it, including deadheads
and crew runs, and is usually kept private. TIDES describes what those vehicles
then did, and can be public.
Where it came from and who runs it
The schemas are based on TCRP Research Report 235, Improving Access and Management of Public Transit ITS Data, published by the Transportation Research Board in 2022. The report is 60 pages and proposes a data structure for storing bus and rail ITS data. The TIDES repository acknowledges that origin and then disclaims it in the same breath: neither the project nor the repository is associated with TCRP, TRB, or the National Academies, and using the research does not imply their endorsement. TIDES is not a federal standard and nobody is required to produce it.
The GitHub repository dates from August 2022. Cal-ITP, the California Integrated Travel Project run by the state transportation agency and Caltrans, incubated the specification alongside two others, TODS and the Mobility Data Interoperability Principles. The handover out of California was formal. On 2023-12-06 the TIDES board approved by unanimous consent a memorandum of understanding making MobilityData the TIDES Manager, and the executed document sits in the governance record. It is signed 2024-01-03 and its footer says effective 2023-12-14, while its own terms say it takes effect on final signature. The same terms say it runs until 2025-03-15, extendable in one-year increments by written agreement, and either party can end it on 60 days’ written notice. No extension appears in the published governance actions, whose last entry is dated 2024-12-04, so the current basis for MobilityData’s role is not on the public record. MobilityData announced the arrangement publicly on 2024-03-04, together with TODS and MDIP, and the result is that one nonprofit now manages GTFS, GBFS, MDIP, TIDES, and TODS.
The board owns the specification. It has five members serving as individuals rather than as delegates, on staggered three-year terms, and the governance document says a majority should come from transit agencies. The live governance page lists one member with a transit agency affiliation, at WMATA, one at Caltrans, which the same document counts as a DOT rather than an agency, one with no affiliation shown (the 2024-12-04 membership record had him at Metro Transit in Minneapolis), one at a consultancy, and one at an analytics vendor. Read literally, the page does not show the majority the policy asks for. Decisions need two thirds of the non-abstaining members of the whole board, not just of those voting. A MobilityData contractor is the program manager and runs the change process, which requires scored reviews from contributors outside the drafting group before a change merges.
The licence is split. The specification, documentation, and sample data are CC BY 4.0. The validation scripts and tooling are Apache 2.0. Copyright sits with the board.
Versions, and what v2.0 changes
The version history is short. A v1.0-beta.1 shipped on 2024-01-06 with all eleven tables. Version 1.0 followed on 2025-12-23 by the changelog’s date, with the GitHub tag and release landing three days later, and carried no normative changes at all; the release notes describe it as a stable baseline before v2.0 work begins, and promised v2.0 pre-releases in early 2026.
That has slipped. As of 2026-09-11 no v2.0 tag exists. The release checklist
issue, opened 2026-06-29
and updated the day before this piece was written, lists nine pull requests and
their status. The largest change renames passenger_events to device_events
and widens it from on-board passenger counters to any measurement device,
including station fare gates and handheld validators. Anyone who has written a
query against v1.0 will care about two others. The stop_visits duration fields
lose their _time suffix in favor of _duration, so a timestamp and an elapsed
time can no longer be confused. And departure_load will be allowed to go
negative, on the reasoning that load is boardings minus alightings, APC error
produces negative results, and clamping them to zero biases every aggregate
upward. The stub operators table becomes a crew table with a vehicle_crew
companion for mid-trip reliefs, and the vehicle tables are restructured around a
new vehicle_groups lookup so rail consists and mixed fleets can be described.
An open question on whether enum values inherited
from GTFS and NTD convert to snake_case along with the TIDES-defined ones was, at
the time of writing, still being taken up by the contributors group.
The board approved a 2026 to 2027 roadmap on 2026-06-10. The pull request that publishes it was still open three months later, which is a fair summary of the project’s pace: real work, done by volunteers and one contractor, landing slower than the release notes say.
Who actually has TIDES data
The spec has existed in usable form since January 2024. The list of organizations that have produced it is short enough to give in full.
The biggest public dataset is California
TIDES, published by Caltrans’s Division of Data
and Digital Services from the Cal-ITP warehouse. What is in it is narrower than
the name suggests. Cal-ITP’s own expansion
epic, opened 2026-06-23,
states that the bucket holds two TIDES tables, vehicle_locations and
trips_performed. Both are derived from Cal-ITP’s archive of the agencies’
GTFS-Realtime feeds, not from AVL or APC systems directly, with
trips_performed joined to the schedule for route, direction, block, and
scheduled start and end. The warehouse model restricts publication to feeds
flagged as public, customer-facing fixed-route service or a regional subfeed of
one, minus an explicit denylist. The warehouse’s floor for the product is
2025-12-01, which is not the same as proven coverage in the bucket back to that
date, and the export job that writes parquet files runs on Mondays and
Thursdays. The epic’s stated goal is to add stop_visits, investigate
fare_transactions, and co-publish the GTFS schedule and organization reference
data into the same bucket so that a record can be resolved to an agency and
route for any service date. The reference half landed on 2026-09-02: a weekly
job now writes the organization, feed, and service lookup tables to a
reference/ prefix in the bucket with a Frictionless data package beside each
and a DCAT catalog over the lot.
So the largest public TIDES dataset is, today, an archive of GTFS-Realtime joined to the schedule, with a service date and a performed trip attached. Cal-ITP was already archiving the vehicle positions feeds of California agencies, and turning that archive into two TIDES tables is the cheapest first implementation available. It is a useful correction to the idea that TIDES adoption means an agency has opened up its passenger counters.
The most complete agency implementation is WMATA’s, funded by a USDOT SMART grant and written up as the SMART Data Hub case study by the consultant who led it. It is described throughout as a prototype. WMATA took the approach of transforming source-system data into TIDES inside its own data lake, using Dagster for orchestration, dbt for the transformations, Iceberg tables on Azure storage, and Trino as the query engine, with OpenMetadata cataloguing the result. The dbt models that produce each TIDES table are open source in the implementations repository. The author’s own note calls it the first TIDES implementation at a major agency, and the ridership metrics it computes from the TIDES tables are the point of the exercise.
At the other end of the scale, Mountain
Line in
Missoula, Montana, with 29 fixed-route buses and 17 paratransit vehicles, is
building what its analyst calls an “analyst on a laptop” pipeline in Python. It
feeds vehicle_locations and trips_performed from its CAD/AVL vendor,
passenger_events and stop_visits from Swiftly-processed APC data, and
demand-response trips from Via. The stated target is an NTD reporting pilot,
co-designed with MobilityData alongside WMATA’s, that runs TIDES-derived NTD
metrics in parallel with the agency’s existing reporting for fiscal year 2027.
The work is in progress, and so far it has put out two MIT-licensed libraries: a
Polars schema validator for every TIDES table, released as an alpha, and a small
pipeline runner.
Those three are the implementations with public artifacts as of this writing.
The implementations repository, stewarded by MobilityData, has two agency
folders. The resource list adds one converter, a set of scripts by a Caltrans
engineer that turns collected GTFS-Realtime vehicle positions and trip updates
into vehicle_locations and trips_performed, which is the same recipe
California runs at scale. The implementation guide, procurement language, and
the NTD and on-time performance use-case profiles are all marked coming soon on
the project’s resource page.
How to pull the California data
The California bucket is the one dataset a reader can go and get, so here is how. The commands are Cal-ITP’s, from its own example repository; we have not run them against a billing project ourselves.
The bucket is gs://calitp-tides and it is requester-pays. There is no
anonymous download, the browser console’s download button is unreliable on
requester-pays buckets, and every request has to be billed to a Google Cloud
project you own. Caltrans’s page puts the egress for the example, one day of LA
Metro’s two feeds, at pennies. Install the gcloud CLI, log in with an account
that has a billing-enabled project, and pass that project on every command.
gcloud auth login
export TIDES_BILLING_PROJECT=your-project-id
gcloud storage ls gs://calitp-tides/ --billing-project=$TIDES_BILLING_PROJECT
Objects are laid out by table, then publishing organization, then feed, then service date:
gs://calitp-tides/vehicle_locations/
organization_source_record_id=recPnGkwdpnr8jmHB/
base64_url=aHR0cHM6Ly9hcGku.../
dt=2026-05-28/
data_*.parquet
The organization identifier is an opaque record id from Cal-ITP’s ingest
metadata. The feed identifier is the feed’s URL, base64-encoded, so it can be
decoded locally. Both resolve through the provider_gtfs_data and
gtfs_datasets tables that Cal-ITP publishes on the California open-data
portal and, since September 2026, under the bucket’s own reference/ prefix.
To fetch one service day for one feed:
gcloud storage cp \
"gs://calitp-tides/vehicle_locations/organization_source_record_id=recPnGkwdpnr8jmHB/base64_url=<feed>/dt=2026-05-28/*.parquet" \
./la_metro_bus_2026-05-28/ \
--billing-project=$TIDES_BILLING_PROJECT
A partition holds several parquet shards of roughly equal size, each an
arbitrary slice of rows that already contains every route. Cal-ITP’s example
notes that LA Metro’s bus feed, at around 1,680 vehicles and about 2.2 million
pings a day, lands as about eight shards, while its rail feed is a single small
file. Read them with any parquet-capable tool. To color vehicles by route you
will need to join trip_id_performed to the GTFS that was in effect on that
service date, because LA Metro regenerates its feed often and reassigns trip
identifiers, so the join has to be against the historical GTFS, not today’s.
Validation is separate from download. The TIDES repository wraps the Frictionless Framework, and its own instruction is to validate a data package with schema syncing on, so that the optional columns a file leaves out are not reported as missing:
frictionless validate --schema-sync path/to/your/datapackage.json
Without --schema-sync, a conforming file that carries only the required
columns fails with one missing-label error per absent optional field. The
California parquet files also carry the partition columns from their bucket
path, so they need those stripped before a schema check.
What to watch
The v2.0 release is the first thing. When it lands, passenger_events becomes
device_events, several stop_visits columns are renamed, operators becomes
crew, the vehicle tables gain a vehicle_groups lookup, and any pipeline
written against v1.0 needs the migration guide that ships with it. Producers
who have not started have a reason to wait a quarter; consumers who have
started should pin the version in their datapackage descriptor.
The second is whether California adds stop_visits. Stop-level arrivals and
departures are what turn an archive of pings into on-time performance, and the
epic that plans it has been open since June. When it happens, the bucket becomes
the first place to compare stop-level reliability across dozens of agencies in
one format, which nobody outside a vendor has been able to do.
The third is the NTD pilot. If TIDES-derived ridership and service metrics match what WMATA and Mountain Line report through their current processes for fiscal 2027, the specification acquires the use case that makes a procurement officer write it into a contract. The procurement language the project has promised does not exist yet. Until it does, TIDES will keep arriving the way it has so far: one grant-funded data lake, one analyst with a laptop, and one state that already had the feeds archived.
Common questions
- What is TIDES in transit?
- TIDES is the Transit Integrated Data Exchange Specification, an open format for archived transit operations data: vehicle locations from AVL, boardings and alightings from automatic passenger counters, and fare transactions from the fare system, plus the summaries an agency builds from them. Version 1.0 was released 2025-12-23. It is governed by a five-person board and managed day to day by MobilityData under a memorandum of understanding signed in January 2024.
- What does TIDES stand for?
- The project's own site and GitHub repository expand it as Transit Integrated Data Exchange Specification. MobilityData's 2024 announcement called it the Transit ITS Data Exchange Specification, and Caltrans's data portal calls it the Transit Integrated Data Exchange Standard. All three refer to the same specification.
- How is TIDES different from GTFS-Realtime?
- GTFS-Realtime is a live feed: the position of each vehicle right now, refreshed every few seconds and then overwritten. TIDES is the archive: a table of every one of those positions with a service date and a performed trip, plus tables the realtime feed never carries, such as passenger counts per stop, fare transactions, and door, ramp, and lift events. Of the 22 fields in the vehicle_locations table, six are defined by reference to GTFS-Realtime.
- What tables are in TIDES?
- There are eleven: three event tables (vehicle_locations, passenger_events, fare_transactions), three summary tables (stop_visits, trips_performed, station_activities), and five reference tables (devices, vehicles, train_cars, vehicle_train_cars, operators). Together they define 157 fields, of which 31 are required within their table. No table is itself required; an agency publishes whichever apply.
- Who publishes TIDES data?
- As of September 2026, the largest public dataset is Caltrans's California TIDES repository, a requester-pays Google Cloud Storage bucket holding vehicle_locations and trips_performed for California fixed-route agencies, both derived from Cal-ITP's archive of the agencies' GTFS-Realtime feeds. WMATA built a TIDES data lake under a USDOT SMART grant, and Mountain Line in Missoula is building a TIDES pipeline for its FY2027 National Transit Database reporting pilot. TODS, its sibling specification, is typically not published at all.
- Is TIDES an official federal or TRB standard?
- No. The schemas are based on TCRP Research Report 235, published by the Transportation Research Board in 2022, but the TIDES project states that it is not associated with TCRP, TRB, or the National Academies, and that its use of the research does not imply their endorsement. TIDES is community-governed and licensed under CC BY 4.0 for the specification and Apache 2.0 for the code.