# What GTFS-Realtime is, and how a feed works

> GTFS-Realtime is the standard for live transit data: what a feed carries, how Protocol Buffers structure it, and why the quality rests on the systems behind it.

Published 2026-07-14 by Nick Sawinyh.
Explainer in Feeds & Standards.
Canonical: https://its-feed.com/articles/what-is-gtfs-realtime/
Keywords: gtfs realtime, gtfs-rt, gtfs realtime feed, trip updates, vehicle positions, service alerts, protocol buffers

---

GTFS-Realtime, often shortened to GTFS-RT, is the standard that carries live transit
information: when the next bus is actually coming, where the vehicle is right now, and what
is disrupted on the network. It is a [feed specification](https://gtfs.org/realtime/) that
public agencies publish and that apps read, and it is the moving-picture companion to the
static [GTFS schedule](https://its-feed.com/articles/what-is-gtfs/). The schedule says what is supposed to happen. GTFS-Realtime says what
is happening.

The name causes some confusion, so it helps to be precise. GTFS-Realtime is a publishing
format, not a tracking system: it does not locate vehicles or compute arrivals on its own.
It is the agreed shape of the message an agency puts on the web once its own systems have
already worked out the location and the prediction. That distinction matters, because it
explains why two agencies can both publish valid GTFS-Realtime and still deliver very
different experiences. The format is the easy part.

## What a feed carries

A GTFS-Realtime feed is built from three kinds of entity, and every agency that runs a live
feed publishes one or more of them. They line up with the questions a rider actually asks.

| Entity type | What it carries | The question it answers |
|---|---|---|
| [TripUpdate](https://gtfs.org/documentation/realtime/feed-entities/trip-updates/) | Predicted arrival and departure times at each stop, carried as StopTimeUpdates, plus delays, skipped stops, and cancellations | When will my bus actually get here? |
| [VehiclePosition](https://gtfs.org/documentation/realtime/feed-entities/vehicle-positions/) | The vehicle's live location, bearing, speed, which stop it is working toward, and optional occupancy | Where is the vehicle now? |
| [Alert](https://gtfs.org/documentation/realtime/feed-entities/service-alerts/) | Human-readable messages about disruption, the stops or routes affected, the cause, the effect, and when it applies | What is disrupted, and why? |

Trip updates are the workhorse. The specification describes them as fluctuations in the
timetable, and each one is a set of per-stop predictions expressed either as an absolute
time or as a delay in seconds against the schedule. That framing is deliberate. A trip
update is anchored to a scheduled trip in the static GTFS, so a prediction is always "this
scheduled trip, running this many seconds late" rather than a free-floating estimate. The
countdown clock on a bus-stop sign and the arrival time in a trip planner are both reading
trip updates.

Vehicle positions are the raw geography. The spec is blunt about where the data comes from:
a vehicle position provides automatically generated information on the location of a
vehicle, such as from a GPS device on board. Latitude and longitude are reported in the
standard WGS-84 coordinate system, alongside bearing, speed, and a status flag for whether
the vehicle is in transit to, incoming at, or stopped at its next stop. Occupancy and
congestion fields exist too, though agencies populate those far less consistently than
location.

Service alerts are the words. When a station closes or a route detours, the alert entity
carries the human-readable text, points at the affected agency, route, trip, or stop, and
records a cause and an effect from a fixed list. The spec draws a clean line here that
producers sometimes miss: delays and cancellations of individual trips belong in trip
updates, and alerts are for the broader disruption a rider needs to read in sentences.

## How the feed is built

Underneath, a GTFS-Realtime feed is a single [Protocol Buffers](https://protobuf.dev/overview/)
message. Protocol Buffers, or protobuf, is Google's language-neutral, platform-neutral
format for serializing structured data. You define the shape once in a schema file, and a
compiler generates the code to read and write it in whatever language you use. The result is
a compact binary payload rather than text, which the protobuf documentation sums up as being
like JSON, only smaller and faster. That choice is the reason an entire fleet can be
re-fetched frequently without moving much data.

The shape of that message is fixed by one [schema file](https://github.com/google/transit/blob/master/gtfs-realtime/proto/gtfs-realtime.proto),
`gtfs-realtime.proto`, and the whole standard nests inside three messages. A FeedMessage
wraps one FeedHeader and a repeated list of FeedEntity. Each FeedEntity, in turn, carries
exactly one of the entity types from the table above. Learn those three names and you have
read the structure of every GTFS-Realtime feed there is.

![Nested structure of a GTFS-Realtime message. An outer FeedMessage box contains a FeedHeader strip (gtfs_realtime_version, timestamp, incrementality) and a FeedEntity band. Inside the FeedEntity band are three option boxes: trip_update carrying a TripUpdate, vehicle carrying a VehiclePosition, and alert carrying an Alert. Each FeedEntity carries exactly one of the three.](https://its-feed.com/charts/what-is-gtfs-realtime-structure.png)

*Every response is one FeedMessage. The header holds the version and a timestamp, and each entity in the list holds exactly one trip update, vehicle position, or alert. Source: GTFS-Realtime reference and gtfs-realtime.proto (gtfs.org; google/transit).*

The FeedHeader is small but load-bearing. It carries a `gtfs_realtime_version` string, which
is currently `2.0`, and a `timestamp` marking the moment the content was built, so a consumer
can tell how fresh the data is. It also carries an `incrementality` field, and this is where a
practical constraint hides. The specification defines two modes, FULL_DATASET and
DIFFERENTIAL, and per the [GTFS-Realtime reference](https://gtfs.org/documentation/realtime/reference/),
DIFFERENTIAL is currently unsupported. In practice that means every feed runs as a full
dataset: each fetch returns the complete current state of every trip, vehicle, and alert, not
a delta since last time. There is no standard way to subscribe to just the changes.

## How one prediction reaches a rider

Because the feed is a full snapshot, the model on the consumer side is a poll, not a
subscription. A feed is a stream of these messages, and each message is obtained as the
response to an ordinary HTTP GET request against a feed URL. An app fetches the current feed,
decodes the protobuf, uses what it needs, and comes back on a short interval for the next
snapshot. Nothing is pushed.

That is only the final step of a longer chain. Following it backward is the quickest way to
see why a technically clean feed can still show a rider the wrong time.

![Left-to-right flow of one arrival prediction across five stages: a vehicle with onboard GPS, an AVL or CAD fleet-management system, a feed producer that turns positions into predictions and encodes them as Protocol Buffers, an HTTP endpoint that serves the feed, and a rider app that fetches and decodes it. A bracket marks the feed producer through the rider app as the span the standard covers.](https://its-feed.com/charts/what-is-gtfs-realtime-flow.png)

*GTFS-Realtime standardizes only the last stretch: what the producer publishes and the app reads. Everything to the left of it, the location and the prediction, is the agency's own systems. Source: GTFS-Realtime reference and gtfs-realtime.proto (gtfs.org; google/transit).*

The location starts on the vehicle, usually from onboard GPS, and flows into the agency's
automatic vehicle location system, the same fleet-management platform dispatchers watch. A
feed producer then does the real work: it matches each vehicle to a scheduled trip, computes
how late that trip is running, projects that delay forward to the stops still ahead, and
encodes the whole picture as a protobuf message. That message goes up at an HTTP endpoint,
and the rider's app pulls it down. The standard governs only the last stretch, from the
producer's output to the app's input. Everything upstream, the accuracy of the GPS and the
quality of the prediction model, is the agency's own system and is where feeds mostly differ.

## Why it matters for the data layer

GTFS-Realtime is one of the standards that makes the transit part of
[intelligent transportation systems](https://its-feed.com/articles/what-are-intelligent-transportation-systems/)
actually interoperable. It first appeared in 2011, [added](https://gtfs.org/about/) to the
static GTFS that a few years earlier had already turned agency schedules into a format any
app could read. GTFS-RT did the same thing for live data. Before it, every agency that wanted
real-time arrivals in a third-party app had to strike a custom integration, and most simply
did not. A single published format is what let one app show live buses across many cities
without negotiating a separate interface for each agency.

The catch is the one the flow diagram makes plain. A valid feed is a low bar. The protobuf
will parse, the three entities will be well formed, and the arrivals can still be wrong,
because the predictions were built on stale positions or a mismatch against the schedule.
This is the recurring lesson of the data layer: the standard guarantees that systems can
exchange data, not that the data is any good. Conformance and feed quality are separate
problems from format, and they are where the harder work sits.

## What to watch

The core three entities have been stable for years, but the specification is still moving at
the edges. Newer entity types, including shapes, stops, and trip modifications, have been
added to the schema to describe detours and reroutes more precisely than an alert can, and
some fields carry an experimental label until adoption settles. Occupancy data is the clearest
example of a field that exists in the spec but that riders cannot yet count on, because it
depends on onboard passenger counters that many fleets do not have. When you evaluate a feed,
read the version in the header, then check which optional fields the producer actually
populates rather than assuming the spec's full menu is on the table.

The thing to hold onto is the division of labor. GTFS-Realtime gives the industry a shared
answer to a narrow question: how should live transit data be shaped so that anyone can read
it. That question is settled, and settling it was worth a great deal. The open questions, the
ones that decide whether the countdown clock is right, live one step upstream, in the systems
that produce the feed rather than the format that carries it.

## Frequently asked questions

### What is GTFS-Realtime?

GTFS-Realtime, often shortened to GTFS-RT, is the standard that carries live transit information: when the next bus is actually coming, where each vehicle is, and what is disrupted on the network. It is a feed specification agencies publish and apps read, the moving-picture companion to the static GTFS schedule.

### Is GTFS-Realtime a vehicle tracking system?

No. It is a publishing format, not a tracking system: it does not locate vehicles or compute arrivals on its own. It is the agreed shape of the message an agency puts on the web once its own systems have already worked out the location and the prediction.

### What does a GTFS-Realtime feed carry?

Three kinds of update: trip updates (delays and predicted times), vehicle positions (where vehicles are right now), and service alerts (disruptions on the network). Every agency running a live feed publishes them in the same message shape.

---

Source: ITS Feed, https://its-feed.com/articles/what-is-gtfs-realtime/
ITS Feed is an independent editorial site on the data and technology layer of transportation, published by the team at Veodyn. Figures trace to the sources linked inline.
Site index for agents: https://its-feed.com/llms.txt
