Every number on this site can be recomputed from these files, on another machine, with different software.
Download the data
Everything below is the data the published numbers are computed from, 12 files and about 20 MB in total. The collision, camera and ticket data are public records from the City of Toronto and the Toronto Police Service; nothing here identifies an individual.
Reproduce the headline numbers
replication.R uses base R only, with nothing to install, and reads the plain CSVs beside it. It prints an OK or FAIL for each check. The study's credibility rests on a simple promise: every published number can be recomputed from the archived data by someone else, on another machine, with different software.
Data & code
A real R session, running in your browser through webR. Nothing is sent anywhere. The camera table is already loaded as sites, one row per camera site. The first run downloads R itself, about 30 MB.
Press Run to start R.
# download the bundle, then: $ Rscript replication.R # or read a single table straight from the site cam <- read.csv("https://toronto-speed-cameras.pages.dev/data/camera_effectiveness.csv") nrow(cam) # 520 camera sites median(cam$pct_change, na.rm=TRUE) # about -10.2 # the departure rebound, on the report's 383-site sample s <- subset(cam, after_rate > 0 & during_rate > 0 & after_months >= 3) nrow(s) # 383 mean(s$during_rate); mean(s$after_rate) # 2.20 ; 2.53 mean(s$after_rate > s$during_rate) # 0.62 wilcox.test(s$after_rate, s$during_rate, paired=TRUE)
$ pip install pandas import pandas as pd BASE = "https://toronto-speed-cameras.pages.dev/data/" cam = pd.read_csv(BASE + "camera_effectiveness.csv") s = cam[(cam.after_rate > 0) & (cam.during_rate > 0) & (cam.after_months >= 3)] len(s) # 383 s[["before_rate","during_rate","after_rate"]].mean() # 2.40 2.20 2.53 (s.after_rate > s.during_rate).mean() # 0.62
$ BASE=https://toronto-speed-cameras.pages.dev/data $ curl -O $BASE/camera_effectiveness.csv $ curl -O $BASE/enforcement_periods.csv $ curl -O $BASE/collisions_flat.csv $ curl -O $BASE/replication.R $ curl -s $BASE/camera_free_year_results.json | head
@techreport{levi2026toronto,
author = {Levi, Ron},
title = {Do Speed Cameras Reduce Crashes? Evidence from Toronto's
Rotational Automated Speed Enforcement Program},
institution = {Community Safety and Policing Research Program,
Global Justice Lab, Munk School of Global Affairs and
Public Policy, University of Toronto},
year = {2026},
month = {7},
note = {Release of 18 July 2026}
}For counts and medians, OK means an exact match within rounding. For p-values, OK means the recomputed and published values land on the same side of the conventional 0.05 threshold; exact p-values can differ slightly because the archived data cache was refreshed in July 2026, which shifted a few sample sizes by one or two sites without changing any conclusion. An OK verdict says the data produce the published number. It does not, by itself, say cameras caused anything.
Columns in the collision file
| Column | Meaning |
|---|---|
| date | Collision date |
| year | Calendar year, 2014 through 2026 |
| injury | Whether at least one person was injured (the TPS any-severity personal-injury flag, not the KSI file) |
| geocoded | Whether the record carries usable coordinates; about 84% do |
| near_camera | Within 250 m of any of the 520 camera sites |
| treated | Within 250 m of a camera while that camera was enforcing |
Spatial operations were performed in EPSG:32617 (UTM Zone 17N, metres). The 16 percent of records without usable coordinates are excluded from the spatial analysis and included in citywide trends; they differ modestly from the geocodable records, skewing less severe.