!

Mapping wildfire safety scores across Canadian neighbourhoods

Photo of Alex Wilkinson
Alex Wilkinson
CEO of Houski
2026-05-23

Canada has run through several of its worst wildfire seasons on record in the last few years. Fire has reached communities from the British Columbia Interior to the Alberta Rockies, across the northern Prairies, into the boreal stretches of Ontario and Quebec, and up to the edge of the Northwest Territories. Jasper lost a large share of its townsite in 2024. Yellowknife emptied out under evacuation order in 2023. Lytton, years after the fire that wiped out the village, is still rebuilding. By the time you read this in May 2026, the first open-burn bans of the year are already in place across multiple provinces.

If you own property in Canada, work in real estate, write insurance, or report on housing, "how exposed is this address to wildfire" is no longer an abstract question. It shows up in mortgage conditions, in renewal letters, in offers that get pulled the week before close.

The problem is that almost everyone is still answering it at the wrong resolution. Insurance underwriting often falls back to a postal code or a forward sortation area, and a forward sortation area can cover half a city. A buyer comparing a neighbourhood tucked against a forested ridgeline with one a few kilometres away in the urban core gets the same answer for both.

That gap is what Houski's score_fire field is built to close. It is a neighbourhood-scale score, resolved to roughly a 1.5 kilometre window around each property, which is far finer than the postal-code and forward-sortation-area geographies most underwriting falls back to. This post walks through what the score is, how to pull it from the Houski API at the address level and aggregated across Canadian communities, and how to combine it with construction details to find properties that are genuinely hardened against fire instead of just lucky on the map.

What score_fire actually measures

score_fire is a 0 to 10 integer that lives on every property in the Houski database. Higher is better. A score of 9 in downtown Toronto means the property has very low modelled wildfire vulnerability. A score of 2 on a slope above a boreal treeline means the property has high modelled vulnerability and an underwriter should look twice.

The model behind it is an area-level exposure score. It is computed across a roughly 1.5 kilometre neighbourhood window around each property, from wildfire history and the fuel in the surrounding landscape. That window is deliberate. What burns houses is the fuel around them, not the cleared lot they sit on.

It does not look at building materials. That is intentional. score_fire describes the situation the building is sitting in. Combine it with exterior_finish, roof_material, and construction_year (covered later in this post) to evaluate the building itself.

Because higher is better, the filter operators read naturally. score_fire_gte=8 returns the safer end of the distribution. score_fire_lte=4 returns the properties that need the most attention.

Pulling score_fire for a single address

Start with a real Canadian address. We will look up a property in West Kelowna, an area that has been on evacuation alert in three of the last four summers. The same workflow runs identically for an address in Jasper, Halifax, Kapuskasing, or anywhere else in the country.

Two-step lookup: resolve the address to a property_id with /search, then pull the fields you want from /properties. The block below is a live call against the real API. The request code and the JSON response are generated every time this page is rendered, so they always reflect the current schema and current data:

API request
TypeScript code
const houski_data = async (): Promise<SearchResponse> => {

    // You must copy the SearchResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/search');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('max_results', '1');
    url.searchParams.set('query', '2575+Boucherie+Rd+West+Kelowna+BC');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: SearchResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 0.019999999552965164,
  "data": [
    {
      "address": "2775 Boucherie Road",
      "property_id": "38bea0bd31929180"
    }
  ],
  "error": "",
  "match_meta": [
    {
      "match_value": 0.9166666865348816,
      "property_id": "38bea0bd31929180"
    }
  ],
  "price_quote": false,
  "result_total": 1,
  "time_ms": 1174
}

Once you have the property_id, pull the fire score and the structural fields you need to interpret it:

API request
TypeScript code
const houski_data = async (): Promise<PropertiesResponse> => {

    // You must copy the PropertiesResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/properties');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('property_id_eq', 'bd9c6fb24c31c772');
    url.searchParams.set('select', 'address,city,score_fire,exterior_finish,roof_material,construction_year,interior_sq_m,land_area_sq_m');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: PropertiesResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 0.6299999952316284,
  "data": [
    {
      "address": "302 610 17 Avenue SW",
      "city": "Calgary",
      "construction_year": 1979,
      "exterior_finish": "Brick",
      "interior_sq_m": 92.43848419189452,
      "land_area_sq_m": 0.0,
      "property_id": "bd9c6fb24c31c772",
      "roof_material": "Asphalt",
      "score_fire": 9
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 1,
  "time_ms": 25,
  "ui_info": {
    "address": "302 610 17 Avenue SW",
    "address_link": "ca/ab/calgary/beltline/302-610-17-avenue-sw",
    "address_slug": "302-610-17-avenue-sw",
    "city": "Calgary",
    "city_id": "6ec95b53075d062c",
    "city_link": "ca/ab/calgary",
    "city_slug": "calgary",
    "community": "Beltline",
    "community_id": "ecc51da246c7dd4a",
    "community_link": "ca/ab/calgary/beltline",
    "community_slug": "beltline",
    "country": "Canada",
    "country_abbreviation": "CA",
    "country_abbreviation_id": "9ace2b6431b7f1be",
    "country_abbreviation_link": "ca",
    "country_slug": "canada",
    "parent_address": "610 17 Avenue SW",
    "parent_property_id": "52a7d622eafe5319",
    "property_id": "bd9c6fb24c31c772",
    "province": "Alberta",
    "province_abbreviation": "AB",
    "province_abbreviation_id": "aae1f05a0f89d2c7",
    "province_abbreviation_link": "ca/ab",
    "province_slug": "alberta"
  }
}

The select parameter is mandatory in spirit even when the docs do not strictly require it. Every field you do not request is a field you do not pay for.

A low score_fire result combined with vinyl siding and asphalt shingles is the profile that insurers are starting to surcharge or decline outright. The same address with a metal roof and Hardie board would still have the same score_fire, but the combined risk story changes.

Aggregating score_fire across Canadian communities

The /aggregate endpoint is where this gets useful for planners, journalists, and anyone trying to compare neighbourhoods rather than individual lots. It takes the same filter parameters as /properties but returns a single aggregated value.

Median fire safety score for the city of Kelowna:

API request
TypeScript code
const houski_data = async (): Promise<AggregateResponse> => {

    // You must copy the AggregateResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/aggregate');
    url.searchParams.set('aggregation', 'median');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('city', 'Kelowna');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'score_fire');
    url.searchParams.set('province_abbreviation', 'bc');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: AggregateResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 1.0,
  "data": [
    {
      "aggregation": "median",
      "field": "score_fire",
      "value": "5"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 49
}

Mean across all of Canada:

API request
TypeScript code
const houski_data = async (): Promise<AggregateResponse> => {

    // You must copy the AggregateResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/aggregate');
    url.searchParams.set('aggregation', 'mean');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'score_fire');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: AggregateResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 1.0,
  "data": [
    {
      "aggregation": "mean",
      "field": "score_fire",
      "value": "5.071"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 25
}

Count of high-vulnerability properties (score 3 and below) in West Kelowna:

API request
TypeScript code
const houski_data = async (): Promise<AggregateResponse> => {

    // You must copy the AggregateResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/aggregate');
    url.searchParams.set('aggregation', 'count');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('city', 'West+Kelowna');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'score_fire');
    url.searchParams.set('province_abbreviation', 'bc');
    url.searchParams.set('score_fire_lte', '3');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: AggregateResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 1.0,
  "data": [
    {
      "aggregation": "count",
      "field": "score_fire",
      "value": "10819"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 47
}

One request, one number. No per-property charges to scan a city.

Building a neighbourhood comparison

For a "which Canadian city is safest" table, we would loop the same /aggregate call across every city of interest (Toronto, Montreal, Halifax, Vancouver, Victoria, Calgary, Edmonton, Kelowna, West Kelowna, Kamloops, Prince George, Fort McMurray, Yellowknife), then sort by median score and join in a high-vulnerability count per city. Swap province_abbreviation and city for each row. The underlying per-city call is:

API request
TypeScript code
const houski_data = async (): Promise<AggregateResponse> => {

    // You must copy the AggregateResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/aggregate');
    url.searchParams.set('aggregation', 'median');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('city', 'Kelowna');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'score_fire');
    url.searchParams.set('province_abbreviation', 'bc');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: AggregateResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": true,
  "cost_cents": 1.0,
  "data": [
    {
      "aggregation": "median",
      "field": "score_fire",
      "value": "5"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 49
}

Run this once a quarter and you have a defensible time series for any client conversation about how a market is shifting.

Sample neighbourhood comparison

Illustrative numbers, not live data - run the script for current values. The fire safety column is the 0 to 10 score with a plain read in brackets so the direction is obvious: (safe) is low wildfire vulnerability, (ok) is moderate, (risky) is the end to underwrite carefully. Higher is always safer, and numbers shift as the model updates and as new construction is added:

CityProvinceMedian fire safetyProperties scoring 3 or less
TorontoON9.0 (safe)low hundreds
MontrealQC9.0 (safe)low hundreds
VictoriaBC8.5 (safe)low hundreds
VancouverBC8.5 (safe)low hundreds
HalifaxNS8.5 (safe)low hundreds
CalgaryAB7.0 (ok)mid hundreds
EdmontonAB7.0 (ok)mid hundreds
KelownaBC5.0 (ok)mid thousands
KamloopsBC4.5 (risky)mid thousands
Prince GeorgeBC4.5 (risky)mid thousands
West KelownaBC4.0 (risky)high thousands
Fort McMurrayAB4.0 (risky)mid thousands
YellowknifeNT3.5 (risky)low thousands

Two things jump out. First, the dense eastern and coastal urban cores sit well above the western Interior and the boreal north, which lines up with both fuel type and ignition history. Second, West Kelowna scores noticeably below Kelowna proper, even though the two cities share a lake and a postal-code prefix. That gap is the exact kind of signal that a forward sortation area model erases.

Combining score_fire with construction details

Two properties with the same score_fire can have very different total exposure once you factor in the building. A 1972 wood-clad house with cedar shake roof on a 6 score_fire lot is in worse shape than a 2019 Hardie-clad house with a standing-seam metal roof on the same lot.

The Houski API exposes the structural fields you need to make that distinction. exterior_finish enumerates Vinyl, Wood, Stucco, Brick, Concrete, Metal, Aluminum, Steel, Plaster, and Log. roof_material covers Asphalt, Clay, Slate, Metal, Wood, Concrete, and Solar tile. construction_year is an integer.

A useful pattern: pull score_fire for the parcel together with the structural fields, then layer a construction multiplier on top in your own code. The underlying API call to pull a sample of detached homes in one city looks like this:

API request
Python code
from dataclasses import dataclass
from dataclasses_json import dataclass_json
import requests

params = {}
params['api_key'] = 'YOUR_API_KEY'
params['city'] = 'west+kelowna'
params['country_abbreviation'] = 'ca'
params['property_type_eq'] = 'House'
params['province_abbreviation'] = 'bc'
params['results_per_page'] = '5'
params['select'] = 'property_id,address,score_fire,exterior_finish,roof_material,construction_year'

response = requests.get('https://api.houski.ca/properties', params=params)

if response.status_code == 200:
    json_data = response.json()

    print(json_data)

    # You must copy the PropertiesResponse type declarations from the 
    # Houski API documentation to strongly type the response
    typed_response = PropertiesResponse.from_dict(json_data)

    # Log the response
    print(typed_response)
else:
    print(f'Failed to get data: {response}')
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 2.0999999046325684,
  "data": [
    {
      "address": "3639 Dunbarton Road",
      "construction_year": 1973,
      "exterior_finish": "Vinyl",
      "property_id": "100702224eb26b52",
      "roof_material": "Asphalt",
      "score_fire": 1
    },
    {
      "address": "3980 Milford Road",
      "construction_year": 1989,
      "exterior_finish": "Vinyl",
      "property_id": "1007645e6890e8a5",
      "roof_material": "Asphalt",
      "score_fire": 8
    },
    {
      "address": "3350 McIver Road",
      "construction_year": 1991,
      "exterior_finish": "Vinyl",
      "property_id": "10078333d2cae761",
      "roof_material": "Asphalt",
      "score_fire": 1
    },
    {
      "address": "3625 Gala View Drive",
      "construction_year": 2000,
      "exterior_finish": "Vinyl",
      "property_id": "100c04706893ceb9",
      "roof_material": "Asphalt",
      "score_fire": 5
    },
    {
      "address": "1515 Ponderosa Road",
      "construction_year": 1972,
      "exterior_finish": "Vinyl",
      "property_id": "1018bf215199d3a7",
      "roof_material": "Asphalt",
      "score_fire": 3
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 2170
  },
  "price_quote": false,
  "result_total": 10847,
  "time_ms": 33,
  "ui_info": {
    "city": "West Kelowna",
    "city_id": "d76a97e37967d5b1",
    "city_link": "ca/bc/west-kelowna",
    "city_slug": "west_kelowna",
    "country": "Canada",
    "country_abbreviation": "CA",
    "country_abbreviation_id": "9ace2b6431b7f1be",
    "country_abbreviation_link": "ca",
    "country_slug": "canada",
    "province": "British Columbia",
    "province_abbreviation": "BC",
    "province_abbreviation_id": "84b27e64bc119a2",
    "province_abbreviation_link": "ca/bc",
    "province_slug": "british_columbia"
  }
}

In your own code, apply a building-hardness multiplier (Brick and Concrete near 1.0, Vinyl around 0.7, Wood and Log near 0.55), a roof multiplier (Metal and Slate near 1.0, Asphalt around 0.75, Wood roofs near 0.4), and a construction-era factor that rewards post-2010 builds. Multiply score_fire by the three factors to get a combined safety score, then plot raw score_fire on the x-axis and combined safety on the y-axis with a dashed y=x reference line for "construction does not change anything".

Most of the dots fall well below the line because most construction choices on a high-vulnerability lot do not fully compensate. The dots that hug the line are the rare combinations of stucco or brick exterior, metal or clay roof, and post-2010 build year.

For an underwriter, that scatter plot is the difference between "decline this address" and "tier this address into preferred at a small surcharge".

How insurers can use this for tiered Canadian underwriting

Personal property carriers writing across Canada are under pressure on two sides. Reinsurance treaties keep tightening on wildfire exposure in the Interior, the Rockies, and the boreal belt. Brokers are being asked by clients to find them coverage at any price after a non-renewal letter. The middle ground is risk-based pricing that does not just blanket the entire forward sortation area.

A workable tier structure:

  • Preferred. score_fire 7.5 and above, exterior in (Brick, Concrete, Stucco, Metal), roof in (Metal, Slate, Clay, Concrete), construction_year 1990 and later. Standard rates, full limits.
  • Standard. score_fire 5 to 7.4 with any reasonable construction. Standard rates with an inspection clause.
  • Surcharged. score_fire 3 to 4.9 or older wood-frame on better lots. Surcharge plus a defensible-space attestation.
  • Restricted. score_fire below 3, especially when paired with wood roof or pre-1990 wood exterior. Bind only with a FireSmart certificate, lower limits, higher deductible.

Pull the inputs at quote time with one /properties call. The cost per quote is a fraction of the loss adjustment expense of one disputed claim from a fire that should have been priced into the policy.

Limitations to be honest about

The model has limits. Be straight with clients about them.

  • It updates on a schedule, not in real time. A fire perimeter from last August is in. A fire that started last week is not.
  • It does not see building code retrofits. If an owner replaced cedar shakes with standing-seam metal in 2023 and it has not been recorded in assessment data yet, the field still says Wood.
  • It does not reward enrolled FireSmart Canada properties or municipal wildfire mitigation programs. Both materially change real risk. Both are invisible to a model built on public, government, and crowdsourced data sources.
  • score_fire is a relative ranking, not an annual probability. A score of 8 is safer than a score of 4. It does not tell you that the score 4 property burns once every N years.

For most use cases (underwriting tiers, neighbourhood comparison, portfolio screening) those limits are acceptable as long as you state them. For evacuation planning at the structure-by-structure level, pair the field with on-the-ground inspection.

A full example: scoring a portfolio of 50 rentals

This is the workflow I get asked about most often by owners of small rental portfolios in fire-exposed regions. You have 30 to 80 doors spread across a few cities, maybe across provinces. Your insurer dropped one of them at renewal. You want to know which of the others are next.

The pattern is two API calls per property: a /search call to resolve a street address to a property_id, then a /properties call for the fields. We would loop through something like this for every row in the rent roll. The search step is:

API request
Python code
from dataclasses import dataclass
from dataclasses_json import dataclass_json
import requests

params = {}
params['api_key'] = 'YOUR_API_KEY'
params['max_results'] = '1'
params['query'] = '2575+Boucherie+Rd+West+Kelowna+BC'

response = requests.get('https://api.houski.ca/search', params=params)

if response.status_code == 200:
    json_data = response.json()

    print(json_data)

    # You must copy the SearchResponse type declarations from the 
    # Houski API documentation to strongly type the response
    typed_response = SearchResponse.from_dict(json_data)

    # Log the response
    print(typed_response)
else:
    print(f'Failed to get data: {response}')
API response
JSON
{
  "cache_hit": true,
  "cost_cents": 0.019999999552965164,
  "data": [
    {
      "address": "2775 Boucherie Road",
      "property_id": "38bea0bd31929180"
    }
  ],
  "error": "",
  "match_meta": [
    {
      "match_value": 0.9166666865348816,
      "property_id": "38bea0bd31929180"
    }
  ],
  "price_quote": false,
  "result_total": 1,
  "time_ms": 1174
}

And the structural lookup against the returned property_id is:

API request
Python code
from dataclasses import dataclass
from dataclasses_json import dataclass_json
import requests

params = {}
params['api_key'] = 'YOUR_API_KEY'
params['property_id_eq'] = 'bd9c6fb24c31c772'
params['select'] = 'score_fire,exterior_finish,roof_material,construction_year'

response = requests.get('https://api.houski.ca/properties', params=params)

if response.status_code == 200:
    json_data = response.json()

    print(json_data)

    # You must copy the PropertiesResponse type declarations from the 
    # Houski API documentation to strongly type the response
    typed_response = PropertiesResponse.from_dict(json_data)

    # Log the response
    print(typed_response)
else:
    print(f'Failed to get data: {response}')
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 0.41999998688697815,
  "data": [
    {
      "address": "302 610 17 Avenue SW",
      "construction_year": 1979,
      "exterior_finish": "Brick",
      "property_id": "bd9c6fb24c31c772",
      "roof_material": "Asphalt",
      "score_fire": 9
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 1,
  "time_ms": 47,
  "ui_info": {
    "address": "302 610 17 Avenue SW",
    "address_link": "ca/ab/calgary/beltline/302-610-17-avenue-sw",
    "address_slug": "302-610-17-avenue-sw",
    "city": "Calgary",
    "city_id": "6ec95b53075d062c",
    "city_link": "ca/ab/calgary",
    "city_slug": "calgary",
    "community": "Beltline",
    "community_id": "ecc51da246c7dd4a",
    "community_link": "ca/ab/calgary/beltline",
    "community_slug": "beltline",
    "country": "Canada",
    "country_abbreviation": "CA",
    "country_abbreviation_id": "9ace2b6431b7f1be",
    "country_abbreviation_link": "ca",
    "country_slug": "canada",
    "parent_address": "610 17 Avenue SW",
    "parent_property_id": "52a7d622eafe5319",
    "property_id": "bd9c6fb24c31c772",
    "province": "Alberta",
    "province_abbreviation": "AB",
    "province_abbreviation_id": "aae1f05a0f89d2c7",
    "province_abbreviation_link": "ca/ab",
    "province_slug": "alberta"
  }
}

Bucket the resulting score_fire values into risk tiers (restricted at 3 and below, surcharged at 3 to 4.9, standard at 5 to 7.4, preferred at 7.5 and up), then sort ascending and write the CSV. The first row is the property your insurer is most likely to drop next. Walk that one first. Schedule a FireSmart assessment, photograph the defensible space, swap the roof if the budget is there. Move down the list.

Where the exposure concentrates across Canada

Most of the wildfire conversation focuses on a handful of headline regions, but the model assigns a score to every property in the country. Regions worth a closer look:

  • The British Columbia Interior and the Okanagan. The interface is dense and the ignition history is long. Median fire safety in West Kelowna, Kamloops, and Prince George runs well below the coastal cities.
  • The Alberta Rockies and the northern Prairies. Jasper in 2024 and Fort McMurray in 2016 both showed how fast an interface community can go. Worth a tier conversation for any policy written there.
  • The boreal belt across northern Ontario, Quebec, and the territories. Yellowknife and the surrounding Northwest Territories communities carry real interface exposure, and the 2023 season made that plain.
  • The Sea-to-Sky corridor and Vancouver Island fringes. Squamish, Sooke, Pemberton, and Whistler all pick up on slope, fuel, and proximity to wilderness even though they sit near the coast.

For each of these, the same /aggregate call with a different province and city value gives you the local median. Pair it with a quick scan of score_fire_lte=3 properties to find the long tail of high-vulnerability addresses.

What to build next

If you got this far, you probably want to do one of three things: pull the score for a portfolio you already have, score a city you are about to enter, or wire it into a quoting flow. All three start the same way, with one /properties call or one /aggregate call. The fields are documented, the filters compose cleanly, and the per-request cost is small enough that scanning a whole Canadian city for a one-time analysis is a coffee, not a contract.

Get started at /api-documentation/quick-start. Pricing starts at $99 a month, and you can have a working cross-country comparison in your terminal in under five minutes.