2
The most common request is a damaged bin lid.
There are 539 different request types. The ten most common add up to 135,681 requests, which is 27.1% of everything. The other 529 types share the rest.
A small data story from City of Toronto Open Data
Every customer-initiated 311 request the City logged in 2025, loaded into SQLite and explored with SQL. Here are five things the data shows, and a few things it cannot.
1
Requests ran between about 33,000 and 54,000 a month. January was the quietest at 32,793 and February the busiest at 53,707, and February is the shortest month of the year.
19 Feb was the busiest day of the year with 6,168 requests. The five busiest days all fall between 14 Feb and 21 Feb.
The top three request types on 19 Feb were Sidewalk Snow Clearing Required (2,000), Road Plowing Request (1,059) and Driveway Blocked By Plowed Snowbank (711). That pattern fits a snow event. I did not check weather records, so it is a reading of the data and not a finding.
Five busiest days
Top request types on 19 Feb
| Month | Requests |
|---|---|
| 2025-01 | 32,793 |
| 2025-02 | 53,707 |
| 2025-03 | 37,317 |
| 2025-04 | 38,111 |
| 2025-05 | 44,571 |
| 2025-06 | 46,971 |
| 2025-07 | 48,120 |
| 2025-08 | 43,555 |
| 2025-09 | 44,851 |
| 2025-10 | 37,840 |
| 2025-11 | 33,525 |
| 2025-12 | 38,908 |
| Day | Requests |
|---|---|
| 2025-02-19 | 6,168 |
| 2025-02-18 | 5,076 |
| 2025-02-20 | 4,431 |
| 2025-02-14 | 3,948 |
| 2025-02-21 | 3,204 |
| Request type on 2025-02-19 | Requests |
|---|---|
| Sidewalk Snow Clearing Required | 2,000 |
| Road Plowing Request | 1,059 |
| Driveway Blocked By Plowed Snowbank | 711 |
| School Zone Snow Clearing | 211 |
| Snow at Intersections - Impeded Mobility | 201 |
2
There are 539 different request types. The ten most common add up to 135,681 requests, which is 27.1% of everything. The other 529 types share the rest.
| Request type | Requests | % of all |
|---|---|---|
| Residential Bin Lid Damaged | 24,448 | 4.89 |
| Property Standards and Maintenance Violations | 17,079 | 3.41 |
| Pick up Dead Wildlife | 15,513 | 3.1 |
| Injured - Wildlife | 15,192 | 3.04 |
| General Pruning | 12,873 | 2.57 |
| Road Pothole / Road Damage | 11,304 | 2.26 |
| Residential Bin Body or Handle Damaged | 11,238 | 2.25 |
| Sidewalk Snow Clearing Required | 10,241 | 2.05 |
| Res / Garbage / Not Picked Up | 9,159 | 1.83 |
| Residential Furniture / Not Picked Up | 8,634 | 1.73 |
3
Solid Waste Management Services got 170,443 requests (34.1%), Transportation Services got 130,056 (26.0%) and Municipal Licensing & Standards got 117,630 (23.5%). Overall, 78.5% of all requests are marked Completed.
Requests by division
How each division's requests ended up
Environment, Climate & Forestry stands out: 31.2% of its requests are still marked New, against 3.4% overall. I did not look into why. It could be reporting practice, workload or timing.
| Division | Requests | % of all |
|---|---|---|
| Solid Waste Management Services | 170,443 | 34.1 |
| Transportation Services | 130,056 | 26.0 |
| Municipal Licensing & Standards | 117,630 | 23.5 |
| Toronto Water | 36,839 | 7.4 |
| Environment, Climate & Forestry | 36,174 | 7.2 |
| 311 | 7,690 | 1.5 |
| Parks and Recreation | 1,437 | 0.3 |
| Division | Completed | Closed | In Progress | New | Cancelled | Unknown |
|---|---|---|---|---|---|---|
| Solid Waste Management Services | 139,929 | 2,335 | 2,539 | 311 | 25,093 | 236 |
| Transportation Services | 112,233 | 2,248 | 3,689 | 4,896 | 3,260 | 3,730 |
| Municipal Licensing & Standards | 86,181 | 5,334 | 6,613 | 3 | 16,597 | 2,902 |
| Toronto Water | 30,660 | 250 | 1,821 | 289 | 3,796 | 23 |
| Environment, Climate & Forestry | 15,013 | 0 | 7,195 | 11,283 | 2,659 | 24 |
| 311 | 7,503 | 0 | 71 | 34 | 82 | 0 |
| Parks and Recreation | 1,134 | 0 | 119 | 0 | 182 | 2 |
| Status | Requests | % of all |
|---|---|---|
| Completed | 392,653 | 78.5 |
| Cancelled | 51,669 | 10.3 |
| In Progress | 22,047 | 4.4 |
| New | 16,816 | 3.4 |
| Closed | 10,167 | 2.0 |
| Unknown | 6,917 | 1.4 |
4
Wednesday is the busiest weekday (90,155) and Sunday the quietest (38,291). Weekends are 16.7% of requests; spread evenly over seven days they would be 28.6%. Only 2.7% arrive between midnight and 6 am.
The busiest hour of the week: Wednesday 10:00, 7,847 requests. Hover, tap or use the arrow keys to read another.
| Weekday | Requests |
|---|---|
| Monday | 71,725 |
| Tuesday | 86,366 |
| Wednesday | 90,155 |
| Thursday | 85,772 |
| Friday | 82,897 |
| Saturday | 45,063 |
| Sunday | 38,291 |
| Hour | Requests |
|---|---|
| 00:00 | 4,509 |
| 01:00 | 2,725 |
| 02:00 | 1,767 |
| 03:00 | 1,326 |
| 04:00 | 1,207 |
| 05:00 | 2,096 |
| 06:00 | 5,242 |
| 07:00 | 12,717 |
| 08:00 | 28,599 |
| 09:00 | 41,194 |
| 10:00 | 43,231 |
| 11:00 | 43,275 |
| 12:00 | 39,701 |
| 13:00 | 39,165 |
| 14:00 | 37,958 |
| 15:00 | 36,636 |
| 16:00 | 34,010 |
| 17:00 | 32,067 |
| 18:00 | 25,643 |
| 19:00 | 20,355 |
| 20:00 | 16,237 |
| 21:00 | 13,140 |
| 22:00 | 9,579 |
| 23:00 | 7,890 |
5
The data has no population or household figures, so this says where requests were made, not which ward has bigger problems.
| Ward | Requests | % cancelled |
|---|---|---|
| Toronto-Danforth (14) | 30,476 | 12.9 |
| Davenport (09) | 27,124 | 9.6 |
| University-Rosedale (11) | 27,122 | 10.5 |
| Beaches-East York (19) | 27,018 | 12.1 |
| Etobicoke-Lakeshore (03) | 25,874 | 9.3 |
| Parkdale-High Park (04) | 25,517 | 11.0 |
| Eglinton-Lawrence (08) | 24,221 | 10.6 |
| Scarborough Southwest (20) | 22,300 | 10.6 |
| Toronto-St. Paul's (12) | 21,747 | 8.9 |
| Spadina-Fort York (10) | 21,243 | 9.0 |
analysis.py asks the City's open data API for the 2025 file.results/.build_web.py reads those CSV files, so every figure here can be traced to a query.01_monthly_volume.sqlNumber of 311 service requests created in each calendar month.-- Number of 311 service requests created in each calendar month.
SELECT strftime('%Y-%m', created_at) AS month,
COUNT(*) AS requests
FROM service_requests
GROUP BY month
ORDER BY month;02_top_request_types.sqlThe 10 most common service request types, with their share of all requests.-- The 10 most common service request types, with their share of all requests.
SELECT request_type,
COUNT(*) AS requests,
ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM service_requests), 2) AS pct_of_total
FROM service_requests
GROUP BY request_type
ORDER BY requests DESC
LIMIT 10;03_division_status_mix.sqlStatus breakdown per responsible division (counts). The Python script turns-- Status breakdown per responsible division (counts). The Python script turns
-- this into percentages for the stacked bar chart.
SELECT division,
status,
COUNT(*) AS requests
FROM service_requests
GROUP BY division, status
ORDER BY division, requests DESC;04_hour_by_weekday.sqlRequests by day of week (0 = Sunday ... 6 = Saturday) and hour of day.-- Requests by day of week (0 = Sunday ... 6 = Saturday) and hour of day.
-- Feeds the heatmap.
SELECT CAST(strftime('%w', created_at) AS INTEGER) AS weekday,
CAST(strftime('%H', created_at) AS INTEGER) AS hour,
COUNT(*) AS requests
FROM service_requests
GROUP BY weekday, hour
ORDER BY weekday, hour;05_top_wards.sqlWards with the most requests, and each ward's share of requests that ended-- Wards with the most requests, and each ward's share of requests that ended
-- up Cancelled. Wards with a missing name are excluded.
SELECT ward,
COUNT(*) AS requests,
ROUND(100.0 * SUM(status = 'Cancelled') / COUNT(*), 1) AS pct_cancelled
FROM service_requests
WHERE ward IS NOT NULL
GROUP BY ward
ORDER BY requests DESC
LIMIT 10;06_data_quality.sqlBasic data-quality profile: row count, date range and missing values.-- Basic data-quality profile: row count, date range and missing values.
SELECT COUNT(*) AS total_rows,
MIN(created_at) AS first_request,
MAX(created_at) AS last_request,
SUM(ward IS NULL OR ward = 'Unknown') AS missing_ward,
SUM(request_type IS NULL) AS missing_type,
SUM(location_kind = 'Intersection') AS rows_located_by_intersection,
COUNT(DISTINCT request_type) AS distinct_request_types
FROM service_requests;07_busiest_days.sqlThe five busiest individual days.-- The five busiest individual days.
SELECT date(created_at) AS day,
COUNT(*) AS requests
FROM service_requests
GROUP BY day
ORDER BY requests DESC
LIMIT 5;08_status_overall.sqlOverall status distribution.-- Overall status distribution.
SELECT status,
COUNT(*) AS requests,
ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM service_requests), 1) AS pct
FROM service_requests
GROUP BY status
ORDER BY requests DESC;09_division_volume.sqlRequests per division.-- Requests per division.
SELECT division,
COUNT(*) AS requests,
ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM service_requests), 1) AS pct
FROM service_requests
GROUP BY division
ORDER BY requests DESC;10_busiest_day_types.sqlWhat people were asking for on the single busiest day of the year.-- What people were asking for on the single busiest day of the year.
SELECT request_type,
COUNT(*) AS requests
FROM service_requests
WHERE date(created_at) = (SELECT date(created_at)
FROM service_requests
GROUP BY date(created_at)
ORDER BY COUNT(*) DESC
LIMIT 1)
GROUP BY request_type
ORDER BY requests DESC
LIMIT 5;Data source: 311 Service Requests - Customer Initiated, City of Toronto Open Data (resource "311 Service Requests 2025"), downloaded through the portal's CKAN API on 2026-10-17. The City refreshes the dataset monthly, so running it later may give slightly different numbers. Check the dataset page for licence terms before redistributing the raw data.