-
-
This image is currently processing. Please be patient...
Inspiration
Nearly half of all households in Toronto rent, yet signing a lease often feels like flying blind. Prospective tenants get staged listing photos and marketing copy, while the most important signs of a building's condition and its surroundings (RentSafeTO inspection scores, construction and demolition permits next door, 311 complaints, neighbourhood rents and crime rates) sit in separate city portals, spreadsheets and multi-gigabyte open-data tables.
As students and renters in Toronto's housing crisis, we saw that the balance of information is broken. Landlords screen tenants with credit checks, background checks and references; tenants have no real way to screen the building or the landlord's ad. We built RentReceipts to flip that: an instant, cited, address-level brief for any rental in Toronto, built only from public records. Housing is a central issue in Toronto's 2026 municipal election, and RentReceipts (built for the Hack the Valley x School of Cities challenge) turns the City's own open data into information renters, advocates and journalists can act on, without predicting the election or backing a candidate.
What it does
RentReceipts turns any Toronto address into a brief from public records, where every number links to the dataset row it came from.
- What to flag: the standout facts for the address, computed from the records (no AI): a low or falling inspection score, major construction close by, crime well above Toronto's rate, rent well above the area average, or no air conditioning on file.
- Building record: the City's RentSafeTO inspection score out of 100 with its history and lowest-graded items, compared with the city median, plus heating, cooling, pets, laundry and elevators from the City's apartment building registration, and a rent-control estimate from the year built.
- Paste the ad: paste a rental listing and every claim ("Steps to subway", "Pets welcome", the rent) comes back Confirmed, Challenged or Can't check against the records. For example, the asking rent is compared with CMHC's average for that size of unit in the area, and subway claims are checked against the nearest station.
- Ask about this address: a chat that answers questions using only this address's records, with a source on every line.
- Interactive map: inspected buildings with their scores, construction sites, development applications, 311 requests by intersection, essentials (subway, groceries, pharmacies, hospitals), parks and recreation, and public services, with search and a 3D view.
- Construction & noise score: nearby major construction and 311 noise complaints, weighted by distance and ranked against 400 random Toronto addresses, with a matching heatmap.
- Neighbourhood context: 2021 Census figures (rent burden, renters, income, commuting) and Toronto Police crime rates, each shown next to Toronto's typical neighbourhood rather than as a "danger rating". The whole city can be shaded by rent burden, break-ins, construction density and more.
- Tenant reviews: unverified renter reviews, clearly labelled as opinions, not City records.
How we built it
RentReceipts is a monorepo split across data engineering, a spatial database and the web app:
- Data pipeline (
etl/): a Python ETL pipeline managed withuvextracts, cleans and standardises City of Toronto Open Data from the CKAN API: RentSafeTO evaluations, apartment building registrations, building permits, development applications, 311 requests, address points, neighbourhood boundaries and census profiles, plus Toronto Police crime rates and CMHC rents. - Spatial database (
supabase/): Supabase PostgreSQL with PostGIS. One SQL function builds a whole address brief as JSON, with a citation on every fact, using indexed spatial queries (ST_DWithin,ST_Distance, point-in-polygon) on the geography type, so distances are real metres. - Web app (
web/): Next.js (App Router, Turbopack) and TypeScript, server-rendered and cached, styled with Tailwind CSS. The map is MapLibre GL on OpenFreeMap vector tiles (OpenStreetMap data). - AI: Google Gemini reads pasted ads, checks their claims and answers questions. The server rebuilds the address's records itself, gives Gemini a numbered list of facts, and requires a fact ID on every line. It then checks every number against the cited facts, falling back to a plain template sentence written from the records when a line fails.
Challenges we ran into
- Address harmonization: the same address is written differently across datasets ("Bloor St W" vs "Bloor Street West", unit numbers, different coordinate systems). We anchor everything on the City's address points, join each dataset on its most reliable key (address ID, RentSafeTO building number, intersection or neighbourhood), convert City map coordinates to latitude and longitude, and normalise text only for search.
- Placing 311 requests: the City records requests by cross-street names, not buildings. We match the street pair to the City's intersection file and place a request only when exactly one intersection matches.
- Keeping the AI honest: language models invent plausible numbers. Every AI line must cite our facts and pass automatic number checks, and "Can't check" is always an allowed answer.
- Counting construction fairly: our first construction count only saw the 10 costliest projects near an address. We rebuilt it as a spatial query over every major site, then calibrated the score and heatmap against a sample of Toronto addresses.
- Client-only map library in Next.js: MapLibre only runs in the browser, so we load it dynamically on the client and keep the brief itself server-rendered.
- Ethical data visualization: we avoided neighbourhood "safety scores". Figures are shown next to Toronto's typical value, and measures that aren't good or bad for a renter are shown neutrally.
Accomplishments that we're proud of
- Every fact cited: each number in a brief links back to its dataset and row.
- Grounded civic AI: the ad check and Ask can only state what the records say; their numbers are checked before anyone sees them, and they say "Can't check" instead of guessing.
- End-to-end spatial pipeline: raw open data goes from Python scripts to PostGIS queries to interactive layers on a web map.
- Team parallelization: we split work cleanly between the data pipeline, spatial queries, AI and the dashboard, and merged it all within the hackathon.
What we learned
- Civic open data is valuable but messy: cleaning, address matching and spatial indexing took most of our effort.
- Responsible urban computing: visualizations can easily stigmatize neighbourhoods. 311 counts, for example, reflect how much people report as well as real problems, so we present them with that context.
- Grounding beats prompting: asking a model nicely to be accurate isn't enough; checking its output against the source data is.
What's next for RentReceipts
- Verified reviews from current and past tenants.
- Landlord and Tenant Board hearing history for buildings.
- Alerts when demolition or major construction permits are filed near your building.
- Bus and streetcar stops, alongside the subway stations we already include.
- Other cities with similar open data.
Built With
- city-of-toronto-open-data
- civic-tech
- ckan-api
- etl
- geospatial
- google-gemini-api
- maplibre-gl
- next.js
- node.js
- openstreetmap
- pandas
- postgis
- postgresql
- python
- react
- supabase
- tailwind-css
- turbopack
- typescript
- urban-planning
- uv
Log in or sign up for Devpost to join the conversation.