GTFS Feed Extractor
Pricing
from $0.35 / 1,000 records
GTFS Feed Extractor
Point at ANY GTFS-static feed URL (BART, MBTA, and thousands of transit agencies worldwide — one global standard) and get flat dataset rows: agency, stops, routes, trips, calendar, stop_times and more. Discovery mode lists a feed's tables. Pay per record.
Point at ANY GTFS-static feed URL and get flat, structured dataset rows — one actor for every transit agency on Earth.
GTFS (the General Transit Feed Specification, originally Google Transit) is the single global standard for public-transit schedule data. Thousands of agencies on every continent — subways, buses, trams, ferries, rail — publish the identical ZIP-of-CSVs: agency.txt, stops.txt, routes.txt, trips.txt, stop_times.txt, calendar.txt, calendar_dates.txt, shapes.txt, fare_*.txt, feed_info.txt and more.
Every other "transit" scraper wraps one agency. This actor is the generic runner: give it any GTFS-static ZIP URL and it turns the tables you ask for into dataset rows — one row per CSV record, the columns preserved exactly, plus a lossless copy of each original record.
What it does
- Extract mode (default): downloads the feed ZIP and parses the tables you choose into flat rows. Each row carries the CSV columns as-is, plus meta columns
_table(which file),_feed_url,_row(0-based index in the table), and_raw(the verbatim original record). - Discovery mode (
listTablesOnly): emits one row per table the feed contains — its name, row count and column names — so you can see what a feed holds before pulling the big tables.
Robust to real-world feed variation: it matches table names case-insensitively against whatever the ZIP actually contains, parses with a proper CSV reader (quoted fields, embedded commas), strips UTF-8 BOMs, tolerates non-UTF-8 feeds and non-standard extension columns, and skips missing tables silently instead of crashing.
Input
| Field | Type | Description |
|---|---|---|
gtfs_url (required) | string | Direct URL to a GTFS-static ZIP feed, e.g. https://www.bart.gov/dev/schedules/google_transit.zip. |
tables | array | Tables to extract, by name (with or without .txt): stops, routes, trips, calendar… Leave empty for a sensible default set (agency, feed_info, calendar, calendar_dates, routes, stops, trips — not stop_times, which is often 100k+ rows). Use ["all"] to extract every table including stop_times/shapes. |
maxRecords | integer | Optional global cap on rows emitted across all requested tables. Keeps a sample cheap. |
listTablesOnly | boolean | Discovery mode — list the feed's tables (name, row count, columns) instead of extracting. |
bearer | string (secret) | Optional bearer token for gated feeds. Never logged. |
extraHeaders | object | Optional extra HTTP headers for gated feeds, e.g. {"x-api-key": "…"}. Never logged. |
Output
One dataset item per CSV record. For a stops row from BART, for example:
{"_table": "stops","_feed_url": "https://www.bart.gov/dev/schedules/google_transit.zip","_row": 0,"stop_id": "A10-1","stop_code": "902101","stop_name": "Lake Merritt","stop_lat": "37.797296","stop_lon": "-122.265287","zone_id": "LAKE","location_type": "0","parent_station": "LAKE","_raw": { "stop_id": "A10-1", "stop_code": "902101", "stop_name": "Lake Merritt", "…": "…" }}
Empty CSV cells become null in the flat columns; _raw preserves the verbatim record (including any values beyond the header).
Finding feeds
Almost every public agency's GTFS feed is cataloged in the MobilityData Mobility Database (https://mobilitydatabase.org), the ~2,000-feed successor to TransitFeeds. Point this actor at any feed's direct download URL.
Pricing
Pay-per-event: $0.0005 per record (one emitted dataset row). Use maxRecords and a focused tables list to control cost — you rarely need every row of stop_times.
Notes & limits
- GTFS-static only. GTFS-Realtime (the protobuf
.pbtrip-update/vehicle-position feeds) is a different format and is not covered here. - Feeds up to 512 MB are supported; larger feeds should be sampled with
maxRecords/tables. - A URL that 404s or isn't a ZIP returns a clear error; a feed missing an optional table simply skips it.
