Summer highs, winter lows, rain and snow: climate normals on every property

Photo of Alex Wilkinson
Alex Wilkinson
CEO of Houski
2026-10-19

Ask a contractor, an insurer or a relocation adviser what they need to know about a place, and the weather comes up fast. How cold does it get in January. How hot is July. How much rain falls in a year. How much snow has to be shovelled, cleared or held up by a roof. These are long-run facts about a location, and they change what a property costs to heat, cool, insure and maintain.

Houski carries four climate fields on the property row, so the climate comes back in the same request as the bedrooms, the roof and the value estimate:

  • climate_temperature_high_warmest_month_c: the average daily high of the warmest month, in degrees Celsius
  • climate_temperature_low_coldest_month_c: the average daily low of the coldest month, in degrees Celsius
  • climate_precipitation_annual_mm: the rain and melted snow that fall in an average year, in millimetres
  • climate_snowfall_annual_cm: the depth of new snow that falls in an average year, in centimetres

Each one is an average over the thirty years from 1991 to 2020. They describe the climate a property sits in, not the weather of any one year.

Pulling the climate for a city's properties

The block below is a live call against the real API. The request and the response are generated every time this page renders, so they always reflect the current data:

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('city', 'calgary');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('property_type_eq', 'House');
    url.searchParams.set('province_abbreviation', 'ab');
    url.searchParams.set('results_per_page', '5');
    url.searchParams.set('select', 'address,community,climate_temperature_high_warmest_month_c,climate_temperature_low_coldest_month_c,climate_precipitation_annual_mm,climate_snowfall_annual_cm');

    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": true,
  "cost_cents": 2.1499999,
  "data": [
    {
      "address": "54 Rowmont Link NW",
      "climate_precipitation_annual_mm": 416,
      "climate_snowfall_annual_cm": 132,
      "climate_temperature_high_warmest_month_c": 23.5,
      "climate_temperature_low_coldest_month_c": -12.8,
      "community": "Haskayne",
      "property_id": "1055f97323e53f25"
    },
    {
      "address": "40 Rowmont Common NW",
      "climate_precipitation_annual_mm": 416,
      "climate_snowfall_annual_cm": 132,
      "climate_temperature_high_warmest_month_c": 23.5,
      "climate_temperature_low_coldest_month_c": -12.8,
      "community": "Haskayne",
      "property_id": "11d2132629e36a28"
    },
    {
      "address": "16 Rowmont Common NW",
      "climate_precipitation_annual_mm": 416,
      "climate_snowfall_annual_cm": 132,
      "climate_temperature_high_warmest_month_c": 23.5,
      "climate_temperature_low_coldest_month_c": -12.8,
      "community": "Haskayne",
      "property_id": "11f8d3671079fb5e"
    },
    {
      "address": "435 Crimson Ridge Place NW",
      "climate_precipitation_annual_mm": 412,
      "climate_snowfall_annual_cm": 132,
      "climate_temperature_high_warmest_month_c": 23.6,
      "climate_temperature_low_coldest_month_c": -12.9,
      "community": "Haskayne",
      "property_id": "1209fe3057284c96"
    },
    {
      "address": "288 Crimson Ridge Place NW",
      "climate_precipitation_annual_mm": 412,
      "climate_snowfall_annual_cm": 132,
      "climate_temperature_high_warmest_month_c": 23.6,
      "climate_temperature_low_coldest_month_c": -12.9,
      "community": "Haskayne",
      "property_id": "1277c8e032dd2f50"
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 64897
  },
  "price_quote": false,
  "result_total": 324484,
  "time_ms": 41,
  "ui_info": {
    "city": "Calgary",
    "city_id": "6ec95b53075d062c",
    "city_link": "ca/ab/calgary",
    "city_slug": "calgary",
    "country": "Canada",
    "country_abbreviation": "CA",
    "country_abbreviation_id": "9ace2b6431b7f1be",
    "country_abbreviation_link": "ca",
    "country_slug": "canada",
    "province": "Alberta",
    "province_abbreviation": "AB",
    "province_abbreviation_id": "aae1f05a0f89d2c7",
    "province_abbreviation_link": "ca/ab",
    "province_slug": "alberta"
  }
}

Select only the climate fields you use. Every field you do not request is a field you do not pay for.

Comparing places with one aggregate call

The aggregate endpoint returns one number for a whole market. Median annual snowfall across Calgary:

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', 'calgary');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'climate_snowfall_annual_cm');
    url.searchParams.set('province_abbreviation', 'ab');

    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": "climate_snowfall_annual_cm",
      "value": "141"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 14
}

And the median coldest month low across Norway:

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('country_abbreviation', 'no');
    url.searchParams.set('field', 'climate_temperature_low_coldest_month_c');

    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": "climate_temperature_low_coldest_month_c",
      "value": "-3.900"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 57
}

Run the same call across the markets you serve and you have a climate profile per city or country, without downloading a single grid.

How fine the climate is

In Canada and the United States, each value belongs to a grid square about two kilometres across, and every property in the square shares it. The two countries are measured the same way, so a Calgary value and a Denver value compare directly across the border. That is different from the score_ fields, which are ranked within each country.

In England, Wales and Scotland the values come from squares about 12 kilometres across. In every other country Houski covers, they come from cells about 4.6 kilometres across or smaller. Wherever a property sits, it takes its climate from its own point, whichever source brought the property itself in.

Snowfall is the exception. It exists for Canada and the United States only. There the estimate starts from each month's average temperature and precipitation in the grid square, which give the share of that month's precipitation that falls as snow, and the year's total is then adjusted to what the nearest weather stations measured over the same thirty years. No other country has a snowfall figure, so the field is empty there rather than guessed.

What people build with it

Heat pump and furnace targeting. A cold-climate heat pump is a different product from a standard one. Filtering on climate_temperature_low_coldest_month_c separates the homes that need the cold-climate unit from the ones that do not, before a contractor quotes anything. Pair it with heating_type_first and construction_year and you have a prospect list sorted by the equipment each home actually needs.

Cooling demand. The warmest month high says where summers run hot enough that a home without air conditioning is a candidate for a retrofit, and where a heat pump that cools as well as heats is the easier sale.

Roof and snow load. Annual snowfall is a first screen for roofing contractors, snow clearing services, and anyone pricing the wear a roof takes over a winter. It is a long-run average, so it says nothing about last February, but it ranks places reliably.

Insurance and maintenance pricing. Freeze-thaw cycles, ice dams, burst pipes and water damage all follow the climate. The four fields give an underwriting model or a home warranty price a climate input on the same row as the building's age and materials.

Relocation and home search. A buyer moving across a country, or between countries, wants to know what winter feels like before they arrive. Four numbers on a listing page answer that better than a paragraph.

What the fields are not

  • They are normals, not forecasts. A thirty-year average says what is typical, not what next winter will bring.
  • They describe the area, not the lot. A property on a sheltered slope and one on an exposed ridge in the same grid square share a value.
  • They are not hazard scores. Flood, fire, hurricane and tornado exposure live in their own score_ fields, oriented so higher is safer.

Getting started

  1. Sign up for API access
  2. Pull the four fields for one city with the query above
  3. Compare your markets with one aggregate call per city or country
  4. Add a climate filter to the lists you already build, such as climate_temperature_low_coldest_month_c_lte=-20 for the coldest winters
  5. Check the fields reference for the full description of each field

Most fields cost a tenth of a cent per field per property, each aggregation value costs one cent, and there is a 99 dollar monthly minimum. Details on the pricing page.


The climate a property sits in shapes what it costs to own. It now comes back on the same row as everything else. Explore the API or browse the datasets.