Why a stench tracker? Because the city's not counting.
The Ashbridges Bay Wastewater Treatment Plant has served Toronto since 1910. It treats roughly half the city's sewage. For years, on the wrong wind, the east end has known about it before the wastewater even leaves the headworks.
"Like a clogged toilet that's been left there for a week."
How the data is collected
Reports are submitted by neighbours through this site. We don't run sensors. We're not a regulator. We're a public counter — when 40 people in M4M report rotten eggs in the same hour, that's a number the plant operators and the councillor's office can be asked about.
Privacy promise — what we do and don't do
This is a community project. We collect the absolute minimum needed to count odour reports and rate-limit spam. Everything below is enforced in code and you can verify it in our open-source repository.
What we never collect
- No name, no account, no login.
- No analytics or third-party trackers (no Google Analytics, no Meta pixel, no Mixpanel — none of it).
- No raw IP address. We compute a one-way HMAC hash with a server-side rotating secret and store only the hash, used solely for rate-limiting. The original IP can't be recovered from it.
- No precise location unless you explicitly opt in on the report form.
What we do collect, and for how long
- Each report stores: postal area (FSA), severity (0/1/3/5 — where 0 means "all clear, no smell here"), optional odour type, optional 280-char description, optional closest-intersection name (a public street like Queen & Carlaw — never your address; selected from a curated allow-list of major Toronto corners. When you pick one, the server stores its public coordinates jittered ~100m so the report can render on the map at neighbourhood resolution, but never at an address), optional jittered GPS location (~100m offset, deterministic per-day so volume doesn't reveal an address), the IP hash (above), and a random ID kept in your browser's localStorage so we can count unique reporters. The only fields you have to fill in are severity ("how bad") and the postal area. All-clear check-ins are stored exactly the same way as positive reports; same 30-day Firestore TTL applies. Auto-deleted from our database after 30 days via Firestore TTL.
- An anonymized analytical row is written alongside each public report (skipped if the report is held for moderation). It contains only postal area, severity, odour type, closest intersection, and a minute-rounded timestamp — no IP hash, no browser ID, no GPS, no description. These rows have no link back to a specific reporter and are kept up to 1 year so analysts can pull seasonal data via the open-data export.
- Aggregated daily counts per FSA are kept indefinitely as a public record. They contain no individual reporter info.
- If you subscribe to alerts, your email is encrypted at rest with a server-side AES-256-GCM key before it's stored, and decrypted only at send time. A separate one-way SHA-256 hash of the address is stored alongside it as a lookup index (so we can dedupe re-subscribes without comparing plaintext). One-click unsubscribe in every email; no login required.
Who sees the data
- Everyone. All counts and reports are visible on the public dashboard the moment they're submitted. There is no private dataset; we don't sell or share data; we don't auto-email the councillor's office or anyone else.
- Coun. Paula Fletcher's office (Ward 14, Toronto–Danforth) and any other interested party can read the live counts directly from this site at any time.
- Description text is scanned for personal info (email/phone/address patterns) before going public. If a description is flagged, the whole report is held in a moderation queue until manually cleared.
Anti-abuse
- 5 reports/hour/IP rate limit. Cloudflare Turnstile verifies you're human (no Google reCAPTCHA — Turnstile doesn't track users across the web).
- Public stats show both report count and unique reporter count — so a single person filing 50 reports doesn't distort the picture.
- Same browser submitting twice in 30 minutes is silently de-duplicated so spam loops don't inflate counts.
Open data
The anonymized dataset is downloadable as CSV or JSON for journalists, researchers, and anyone running their own analysis: 1-year CSV · 90-day CSV · 30-day CSV · 1-year JSON. Capped at 5000 rows per download and 12 downloads per hour per IP.
- Included: minute-rounded timestamp, FSA, severity, odour type, closest intersection, day-of-week, hour-of-day.
- Excluded: the free-text description (unique phrasing can re-identify a reporter even after PII filters), GPS coordinates (≥7 days of jittered points centroid back to a home address), the IP hash, the per-browser ID, and any report held for moderation.
- The export reads from a long-retention companion table that's stripped of every reidentifier at write time. Raw report documents (which carry the IP hash and browser ID) are still auto-purged from the database after 30 days.
Who's behind this
A handful of east-end residents, no funding, no affiliation with the City of Toronto or Toronto Water. The site is open source and runs on Firebase + Vercel. The councillor's office hasn't asked us to do this — but they (and anyone else) can read live counts directly from this dashboard any time.
Also worth doing
This site is unofficial. Reports here are not automatically forwarded to the City. If you want a service request on file, please file with 311 as well.
Call the 24/7 odour complaint line: (416) 392-5153
Toronto Water runs a direct odour complaint line for the Ashbridges Bay plant. A neighbour rang it recently to confirm it's still active. A technician informed them that the protocol followed on every call is:
- Record the complaint in writing.
- Check wind speed and direction.
- Investigate at street level near the resident's home.
- Identify the odour and its source.
- Report back to management.
- Liaise with work groups at the plant.
- Follow up with a callback within two days.
The more people report directly to the treatment plant, the better the response and mitigation tends to be. — tip shared by a neighbour on Facebook.