Open source

An open-source civic project. Not affiliated with the Government of Canada or the City of Toronto.

GitHub
Open NshipyardTTC Delays

Nshipyard Canada · TTC delay analysis

Every TTC delay since 2014, on one chart.

Delay time is roughly flat: 1.38 million delay-minutes in 2014 vs 1.29 million in 2024, with bus delays down 16% while streetcar delays rose 49% and subway delays rose 82%.

1,240,037 delay incidents and 15.1 million delay-minutes across the TTC's subway, streetcar, and bus networks, unified on one cause taxonomy from 2014-01-01 to 2026-08-31. The TTC, Toronto's transit agency, changed its delay-coding scheme in 2025 and published no crosswalk between the old and new codes, so every time series died at the break. This is the editorial, versioned crosswalk v1 that bridges it.

…

delay incidents cleaned and crosswalked, 2014-01-01 to 2026-08-31

…

delay-minutes across subway, streetcar, and bus

…

crosswalk rows mapping every observed cause code to 8 categories

…

of incident rows map at high or medium confidence (99.3%)

BusStreetcarSubway
0.00M0.50M1.00M1.50MDelay-minutes

* Unified with crosswalk v1. 2026 is partial (Jan-Aug). Coverage 2014-01-01 to 2026-08-31; pulled 2026-10-09.

This chart exists only because crosswalk v1 maps the 2025+ alphanumeric codes onto the same 8 categories as the 2014-2024 records. No TTC-published crosswalk exists.

The trend

Better or worse? Roughly flat, but the mix changed.

Total TTC delay time fell 6% between 2014 (1,376,820 minutes) and 2024 (1,289,281 minutes). The flat total hides a split: bus delay time fell 16%, streetcar delay time rose 49% (140,112 to 208,998 minutes), and subway delay time rose 82% (39,625 to 72,087 minutes). The 2025 figure, 1,363,898 minutes, is the first full year on the new codes, so comparisons across the 2025 code break are approximate. 2026 is partial, January through August.

Frequency vs severity

Where a dollar of intervention buys the most.

Operations/Crew dominates total time lost: 7.76 million minutes (129,346 hours) across 471,501 incidents, at 16.5 minutes each. Collision is the opposite corner: only 28,712 incidents, but the worst per incident at 19.2 minutes. Mechanical is the second-largest bucket at 3.65 million minutes. Track/Overhead is cheapest per incident, 4.6 minutes, but strikes 61,143 times.

05101520025,00050,00075,000100,000125,000Average minutes per incidentTotal hours lost

Bubble area scales with incident count. Vintage: 2014-01-01 to 2026-08-31.

Failure fingerprints

Two systems, same agency, different failures.

Streetcars are delayed by the streets they run in: Operations/Crew is 49.3% of streetcar delay-minutes (diversions, traffic blocking the rail), Mechanical 18.1%, Security 13.4%. Subways run underground but are delayed by people: Security is 25.1% of subway delay-minutes (disorderly patrons, police), Track/Overhead 16.7%, Emergency/Medical 16.0%, Operations/Crew 16.0%. Buses look like streetcars without rails: Operations/Crew 53.7%, Mechanical 26.0%.

Streetcar

    Subway

      Bus

        Delay-minute shares, 2014-01-01 to 2026-08-31.

        One claim fails verification

        Streetcars do not lose more time to cars parked on the tracks than to mechanical breakdowns. Auto-foul-rail codes total 36,728 minutes across 1,394 incidents; Mechanical totals 400,253 minutes across 47,547 incidents, roughly 11 times larger.

        Disorderly patrons peak at 5 PM

        Subway code SUDP (the TTC code for a disorderly patron) peaks at 5 PM with 1,398 incidents in hour 17, not late at night. The 6 PM to 8 PM window is nearly as high.

        Subway lines

        Line 1 carries half the subway's delay time.

        Over the full 2014-2026 series, Line 1 (Yonge-University) accounts for 50.5% of subway delay-minutes (333,979), Line 2 (Bloor-Danforth) 39.4% (260,533), Line 3 (Scarborough) 6.0%, and Line 4 (Sheppard) 4.0%.

          The missing denominator

          No public ridership denominator exists, so per-rider delay rates cannot be computed. Delay-minutes are not passenger-minutes, and line shares are not per-rider shares.

          Full series, 2014-01-01 to 2026-08-31. Pulled 2026-10-09.

          Timing

          When delays happen.

          Hour of day, by cause category

          Incidents per hour. Security incidents concentrate in the evening across all modes; subway disorderly-patron incidents peak at 5 PM.

          01234567891011121314151617181920212223
          Operations/Crew
          Mechanical
          Security
          Emergency/Medical
          Collision
          Cleaning/Sanitation
          Track/Overhead
          Unclassified

          Incidents · All modes, 2014-01-01 to 2026-08-31.

          Day of week, by cause category

          Average minutes per incident. Sunday incidents average 13.8 minutes, about 14% longer than Friday's 12.1. Saturday averages 13.0.

          MonTueWedThuFriSatSun
          Operations/Crew
          Mechanical
          Security
          Emergency/Medical
          Collision
          Cleaning/Sanitation
          Track/Overhead
          Unclassified

          Avg min/incident · All modes, 2014-01-01 to 2026-08-31.

          The crosswalk

          The code break, audited row by row.

          539 rows map every observed cause code onto 8 categories. 271 rows come from the TTC's own code-description tables, 71 from the TTC's legacy subway code table, 58 are direct matches on the 2024-era plain-language labels, 45 come from another mode's official table, and 94 are pattern-matched to codes the TTC's tables do not cover. Pattern-matched rows are flagged below. 99.3% of incident rows map at high or medium confidence; 8,618 rows (0.7%) rest on pattern matching. No TTC-published crosswalk exists; this one is editorial and versioned.

          Two breaks, not one

          The subway switched code schemes around 2018-2024: legacy codes are mapped from the TTC's own legacy table, not guessed. The 2025 break affects streetcar and bus. The subway never used plain-language categories; its 2014-2024 files always carried codes.

          Sensitivity flag

          Streetcar Track/Overhead jumps from 1.4% of 2024 delay-minutes to 15.7% in 2025 while Mechanical falls 8.1% to 3.6%. Part of that jump may be crosswalk sensitivity at the break, not a real change. Year-over-year comparisons across the break are approximate.

          0 crosswalk rows · Crosswalk v1. Vintage: pulled 2026-10-09.

          CodeOfficial descriptionCategoryModeMethodConfidenceIncidentsMinutes

          Honest caveats

          What this does not show.

          • 1

            No ridership denominators exist in public data, so per-rider delay rates cannot be computed. This applies next to every line and route comparison.

          • 2

            The TTC logs a single primary cause per incident; a delay with two causes appears once.

          • 3

            Delays under 1 minute are not consistently logged. 221,620 zero-minute rows were kept and flagged: the subway logs zero minutes on 65% of incidents (a stable TTC convention, not a data error), streetcars 22.0% in 2025+, buses 12.4%. Zero-minute rows count toward incidents, not minutes.

          • 4

            The 2024-to-2025 crosswalk is editorial, not official. Year-over-year comparisons across the break are approximate; the explorer above shows exactly how each code was mapped.

          • 5

            Coverage is 2014-01-01 to 2026-08-31. 2026 is partial, January through August. The 2025+ files are rolling and the portal refreshes them: portal refresh 2026-09-21, data pulled 2026-10-09.

          Methodology

          How the taxonomy was built.

          Sources

          All three datasets are City of Toronto Open Data under the Open Government Licence - Toronto, pulled 2026-10-09 (portal last refreshed 2026-09-21): TTC Subway Delay Data, TTC Streetcar Delay Data, and TTC Bus Delay Data. Resources were enumerated with the CKAN catalog API (package_show on each dataset slug); exact resource IDs and pull dates are in resource_meta.json in the repo.

          What was joined

          Subway: yearly XLSX files 2014-2024 (12 monthly sheets each) plus the rolling 'TTC Subway Delay Data since 2025' CSV. Streetcar and bus: yearly XLSX 2014-2024 plus the rolling 2025+ CSVs. The official code-description tables were joined first: 140 subway codes, the TTC legacy subway table of 71 codes, 85 streetcar codes, 46 bus codes. Prior-art articles at opendatacanada.ca were methodology reference only; every number was recomputed from the raw files.

          What was normalized

          Monthly-sheet column renames (Gap/Delay, Incident ID), the bus/streetcar Route/Line vs subway Line/Bound difference, and 117 subway station spelling variants normalized to canonical names (2,099 rows, e.g. DANFORT to DANFORTH). One incident-level table results: date, time, mode, line/route, station/location, raw cause code, crosswalked cause category, delay minutes, day of week, hour.

          What was left out

          Dropped rows: streetcar/bus Line placeholders of 999 or 500 (1,752 rows), Min Delay of exactly 999 as a data-entry cap (1,235), Min Delay over 300 minutes (5,391), negative Min Delay (10). Zero-minute rows were kept but flagged (221,620). Raw rows ingested: 1,248,435. Cleaned rows: 1,240,037.

          Exact computation

          Delay-minutes are summed per row of the cleaned incident table; incident counts count rows. Average minutes per incident is total delay-minutes divided by incident count. Category shares are category delay-minutes divided by the mode total. Line shares are line delay-minutes divided by the subway total. All aggregates are published in data/aggregates/; the export script scripts/export_site_data.py reproduces every figure on this page from them.

          Crosswalk v1

          539 rows, methods official 271, official-legacy 71, direct-label 58, cross-mode-official 45, pattern 94; confidence high 416, medium 67, low 56. By incident rows, 99.3% map at high or medium confidence; 8,618 rows (0.7%) rest on pattern matching; zero rows are unmapped. No TTC-published crosswalk exists; this one is editorial and versioned.

          Built October 2026 from City of Toronto open data.

          For developers

          Query it from code, or from an agent.

          Three consumption paths, same canonical data. REST for applications, OpenAPI for integration, MCP tools over streamable HTTP for AI agents.

          Endpoints

          GET/api/v1/delays/by-mode?mode=subway

          One mode: yearly delay-minute trend, failure fingerprint, category totals

          Try it →
          {
            "mode": "subway",
            "trend": [
              { "year": 2014, "delay_minutes": 39625.0,
                "incidents": 17821 }, … ],
            "fingerprints": [
              { "category": "Security", "share": 25.1 }, … ]
          }
          GET/api/v1/delays/crosswalk?q=SUDP&mode=subway

          Search the 539-row editorial crosswalk by code, description, or category

          Try it →
          {
            "total": 1,
            "rows": [
              { "mode": "subway", "cause_code": "SUDP",
                "official_description": "Disorderly Patron",
                "category": "Security", "method": "official",
                "confidence": "high", "incidents": 22482, … }
            ]
          }
          GET/api/v1/delays/by-line

          Subway line shares of delay-minutes over the full series

          Try it →
          {
            "lines": [
              { "line": "Line 1 (Yonge-University)",
                "delay_minutes": 333979.0,
                "incidents": 134725, "share": 50.5 }, … ]
          }

          Connect your agent

          Put this data to work inside your AI tools.

          Pick your harness, copy the prompt, send it to your agent. Your agent runs the setup itself.

          Copy and send this to Claude Code

          Set up the TTC Delays, One Taxonomy MCP server so I can query it from here.
          1. Run: claude mcp add --transport http toronto-ttc-delays https://this-site.example/mcp
          2. Run `claude mcp list` to confirm it connected.
          3. Look up crosswalk code SUDP and tell me its category and incident count, and show me the result.

          Data

          Take the files.

          Versioned releases, MIT licensed. CSV for spreadsheets, JSON for applications. All aggregates plus the editorial crosswalk v1.

          by_year_mode_category.csv

          Delay minutes and incidents by year, mode, cause category

          Download
          frequency_severity_category.csv

          Total minutes, incidents, average minutes per incident per category

          Download
          frequency_severity_code.csv

          Same per (mode, cause code), with official descriptions

          Download
          by_line.csv

          Subway lines by year and category

          Download
          by_hour.csv

          Hour of day by mode and category

          Download
          by_weekday.csv

          Day of week by mode and category

          Download
          crosswalk_v1.csv

          The 539-row editorial crosswalk: code to category, method, confidence

          Download
          summary.json

          Headline totals, vintage, and methodology notes

          Download