Methodology

How NestScore works.

Every NestScore is built from fourteen things we measure about a place and weighted by what you tell us matters. Read on for the plain-English version, complete with a mathematical breakdown if you want it.

The big idea

Three steps, one number.

A NestScore is a single 0–100 number that summarizes how well a place fits your lifestyle. Here's the whole pipeline, end to end.

01 Score every factor

Each factor gets its own 0–100.

For each listing, we compute fourteen separate sub-scores using public data (TTC + GO, Toronto Open Data, OpenStreetMap) plus the listing's own details. Each listing is on the same 0–100 scale so they can be compared.

02 Weight by your priorities

Multiply each sub-score by what you care about.

By default, every factor has a weight that reflects what most renters tell us matters. You can override that by boosting transit, lowering restaurants, ignoring a school nobody in your household needs, and much more. Each factor is an independent priority — turn it up or down and the map re-ranks.

03 Average them out

A weighted average gives the NestScore.

The fourteen weighted sub-scores are averaged into a single 0–100 NestScore. If a factor genuinely can't be computed (e.g., no nearby price comps), it's left out rather than counted as zero so the composite stays meaningful.

Reading the score

What does the number actually mean?

A NestScore is a peronsal fit, not a quality rating. A 95 doesn't mean this is the nicest apartment in Toronto, it means "for the priorities you set, almost everything lines up." Here are the bands.

92
Exceptional = 90–100
Everything's close. You'll wonder why you ever lived elsewhere.
90+
84
Strong = 80–89
A great neighbourhood with maybe one or two tradeoffs.
80s
73
Decent = 70–79
Good base, but worth knowing what you're giving up.
70s
63
Compromises = 60–69
The price might be right, but some things are genuinely inconvenient.
60s
48
Weak fit = <60
Worth looking into the details breakdown before booking a viewing.
<60
What we measure

Fourteen things. One score per place.

Each factor has its own logic: proximity, density, comparison to peers, or a yes/no flag. Click Show the math on any card to see the formula and constants we actually use.

Transit
Default 20% weight

How well-connected the listing is, scored two ways: how easy it is to walk to a stop, and how fast you can actually get places from there.

Walk-to-stop (60% of the score). Every TTC and GO stop within a real 1.2 km walking distance (along the street network, not as the crow flies) contributes to a pool, weighted by service quality — a subway station counts most, then streetcars, GO rail, frequent buses (10-min peak headway), and regular buses last. Closer wins; each extra ~350 m of walking roughly halves a stop's contribution.

Destination reachability (40% of the score). From each address we precompute the morning-peak transit time to every TTC subway station and every in-Toronto GO rail station — 91 places in total — using a real trip planner over TTC and GO schedules. The score uses your five fastest destinations. So a downtown listing isn't punished for being far from Pioneer Village or Pearson, and a North York listing still gets credit for the destinations it can reach quickly.

Feeds TTC GTFS · GO Transit GTFS · OpenStreetMap (walking network) · OpenTripPlanner (transit routing)
Show the math

walk-to-stop = 100 × (1 − exp(−pool / 5))

where pool = Σ mode_w × exp(−2.0 × d_km) over stops within 1.2 km of walking. Distance comes from OSRM walking-network routing, converted to a km-equivalent at 5 km/h. The soft-cap divisor of 5 means a typical downtown listing with one nearby subway + a streetcar (pool ≈ 5) lands near 63, and two subway lines plus a streetcar (pool ≈ 10) approaches 86.

Mode weights:

  • subway = 3.0
  • tram / streetcar / LRT = 1.5
  • GO rail = 0.8
  • frequent bus (≤10 min peak) = 0.5
  • regular bus = 0.2

destinations = 100 × mean(exp(−0.02 × t_min)) over the five fastest of 91 destinations. Decay calibration: t = 5 min contributes ~0.90, 20 min ~0.67, 35 min ~0.50, 60 min ~0.30.

Transit = 0.6 × walk-to-stop + 0.4 × destinations

If transit-time data isn't available for an address (outside our Toronto grid), the score falls back to walk-to-stop only — no penalty for the missing term.

Grocery
Default 11% weight

Whether you can shop your whole list without driving.

We sum up nearby supermarkets, weighted by both how close they are and what kind of store they are. A full-service supermarket (e.g., Loblaws, Metro, Sobeys) counts the most; a discount grocer (No Frills, FreshCo, Food Basics) is most of the way there; an independent grocer contributes less. Multiple stores stack but with diminishing returns, so your second nearby Loblaws boosts your NestScore less than your first.

Feeds OpenStreetMap (via Overpass API)
Show the math

Grocery = min(100, sqrt(Σ tier × exp(−2.5 × d_km)) × 40)

Tier weights:

  • full-service supermarket = 1.0
  • discount supermarket = 0.6
  • independent grocer = 0.3

Stores beyond 1.5 km are ignored. Calibration: a single store at 300 m ≈ 35; two at 300 m ≈ 50.

Medical
Default 7% weight

Pharmacies and walk-in clinics within walking range.

Same mathematical shape as Grocery, but for pharmacies and walk-in clinics. Pharmacies count more than clinics, because most people use them more often (prescriptions, OTC meds, allergy season). Multiple options stack with diminishing returns; anything past 1.5 km doesn't count.

Feeds OpenStreetMap (pharmacy / clinic / doctors tags via Overpass)
Show the math

pool = Σ tier × exp(−2.5 × d_km) over locations within 1.5 km

Medical = 100 × (1 − exp(−pool / 4))

Tier weights:

  • pharmacy = 1.0
  • walk-in clinic / doctor's office = 0.7

Locations beyond 1.5 km are ignored. Same soft-cap shape as Transit: a pool of 4 lands near 63, a pool of 8 near 86. The smaller saturation scale (4 vs Transit's 10) reflects that pharmacies are rarer than transit stops, so even a single nearby pharmacy moves the score meaningfully.

Restaurants
Default 7% weight

Whether the streets feel alive.

This one's about density — how many places to eat, drink, and grab a coffee are within walking distance, because that's what makes a neighbourhood feel like one. We pool every restaurant, café, bar, and fast-food spot within 1 km, weighted by what kind of place it is: a sit-down restaurant counts the most, a café somewhere in between, a McDonald's the least. Closer wins — each extra ~230 m of distance roughly halves a place's contribution. The total feeds into a saturating curve that approaches 100, so going from 0 to 10 nearby places matters way more than going from 40 to 50.

Feeds OpenStreetMap (restaurant / cafe / bar / fast_food tags)
Show the math

pool = Σ tier × exp(−3.0 × d_km) over places within 1 km

Restaurants = 100 × (1 − exp(−pool / 22))

Tier weights:

  • restaurant (sit-down) = 1.0
  • café = 0.6
  • bar = 0.4
  • fast food = 0.3

Same soft-cap shape as Transit and Medical — pool of 22 lands near 63, pool of 44 near 86. Tiering keeps every downtown block from tying at 100 (fast-food chains used to be a third of all OSM hits in Toronto, and the untiered count buried real signal).

Bike
Default 4% weight

Cycling infrastructure: stations + lanes.

Two halves, each worth up to 50 points. The first half rewards Bike Share Toronto stations nearby — close ones (≤500 m) count three times as much as further ones (500 m – 1 km). The second half rewards protected lane density, or how many sample points along Toronto's official cycling network are within 500 m of your new home. We sample lanes every ~200 m, so a long protected stretch nearby will accumulate a lot of points.

Feeds Toronto Bike Share station feed · City of Toronto cycling network GeoJSON
Show the math

share_score = min(50, sqrt(3 × n_close + 1 × n_far) × 14)
(close = ≤500 m; far = 500 m – 1 km)

lane_score = min(50, sqrt(n_lane_samples_within_500m) × 8)

Bike = share_score + lane_score

Parks
Default 11% weight

Green space within a 10-minute walk. The big ones count more!

We measure the distance to each park's edge, not its centre. That matters: standing across the street from High Park, you're roughly 600 metres from its centroid but effectively at the front gate. Bigger parks also get a bonus — a 50 hectare ravine system contributes 3× more than a small playground at the same distance, because we know the experience is meaningfully different. Multiple parks stack with diminishing returns; anything past an 800-metre walk to the edge stops counting.

Feeds Toronto Open Data Green Spaces | OpenStreetMap parks
Show the math

For each park, treat it as a disc with radius_km = sqrt(hectares × 10,000 / π) / 1000 and let edge_d = max(0, centroid_d − radius_km).

Parks = min(100, sqrt(Σ exp(−2 × edge_d) × size_mult) × 30)

Size multiplier:

  • ≥ 50 hectares (High Park / Tommy Thompson scale) = 3.0
  • 5 – 50 hectares (neighbourhood park) = 1.8
  • < 5 hectares (small park / playground) = 1.0

Parks with edge_d > 0.8 km are ignored.

Schools
Default 1% weight

Nearest elementary plus nearest secondary: best-of-each, no stacking.

For schools we use a best-of-each rule: only the single nearest elementary school (worth up to 60 points) and the single nearest secondary school (worth up to 40 points) contribute. We don't reward the listing for being near five elementary schools since you only need one. The closer the school, the more points; anything past 1.5 kilometres doesn't count.

Feeds Ontario Ministry of Education school list
Show the math

elem_score = 60 × exp(−1 × d_nearest_elem) (or 0 if none within 1.5 km)

sec_score = 40 × exp(−1 × d_nearest_sec) (or 0 if none within 1.5 km)

Schools = elem_score + sec_score

Calibration: elem 100 m + sec 300 m ≈ 71; elem 500 m + no nearby sec ≈ 50.

Square footage
Default 7% weight

Spaciousness compared to other Toronto units of the same bedroom count.

We compare the unit's reported sqft to a typical citywide range for that bedroom count. A 1-bed at the top of the typical range scores around 90; a 1-bed near the bottom scores around 20. If the listing doesn't report sqft, we estimate it from the median sqft of comparable listings in our database, so the score is still meaningful if not precise.

Feeds Listing's own sqft + bedrooms fields (with peer-median fallback)
Show the math

Sqft = clamp(0, 100, 20 + (sqft − low) / (high − low) × 70)

So at the bottom of the range you get 20, at the top you get 90, and we extrapolate beyond. Bedroom-count benchmarks (square feet, low – high):

  • studio = 300 – 550
  • 1 bed = 450 – 750
  • 1 bed + den = 550 – 850
  • 2 bed = 700 – 1,100
  • 2 bed + den = 850 – 1,300
  • 3 bed = 1,000 – 1,600

If sqft is unknown, we substitute the median sqft of listings with the same bedroom count.

Pool
Default 3% weight

Building has a pool: yes or no?

Binary. If we know the building has a pool, the score is 100; if we know it doesn't, the score is 0. If we genuinely can't tell, the pool is left out of the composite rather than counted as zero. We prefer the structured amenity flag when pulling listings and only fall back to scanning the listing description when we have to. Drop this from your own NestScore if it's not important to you.

Feeds Listing's has_pool flag → text in description (with negation guard)
Show the math

Detection priority:

  • Explicit has_pool flag from the listing — used as-is.
  • Legacy pool field — used as-is if set.
  • Description regex \bpool\b with two guards: a negation window ("no pool", "without a pool", "lacks a pool" → False) and a false-positive filter ("carpool", "pool table", "pool noodle", "pool party", "pool hall" → ignored).

Score: True → 100, False → 0, Unknown → excluded from composite.

Balcony
Default 3% weight

Unit has a balcony: yes or no?

Same shape as Pool. If we know there's a balcony, 100; if we know there isn't, 0; if we can't tell, it's left out. Structured flag first, description text second. The negation guard catches things like "no balcony".

Feeds Listing's has_balcony flag → text in description
Show the math

Detection priority:

  • Explicit has_balcony flag — used as-is.
  • Legacy balcony field — used as-is.
  • Description regex \bbalcon(?:y|ies)\b with negation window ("no balcony", "without a balcony" → False).

Score: True → 100, False → 0, Unknown → excluded from composite.

Quiet
Default 5% weight

An inverse methodology means higher score equals quieter neighbourhood.

This is the only factor where we work backwards. We start at 100 and subtract a noise-exposure penalty based on nearby highway corridors (worst), GO and other rail lines, and above-ground TTC subway stops. Noise drops off very quickly, so we use a steep distance decay. A busy road 500 metres away barely registers, but a building right on the Gardiner takes a serious hit. Anything past 800 metres doesn't contribute.

Feeds Toronto highway corridors · GO rail · TTC subway lines (curated)
Show the math

exposure = Σ severity × exp(−5 × d_km) over noise sources within 800 m

Quiet = max(0, 100 − min(100, sqrt(exposure) × 30))

Severity by source:

  • highway corridor (Gardiner, 401, DVP) = 1.0
  • GO / commuter rail = 0.7
  • TTC subway (partly or fully above ground) = 0.4

Calibration: quiet residential ≈ 90–95; near the Gardiner at 500 m ≈ 60–70; immediately on the 401 ≈ 20–30.

Price value
Default 10% weight

Rent compared to nearby units of the same size.

Price-value answers a single question: am I overpaying compared to similar nearby units? We find every other listing within 2 kilometres that has the same bedroom count, take the median rent, and compare. 30% below median tops out at 100; at the median scores 50; 30% above the median drops to 0. We need at least 3 nearby comparables, so if we don't have them in the listings database, this score is excluded rather than guessed. As more listings join the database, more areas become scoreable.

Feeds All other listings in our database (same bedroom count, within 2 km)
Show the math

Let median = median price of same-bedroom listings within 2 km, where there are at least 3 comps.

Price value = clamp(0, 100, 50 − (price / median − 1) × 167)

The 167 multiplier means a ±30% swing from the median maps to the full 0–100 range. With fewer than 3 comparables, this score is left out of the composite.

Rent control
Default 10% weight

Whether the unit falls under Ontario's rent-increase cap.

Ontario exempts buildings first occupied on or after 15 November 2018 from rent control, so whether a unit is rent-controlled depends almost entirely on when its building was finished. If the listing tells us the build year, we use it directly. If it doesn't, we match the listing to the nearest building in our database of Toronto building records and read its rent-control flag from there. If we can't get either, the score is excluded rather than being guessed at.

Feeds Listing's year_built → proprietary database of Toronto buildings
Show the math

Detection priority:

  • If year_built is set: 100 if year_built < 2018, else 0.
  • Otherwise: find the nearest building in Toronto_Buildings within 100 m and use its rent-control flag.
  • If neither is available: excluded from composite.

We use the year 2018 as the cutoff (the formal date is 15 November 2018, but year-level data is what's reliably available).

Traffic
Default 1% weight

Vehicle volume, speed at the curb, and a toggle for which way you want it.

Most renters want calm streets. Some actively want a busy arterial for quick access in their cars. This factor has a direction toggle next to its slider: Less traffic (the default — calm = good) or More traffic (busy = good). The underlying number doesn't change; we just flip the sign at the point your composite is calculated. We use Toronto's midblock vehicle counts, which are survey points where the city has measured average daily volume (AADT) and the 85th-percentile speed of vehicles passing by. For a listing, we look at every survey point within 200 metres and combine them with a steep distance decay (a count 50 metres away counts way more than one 180 metres away). Volume dominates the severity blend; speed nudges it (a fast residential street feels worse than a slow one with the same volume). Coverage isn't perfect since the city only counts streets it has surveyed, and small residential laneways often aren't in the dataset. If there's no survey point within 200 metres, we leave the score blank rather than guess, and the factor drops out of that listing's composite.

Feeds Toronto Open Data — Midblock Vehicle Speed, Volume and Classification Counts (most recent summary, ~14k surveyed segments)
Show the math

Let v = min(1, AADT / 30000) and s = min(1, speed_85th / 80). Speed is null on volume-only counts; in that case severity = v. Otherwise:

severity = 0.7 × v + 0.3 × s

exposure = Σ severity × exp(−8 × d_km) over surveyed points within 200 m

Calm streets = max(0, 100 − exposure × 45)

If you toggle direction to More, the composite uses 100 − Calm streets. The stored value is always the calm-streets number, so toggling doesn't trigger a re-score.

Calibration: residential side streets land near 80–95, collectors 45–60, arterials 20–35, on a major highway 0–10.

How weights work

We set the defaults. You make them yours.

Every NestScore is a weighted average. Below is the default mix we use when a renter hasn't told us anything yet, and how that mix changes when you start adjusting sliders on the map.

Location & access — 61%
Transit
20%
Grocery
11%
Medical
7%
Restaurants
7%
Bike
4%
Parks
11%
Schools
1%
Unit quality — 13%
Square footage
7%
Pool
3%
Balcony
3%
Value & livability — 26%
Quiet
5%
Price value
10%
Rent control
10%
Traffic
1%

Tuning the weights yourself

The default mix above is what most renters tell us matters. None of it is right for you. The map lets you change the weights and the scores recalculate live.

Free
7 lifestyle presets.

Pick a curated preset — Balanced, Transit Commuter, Cyclist, Family with kids, Quiet & calm, Foodie, or Value Hunter — and the map re-ranks instantly. Sliders are visible so you can see exactly how each preset distributes its weight, but they're read-only. Forever free; your last-used preset sticks across visits via your browser.

Distance & coverage

A few things to know about how we measure.

The honest small print, in two paragraphs.

Distance follows the street network — not the crow.

For factors where what matters is real walkability — transit, grocery, medical, restaurants, bike-share, parks, and schools — distance is measured along the actual walking network using OSRM over OpenStreetMap data. A subway stop 600 m as the crow flies but cut off by the Don Valley correctly registers as a longer walk, not a shorter one. For Transit specifically, we also precompute real morning-peak transit times via OpenTripPlanner so the score reflects how long your commute would actually be. A few factors still use straight-line distance because that's the right measure for them: noise (sound doesn't follow streets), price-value comps (market geography), traffic exposure (line-of-sight), and rent-control building matching (snapping to the nearest address).

Toronto only — and missing data is excluded, not zeroed.

Coverage today is Toronto and immediate neighbours; Vancouver, Montréal, and Calgary are on the roadmap. When a sub-score genuinely can't be computed for a listing — fewer than 3 nearby price comps, no year_built, no description to scan for amenities — we leave that factor out of the composite rather than count it as a zero. The remaining factors are reweighted to still sum to 100%, so a missing pool flag doesn't tank a score it has no business tanking.

Data sources

We didn't make any of this data ourselves.

Every score in NestScore is built on public, third-party data. Here's where each piece comes from.

Dataset Feeds Source
TTC stops & schedulesTransitTTC GTFS feed
GO Transit stops & schedulesTransitMetrolinx GTFS feed
Grocery storesGroceryOpenStreetMap (via Overpass API)
Pharmacies, clinics, doctorsMedicalOpenStreetMap (via Overpass API)
Restaurants, cafés, barsRestaurantsOpenStreetMap (via Overpass API)
Bike Share Toronto stationsBikeCity of Toronto live JSON feed
Cycling network (lanes)BikeCity of Toronto Open Data
Parks & green spaceParksToronto Open Data Green Spaces + OpenStreetMap
Schools (elementary & secondary)SchoolsOntario Ministry of Education
Highway corridors & rail linesQuietCity of Toronto road network + curated geometry
Toronto building recordsRent control (geo-match)Toronto Open Data
Midblock vehicle volume & speed countsTrafficToronto Open Data — SVC most-recent summary
Listings (rent, sqft, beds, year)Price value, sqft, rent control, pool, balconyPublic rental listings

The point of NestScore isn't to generate data. It's to combine the right data, intelligently.