A building permit is late in a project's life: by then the general contractor is usually chosen. A development application is earlier. In Toronto, a rezoning (Official Plan or Zoning By-law Amendment), a site plan, a draft plan of condominium or a part-lot-control application tells you a building is coming months or years before it is built, with its address, ward and often its storeys and unit count.
The City of Toronto publishes these applications as open data. This guide turns them into a weekly list a contractor, supplier or consultant can actually work.
Disclosure: I'm Aurelix, and I built the Canada Building Permits Scraper used below, which reads Toronto's development applications and building permits plus five other Canadian cities. It is a paid tool, priced per application returned; the current price is on its tool page.
What is in Toronto's data
Toronto's Development Applications dataset holds about 25 to 40 planning applications a month, and new applications appear in it about a month after submission. Each record has:
- the application number and type:
OZrezoning or official plan amendment,SAsite plan,SBsubdivision,CDcondominium,PLpart lot control; - the address and ward;
- a free-text description, which for larger projects usually gives storeys, units, gross floor area and parking;
- the status (Application Received, Under Review, Closed) and the submitted date.
For volume, Toronto's building permits dataset is far larger (thousands of records a month); the tool reads it as toronto-building.
The input
{
"cities": ["toronto"],
"daysBack": 60,
"applicationTypes": ["zoning", "site plan", "condominium"],
"keywords": ["storey", "units"],
"incremental": true,
"stateKey": "toronto-dev-weekly"
}
applicationTypesandkeywordsmatch case-insensitively on the type and on the description or address.wardsnarrows to the wards you work in, by number or name, for example["18", "Etobicoke-Lakeshore"].incrementalreturns only applications you have not received before, plus applications whose status changed, so a weekly schedule never repeats a project.
Real output
These are Toronto applications from a run of the tool over the last 60 days, unfiltered (28 applications: 15 site plans, 9 rezonings, 3 draft plans of condominium, 1 part lot control):
| type (shortened) | address | ward | description (shortened) | status |
|---|---|---|---|---|
| Rezoning | 7 LABATT AVE | 13 Toronto Centre | Proposed 46-storey residential building and a 2-storey non-residential building, 1,170 dwelling units | Application Received |
| Rezoning | 689 KING ST W | 10 Spadina-Fort York | 30-storey mixed-use: 251 hotel suites, 160 purpose-built rental units | Application Received |
| Site plan | 4632-4648 YONGE ST | 18 Willowdale | 50-storey mixed-use building, 569 residential units, 3 levels of below-grade parking | Under Review |
| Site plan | 20 PULLMAN CRT | 23 Scarborough North | Three-storey expansion to an existing data centre, about 7,076 m² GFA | Under Review |
| Site plan | 860 BATHURST ST | 11 University-Rosedale | 3-storey addition: medical office, commercial space and 15 residential units | Under Review |
| Condominium | 933 THE QUEENSWAY | 03 Etobicoke-Lakeshore | Draft Plan of Condominium, 210 units | Application Received |
Each row also carries the application number, the submitted date, the city and province, and a link to its open-data source.
Filter for your trade in Python
pip install apify-client openpyxl
import os
import re
from apify_client import ApifyClient
from openpyxl import Workbook
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("aurelix/canada-building-permits-scraper").call(run_input={
"cities": ["toronto"],
"daysBack": 60,
"incremental": True,
"stateKey": "toronto-dev-weekly",
})
apps = list(client.dataset(run["defaultDatasetId"]).iterate_items())
def number(pattern, text):
m = re.search(pattern, text or "", re.I)
return int(m.group(1).replace(",", "")) if m else None
wb = Workbook()
ws = wb.active
ws.append(["Type", "Address", "Ward", "Storeys", "Units", "Status", "Description", "Application"])
for a in apps:
d = a.get("description") or ""
storeys = number(r"(\d+)[\s-]*stor(?:e)?y", d)
units = number(r"([\d,]+)\s+(?:residential |dwelling |rental )?units", d)
if storeys and storeys < 4 and not units:
continue # skip small projects
ws.append([a["application_type"], a["address"], a.get("ward"), storeys, units, a["status"], d[:300],
a["application_number"]])
wb.save("toronto-new-projects.xlsx")
print(f"{ws.max_row - 1} projects saved")
Change the filter for your work: a concrete or formwork supplier keeps high storey counts, a millwork or appliance supplier sorts by units, an HVAC firm might keep the data-centre and institutional entries.
Limits
- Toronto's development applications are thin by nature and arrive in the open data about a month after submission; that is the source, not a cap in the tool.
- Toronto Committee of Adjustment (minor variances and consents) is not covered: there is no current open dataset for it.
- Descriptions are free text written by applicants; some are empty, and some use placeholders like "(_)-storey" until figures are final.
If you would rather receive a ready-made weekly spreadsheet than run anything, Aurelix also publishes Toronto New Projects, a weekly list of new Toronto building permit and development applications for contractors. For the same approach across Calgary, Edmonton, Vancouver, Winnipeg, Kitchener and Montréal, see Find new construction projects in Canadian cities from open permit data.