Real-time road data provides current updates on road conditions and events for
your selected routes, supporting dynamic monitoring and rapid response. This
data differs from the periodically collected data available in BigQuery, and is
suitable for scenarios requiring timely information.

This data streams continuously and includes trip duration, which indicates
travel times on a route, and
[speed reading intervals](https://developers.google.com/maps/documentation/roads-management-insights/rmi-concepts.md.txt#speed-reading-intervals),
which show traffic density along the route.

> [!WARNING]
> **Deprecated:** The `speed_reading_intervals`,
> `travel_duration`, and `retrieval_time` fields are deprecated
> in favor of `speed_reading_offsets`, `duration_in_seconds`,
> `static_duration_in_seconds`, and `retrieval_timestamp`, which
> real-time messages include as of October 8, 2026. Starting January 13, 2027, the
> deprecated fields might no longer be populated. Before then, update your
> subscribers to read the new fields, and add the new columns to any BigQuery
> table that you stream this data to.

**To access real-time road data, your contract must include the Real-Time
Operations package.**

## Create a Travel Duration and Speed Reading Intervals Pub/Sub subscription

Dedicated Google Cloud Pub/Sub topics will be provided to you, those are where
you can subscribe to the real-time data for all your created routes.

The following code sample shows the format of the topic using binary encoding:

```html
projects/maps-platform-roads-management/topics/rmi-roadsinformation-PROJECT_NUMBER
```

We also provide another topic using JSON encoding (suffixed with `-json`). You
must subscribe to the Pub/Sub topic provided to you to receive real-time
data messages. See [Subscribe to a
topic](https://cloud.google.com/pubsub/docs/subscription-overview) for a quick
overview on how to subscribe and consume messages from a Cloud Pub/Sub topic.

### Travel Duration and Speed Reading Intervals schema

Each real-time data message incorporates data such as:

- **Road details** like `duration_in_seconds`, `static_duration_in_seconds`, `speed_reading_offsets` (offset-based speed reading intervals), `retrieval_timestamp`, and `has_road_closure`.
- **Route identifiers** like `selected_route_id` and `display_name`.

Each message is published adhering to the following Protobuf format.

```protobuf
syntax = "proto3";

// Contains the road information like travel duration and speed reading
// intervals for a selected route.
message RoadsInformation {
  // Legacy message. May stop being populated on or after January 13, 2027.
  // Use top-level duration_in_seconds and static_duration_in_seconds instead.
  message TravelDuration {
    // The duration of travel through the route based on current road
    // conditions.
    float duration_in_seconds = 1;
    // The duration of travel through the route without taking road
    // conditions into consideration.
    float static_duration_in_seconds = 2;
  }
  message Timestamp {
    // Represents seconds of UTC time since Unix epoch
    // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
    // 9999-12-31T23:59:59Z inclusive.
    int64 seconds = 1;

    // Non-negative fractions of a second at nanosecond resolution. Negative
    // second values with fractions must still have non-negative nanos values
    // that count forward in time. Must be from 0 to 999,999,999
    // inclusive.
    int32 nanos = 2;
  }
  // Legacy message representing the latitude and longitude of a coordinate
  // within a coordinate-based speed reading interval.
  message LatLng {
    float latitude = 1;
    float longitude = 2;
  }
  // Legacy coordinate-based speed reading interval message. May stop being
  // populated on or after January 13, 2027. Use SpeedReadingOffset instead.
  message SpeedReadingInterval {
    // The coordinates on the polyline for the speed reading interval.
    repeated LatLng interval_coordinates = 1;

    // Describes the categorized current speed of road conditions.
    // Possible values are:
    // - "NORMAL": Road is flowing smoothly, no slowdown is detected.
    // - "SLOW": Slowdown detected, but no congestion formed.
    // - "TRAFFIC_JAM": Traffic jam detected. In this legacy field, heavy
    //   traffic jams (dark red) are also reported as "TRAFFIC_JAM";
    //   "TRAFFIC_JAM_HEAVY" is never used.
    string speed = 2;
  }
  // Offset-based speed reading interval along the route.
  message SpeedReadingOffset {
    // The distance offset from the start of the route in meters for the start
    // of the interval (inclusive).
    int32 start_offset = 1;

    // The distance offset from the start of the route in meters for the end of
    // the interval (exclusive; equals the start_offset of the subsequent
    // interval).
    int32 end_offset = 2;

    // Describes the categorized current speed of traffic, aligned with the
    // colors in the Google Maps traffic layer. Possible values are:
    // - "NORMAL" (green): Traffic is flowing smoothly, no slowdown is detected.
    // - "SLOW" (yellow): Slowdown detected, but no traffic jam formed.
    // - "TRAFFIC_JAM" (red): Traffic jam detected.
    // - "TRAFFIC_JAM_HEAVY" (dark red): Heavy traffic jam detected (available
    //   as of October 8, 2026).
    string speed = 3;
  }
  // Id for selected_route.
  string selected_route_id = 1;
  // User provided name for the route.
  string display_name = 2;
  // Legacy coordinate-based speed reading intervals. May stop being populated
  // on or after January 13, 2027. Use speed_reading_offsets instead.
  repeated SpeedReadingInterval speed_reading_intervals = 3;
  // Legacy travel time information. May stop being populated on or after
  // January 13, 2027. Use duration_in_seconds and static_duration_in_seconds
  // instead.
  TravelDuration travel_duration = 4;
  // Legacy timestamp when the road data was collected. May stop being populated
  // on or after January 13, 2027. Use retrieval_timestamp instead.
  Timestamp retrieval_time = 5;
  // Contains a geojson polyline representing the optimal route determined
  // based on user's input waypoints.
  string route_geometry = 6;
  // Road segment place IDs along the route. They follow topological order
  // and are always connected.
  repeated string road_segment_ids = 7;
  // Offset-based speed reading intervals representing traffic density across
  // the route; each interval is demarcated by the distance offset from the
  // start of the route. Omitted when has_road_closure is true.
  repeated SpeedReadingOffset speed_reading_offsets = 8;
  // The duration of travel through the route based on current traffic
  // conditions. Omitted when has_road_closure is true.
  float duration_in_seconds = 9;
  // The duration of travel through the route without taking traffic
  // conditions into consideration.
  float static_duration_in_seconds = 10;
  // The time the traffic data was collected, as an RFC 3339 UTC timestamp
  // string (for example, "2026-10-08T15:04:05+00:00").
  string retrieval_timestamp = 11;
  // Whether there is a full road closure on the route. When true,
  // duration_in_seconds and speed_reading_offsets are omitted because the
  // route is impassable. Omitted when road closure information is undetermined.
  bool has_road_closure = 12;
}
```

> [!NOTE]
> **Note:** The `has_road_closure` flag is consistent with the full road closure status on Google Maps.

#### Offset-based speed reading intervals and field migration

As of October 8, 2026, speed reading intervals are provided in the offset-based
`speed_reading_offsets` field, where each interval is demarcated by its
`start_offset` (inclusive) and `end_offset` (exclusive) in meters from the start
of the route, and includes the fourth speed category `TRAFFIC_JAM_HEAVY`. For
details on speed categories and interval formats, see
[Speed reading intervals](https://developers.google.com/maps/documentation/roads-management-insights/rmi-concepts.md.txt#speed-reading-intervals).

The following table maps each legacy Pub/Sub field (which may stop being
populated on or after January 13, 2027) to its replacement:

| Legacy field | Replacement field | Notes |
|---|---|---|
| `speed_reading_intervals` | `speed_reading_offsets` | Uses meter offsets (`start_offset`, `end_offset`) instead of polyline coordinates and adds the `TRAFFIC_JAM_HEAVY` speed category. |
| `travel_duration.duration_in_seconds` | `duration_in_seconds` | Flattened to a top-level `float` field. |
| `travel_duration.static_duration_in_seconds` | `static_duration_in_seconds` | Flattened to a top-level `float` field. |
| `retrieval_time` | `retrieval_timestamp` | Formatted as an RFC 3339 string, which BigQuery subscriptions automatically convert to `TIMESTAMP`. |

## Stream Route Data to BigQuery using Pub/Sub

You can configure a Pub/Sub subscription to stream **road data** directly into a
BigQuery table. This allows for robust data storage and enables powerful
analytics on the provided route information. Before setting up this type of
subscription, you need to create a suitable dataset and table in your BigQuery
project to write the data in.

For detailed instructions on how to create a Pub/Sub subscription that writes
to BigQuery, see
[Streaming data to BigQuery](https://cloud.google.com/pubsub/docs/bigquery).
Create the BigQuery subscription on the JSON-encoded topic. When configuring
the subscription, select **Use table schema** and enable **Drop unknown
fields** so that your ingestion pipeline continues running smoothly when new
fields are added. To store new fields, such as `speed_reading_offsets`, add the
corresponding columns to your table.

### BigQuery table schema

The messages published to your Pub/Sub topic, which can also get written to your
BigQuery table, conform to the following schema. You should use this schema when
creating your target BigQuery table to ensure compatibility.

```
[
  {
    "mode": "NULLABLE",
    "name": "selected_route_id",
    "type": "STRING",
    "description": "Id for selected_route."
  },
  {
    "mode": "NULLABLE",
    "name": "display_name",
    "type": "STRING",
    "description": "User provided name for the route."
  },
  {
    "fields": [
      {
        "mode": "NULLABLE",
        "name": "speed",
        "type": "STRING",
        "description": "Describes the categorized current speed of traffic. Possible values are: \"NORMAL\": Traffic is flowing smoothly, no slowdown is detected. \"SLOW\": Slowdown detected, but no traffic jam formed. \"TRAFFIC_JAM\": Traffic jam detected (groups red and dark red segments; does not include \"TRAFFIC_JAM_HEAVY\")."
      },
      {
        "fields": [
          {
            "mode": "NULLABLE",
            "name": "latitude",
            "type": "NUMERIC"
          },
          {
            "mode": "NULLABLE",
            "name": "longitude",
            "type": "NUMERIC"
          }
        ],
        "mode": "REPEATED",
        "name": "interval_coordinates",
        "type": "RECORD",
        "description": "The geometry for this interval"
      }
    ],
    "mode": "REPEATED",
    "name": "speed_reading_intervals",
    "type": "RECORD",
    "description": "Legacy coordinate-based speed reading intervals. May stop being populated on or after January 13, 2027. Use speed_reading_offsets instead."
  },
  {
    "fields": [
      {
        "mode": "NULLABLE",
        "name": "duration_in_seconds",
        "type": "FLOAT",
        "description": "The duration of travel through the route based on\ncurrent traffic conditions."
      },
      {
        "mode": "NULLABLE",
        "name": "static_duration_in_seconds",
        "type": "FLOAT",
        "description": "The duration of travel through the route without\ntaking traffic conditions into consideration."
      }
    ],
    "mode": "NULLABLE",
    "name": "travel_duration",
    "type": "RECORD",
    "description": "Legacy travel time information. May stop being populated on or after January 13, 2027. Use top-level duration_in_seconds and static_duration_in_seconds instead."
  },
  {
    "fields": [
      {
        "mode": "NULLABLE",
        "name": "seconds",
        "type": "INTEGER",
        "description": "Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive."
      },
      {
        "mode": "NULLABLE",
        "name": "nanos",
        "type": "INTEGER",
        "description": "Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive."
      }
    ],
    "mode": "NULLABLE",
    "name": "retrieval_time",
    "type": "RECORD",
    "description": "Legacy timestamp when the traffic data was collected. May stop being populated on or after January 13, 2027. Use retrieval_timestamp instead."
  },
  {
    "mode": "NULLABLE",
    "name": "route_geometry",
    "type": "STRING",
    "description": "Contains a geojson polyline representing the optimal route determined based on user's input waypoints"
  },
  {
    "mode": "REPEATED",
    "name": "road_segment_ids",
    "type": "STRING",
    "description": "Road segment place IDs along the route. They follow topological order and are always connected"
  },
  {
    "fields": [
      {
        "mode": "NULLABLE",
        "name": "start_offset",
        "type": "INTEGER",
        "description": "The distance offset from the start of the route in meters for the start of the interval (inclusive)."
      },
      {
        "mode": "NULLABLE",
        "name": "end_offset",
        "type": "INTEGER",
        "description": "The distance offset from the start of the route in meters for the end of the interval (exclusive; equals the start_offset of the subsequent interval)."
      },
      {
        "mode": "NULLABLE",
        "name": "speed",
        "type": "STRING",
        "description": "Describes the categorized current speed of traffic, aligned with the colors in the Google Maps traffic layer. Possible values are: \"NORMAL\" (green): Traffic is flowing smoothly, no slowdown is detected. \"SLOW\" (yellow): Slowdown detected, but no traffic jam formed. \"TRAFFIC_JAM\" (red): Traffic jam detected. \"TRAFFIC_JAM_HEAVY\" (dark red): Heavy traffic jam detected (available as of October 8, 2026)."
      }
    ],
    "mode": "REPEATED",
    "name": "speed_reading_offsets",
    "type": "RECORD",
    "description": "Offset-based speed reading intervals representing traffic density across the route; each interval is demarcated by the distance offset from the start of the route. Omitted when has_road_closure is true."
  },
  {
    "mode": "NULLABLE",
    "name": "duration_in_seconds",
    "type": "FLOAT",
    "description": "The duration of travel through the route based on current traffic conditions. Omitted when has_road_closure is true."
  },
  {
    "mode": "NULLABLE",
    "name": "static_duration_in_seconds",
    "type": "FLOAT",
    "description": "The duration of travel through the route without taking traffic conditions into consideration."
  },
  {
    "mode": "NULLABLE",
    "name": "retrieval_timestamp",
    "type": "TIMESTAMP",
    "description": "The time the traffic data was collected."
  },
  {
    "mode": "NULLABLE",
    "name": "has_road_closure",
    "type": "BOOLEAN",
    "description": "Whether there is a full road closure on the route. When true, duration_in_seconds and speed_reading_offsets are omitted because the route is impassable. A NULL value indicates that road closure information is undetermined."
  }
]
```