# RTD Denver Real-Time Transit Tracker (`automation-lab/rtd-denver-realtime-transit-tracker`) Actor

Export current RTD Denver bus stop arrival predictions, delay values and vehicle positions from official GTFS-Realtime feeds with timestamped dataset rows.

- **URL**: https://apify.com/automation-lab/rtd-denver-realtime-transit-tracker.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.44 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## RTD Denver Real-Time Transit Tracker

Fetch a current **RTD Denver real-time bus arrivals** snapshot and vehicle locations from RTD's official GTFS-Realtime feeds. Use it alongside a Denver RTD schedule when building rider displays or measuring service. Each run records the source feed timestamp and retrieval time, so repeated runs can be compared externally. This is a snapshot exporter, not a hosted live display or historical archive.

### Who is it for?

Transit application developers can refresh stop arrival predictions. Operations analysts can compare trip delays at regular intervals. Mobility teams can export route-filtered vehicle coordinates for maps or downstream dashboards. You can schedule recurring Apify runs and store the resulting datasets in your own database.

### Why use the official feeds?

This Actor downloads RTD's canonical Fall 2025 GTFS-RT protobuf feeds, decodes source trip and stop IDs, and produces flat, typed dataset rows. It does not infer arrival times from a web page or silently return static schedules when live feeds fail. RTD publishes updates asynchronously; the feed timestamp makes freshness observable.

### Getting started

1. Read [RTD's real-time feed page and license agreement](https://www.rtd-denver.com/open-records/open-spatial-information/real-time-feeds) before downloading or redistributing data.
2. Select `both` for stop predictions plus vehicle positions, `arrivals` for stop-level trip updates, or `vehicles` for locations alone.
3. Set `maxItems` and optionally a GTFS `routeId`, `stopId`, or `tripId` from RTD's source data.
4. Optionally enable `includeScheduleDetails` to download the current RTD static GTFS ZIP and join stop names, route names, and trip headsigns to live IDs. It adds about 20 MB of source transfer per run; default is off.
5. Run the Actor, then download the default dataset as JSON, CSV, or Excel. Store consecutive snapshots externally if you need history.

### What does it return?

The default dataset contains `arrival` rows (one predicted stop per trip update) and/or `vehicle` rows (one position per vehicle). Each row has `recordType`, `routeId`, `tripId`, `entityId`, `source`, `feedTimestamp`, and `retrievedAt`. Arrival rows carry `stopId`, `stopSequence`, `arrivalTime`, `departureTime`, and source delays in seconds. Vehicle rows carry `vehicleId`, `latitude`, `longitude`, `bearing`, `speedMetersPerSecond`, and `vehicleTimestamp`. With schedule enrichment on, `stopName`, `routeName`, `tripHeadsign`, and `scheduleSource` come from the official GTFS ZIP when IDs match. Absent source values are null, not guessed.

### Input examples

For a quick snapshot of predicted arrivals:

```json
{"mode":"arrivals","maxItems":10}
```

For a route-specific vehicle map, supply an exact source route ID (for example, a GTFS route ID you obtained from a recent dataset):

```json
{"mode":"vehicles","routeId":"0","includeScheduleDetails":true,"maxItems":25}
```

For a trip-centric service review, use `tripId` from an earlier live snapshot. IDs may change by service day.

### Filtering and result limits

All filters are exact, case-sensitive GTFS IDs, not route names or text search. `routeId` and `tripId` apply to both feeds. `stopId` applies only to arrival predictions: in `both` mode vehicle rows are omitted because GTFS-RT vehicle positions do not identify the selected stop; `vehicles` plus `stopId` is rejected. A no-match query returns an empty dataset without an invented error record. `maxItems` bounds all records at 1–5,000. With `both` and no stop filter, up to half the budget is reserved for arrivals and the remainder for vehicles. A sparse feed may return fewer records than requested.

### How much does it cost to export RTD transit snapshots?

A validated run incurs one `start` event ($0.005), including when the selected filter matches no rows. Each saved dataset row incurs one `item` event. The BRONZE spend-tier price is $0.004068 per item: 1 row costs approximately $0.009068, 10 rows $0.04568, and 100 rows $0.41180. Other monthly Store spend tiers: FREE $0.0046782, SILVER $0.003173, and GOLD/PLATINUM/DIAMOND $0.0024408 per item; all include the $0.005 start event. These are customer billing estimates, not guaranteed invoices or publisher payouts; refunds, fraud, disputes, taxes, corrections and contractual clawbacks can affect payouts. Your applicable tier depends on aggregate monthly Store spend, not this Actor's row count. Check live pricing before running; no residential proxy is used.

### Integrations and recurring monitoring

Schedule a run every few minutes only if your usage complies with RTD's feed terms. Persist `feedTimestamp`, `tripId`, `stopId`, and `retrievedAt` together to compare predictions across snapshots; datasets from different runs are independent. Feed rows may repeat between refreshes. Apify webhooks can send a completion event to your ingestion pipeline; the Actor itself does not send alerts or maintain a history. The Actor uses no AI and sends no feed data to a model provider. It processes official public RTD data in memory and stores only output rows in the per-run Apify dataset, with input and logs managed under your Apify account's retention and deletion settings. Do not enter secrets in the ID filters. For assistance, use the Actor's Store issues tab after publication.

### API: start a run with cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~rtd-denver-realtime-transit-tracker/runs?token=YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' -d '{"mode":"arrivals","maxItems":10}'
```

The returned run object includes the default dataset ID; retrieve its items via `/v2/datasets/<id>/items`.

### API: JavaScript and Python

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/rtd-denver-realtime-transit-tracker').call({ mode: 'vehicles', maxItems: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

```python
from apify_client import ApifyClient
import os
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/rtd-denver-realtime-transit-tracker').call(run_input={'mode': 'arrivals', 'maxItems': 10})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### MCP for transit analysis

Connect an MCP client to the Actor-specific Apify endpoint:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/rtd-denver-realtime-transit-tracker'
```

Claude Desktop, Cursor, and VS Code MCP setup: add the following HTTP server to each client's MCP configuration (the UI for importing the configuration differs by client):

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/rtd-denver-realtime-transit-tracker"}}}
```

Example prompts for Claude Desktop, Cursor, or VS Code: “Run the RTD Denver tracker with arrivals and maxItems 10, and summarize the predicted stops and feed age.” Or: “Export ten current vehicle positions and show route IDs for the map.”

### Source, legality, and accuracy

Read and agree to [RTD's GTFS-Realtime license](https://www.rtd-denver.com/open-records/open-spatial-information/gtfs-realtime-license-agreement). Attribute RTD as required and avoid excessive polling. RTD states real-time data is accurate within two minutes; feed timestamps can still be old or absent. Predictions are not guarantees of actual arrival. All times are UTC ISO 8601. Some vehicles have no route or coordinates; null values are preserved.

### Limitations and troubleshooting

Schedule enrichment decodes static GTFS stops, routes, and trips only when opted in. It does not decode stop\_times for scheduled arrivals, derive delays where RTD omits them, or guarantee names for unmatched identifiers. Delay fields are present only when the upstream feed provides them. A `maxItems` cap does not paginate a momentary feed into historic records. A 4xx response fails immediately; network, 429 and 5xx failures receive up to three bounded attempts. A failed required feed fails the run rather than producing a partial 'both' dataset. If you see zero rows, confirm the exact source IDs, service date, and whether that route operates at this hour. For invalid filter errors inspect the run log and revise the input. No login, browser, or proxy is required for the tested official feed URLs.

### FAQ

**Is this the Denver RTD schedule?** It is primarily a live GTFS-Realtime snapshot. Enable optional static GTFS enrichment for stop/route names and trip headsigns; scheduled times and full timetable exports are not included.

**Can I get an A Line train tracker?** Only if RTD includes its trip/vehicle records in the selected canonical feeds. The Actor does not promise comprehensive rail coverage or map matching.

**Why are some arrival delays null?** RTD may provide a predicted time without a delay value. The Actor never substitutes zero.

**Can I track changes over time?** Yes, schedule repeated runs and compare their timestamped outputs in your own storage; a single run has no previous snapshot.

### Related data

The [RTD GTFS schedule download](https://www.rtd-denver.com/open-records/open-spatial-information/gtfs) is the companion source for static routes, stops, and timetables. There is no same-source automation-lab Actor to cross-link at this time.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/rtd-denver-realtime-transit-tracker/changelog.md

# Actor input Schema

## `mode` (type: `string`):

Arrivals are stop-level trip predictions; vehicles are location snapshots. Both fetches arrivals first, then vehicles until the item limit.

## `routeId` (type: `string`):

Optional exact RTD GTFS route\_id, for example 15. Use IDs rather than route names.

## `stopId` (type: `string`):

Optional exact GTFS stop\_id. Matches arrival predictions only; in both mode vehicle records are omitted because positions do not identify a stop.

## `tripId` (type: `string`):

Optional exact GTFS trip\_id for a specific trip.

## `includeScheduleDetails` (type: `boolean`):

Download RTD's current ~20 MB static GTFS ZIP to add stop names, route names, and trip headsigns to matched realtime records. This does not compute scheduled arrival times.

## `maxItems` (type: `integer`):

Upper bound on total rows across both feeds; arrivals are emitted first.

## Actor input object example

```json
{
  "mode": "both",
  "includeScheduleDetails": false,
  "maxItems": 12
}
```

# Actor output Schema

## `overview` (type: `string`):

Flat, typed arrival and vehicle records with RTD trip/route identifiers and feed timestamps

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxItems": 12
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/rtd-denver-realtime-transit-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "maxItems": 12 }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/rtd-denver-realtime-transit-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxItems": 12
}' |
apify call automation-lab/rtd-denver-realtime-transit-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/rtd-denver-realtime-transit-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jLByOHdB0JFthgPVO/builds/BArebHfRsckNOVeoi/openapi.json
