Realtor.ca Listings & Price Changes Scraper avatar

Realtor.ca Listings & Price Changes Scraper

Pricing

from $5.00 / 1,000 listing scrapeds

Go to Apify Store
Realtor.ca Listings & Price Changes Scraper

Realtor.ca Listings & Price Changes Scraper

Scrape public Realtor.ca Canadian MLS listings by city, map bounds, listing URL or MLS number, with price, beds, baths, agents, photos and price-change signals. Optional detail enrichment and a cross-run price monitor are included.

Pricing

from $5.00 / 1,000 listing scrapeds

Rating

0.0

(0)

Developer

Khadin Akbar

Khadin Akbar

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

a month ago

Last modified

Share

What is Realtor.ca Listings & Price Changes Scraper?

Realtor.ca Listings & Price Changes Scraper returns public Canadian MLS listings from Realtor.ca as a dataset, one row per listing, searched by city, map area, Realtor.ca URL or MLS number. Each row has the MLS number, CAD list price, structured address, coordinates, bedrooms, bathrooms, building type, photo URLs, listing agent, brokerage and price-change fields. Optional detail enrichment adds public remarks and price history, and monitor mode compares prices across scheduled runs. Investors, agents, proptech teams and AI agents use it to track Canadian inventory and price drops.

Why property teams use this Realtor.ca scraper

  • Four ways to search. A city name, an exact mapBoundingBox, Realtor.ca startUrls, or a list of mlsNumbers.
  • Clean numbers. price is a number in CAD next to the display string, and lat/lon place each listing on a map.
  • Listing contact on the row. agentName, agentPhone and brokerageName come with every listing.
  • Price-drop tracking you can trust. monitorMode stores a snapshot in your own key-value store and fills previousPrice, newPrice, priceChangeDetected and monitorDiff on the next run.
  • Filters that match the site. transactionType, propertyGroup, minPrice, maxPrice, minBeds, minBaths, keywords and sortBy.

Best fit for this Actor

  • Best fit for Canadian residential and commercial listings on Realtor.ca, for sale or for rent.
  • Use city for a quick market pull and mapBoundingBox for a precise neighbourhood.
  • Use mlsNumbers with enrichDetails when you already have a shortlist and want remarks and history.
  • For US markets, use Zillow Search Scraper with the same workflow.
  • To price a rental against nearby comparables, then pass the address to Rental Price Analyzer — Rentometer Alternative.

What people and AI agents ask this Actor to do

List the newest condos for sale in downtown Toronto under 700,000 dollars. Tell me every day which Vancouver listings dropped their price. Get the details and remarks for these three MLS numbers.

RequestInput to send
City market pull{"city": "Vancouver", "maxPrice": 900000, "minBeds": 2, "maxResults": 100}
Exact neighbourhood{"mapBoundingBox": {"LatitudeMin": 43.63, "LatitudeMax": 43.68, "LongitudeMin": -79.43, "LongitudeMax": -79.35}}
Rentals in a city{"city": "Calgary", "transactionType": "for-rent"}
MLS shortlist with remarks{"mlsNumbers": ["C13846184"], "enrichDetails": true}
Daily price-drop alert{"city": "Toronto", "monitorMode": true, "onlyPriceChanges": true} on a daily schedule

Example workflow: from a neighbourhood map to a price-drop list

A small investment fund starts with a map box around Toronto's Annex and University neighbourhoods and maxPrice set to 1,100,000. The first run returns every matching listing with price, bedrooms, bathrooms, buildingType and listingUrl, and with monitorMode on it saves a price snapshot. They schedule the same input daily with onlyPriceChanges on, so each morning's dataset holds only listings whose price moved, with previousPrice and newPrice. They compare those against their target yield, export the shortlist, and feed the MLS numbers back with enrichDetails for remarks before calling the listing agents.

Input

Provide one of city, mapBoundingBox, startUrls or mlsNumbers.

{
"mapBoundingBox": {
"LatitudeMin": 43.63,
"LatitudeMax": 43.68,
"LongitudeMin": -79.43,
"LongitudeMax": -79.35,
"ZoomLevel": 13
},
"transactionType": "for-sale",
"propertyGroup": "residential",
"sortBy": "date-desc",
"maxResults": 25,
"enrichDetails": false,
"monitorMode": false
}
FieldTypeWhat it controls
citystringCanadian city name, for example Toronto or Calgary
mapBoundingBoxobjectLatitudeMin, LatitudeMax, LongitudeMin, LongitudeMax, optional ZoomLevel
startUrlsarrayRealtor.ca map search URLs or listing URLs
mlsNumbersarrayMLS reference numbers for direct lookups
transactionTypestringfor-sale or for-rent. Default for-sale
propertyGroupstringresidential or commercial. Default residential
sortBystringdate-desc, date-asc, price-asc, price-desc
minPrice, maxPriceintegerPrice range in CAD
minBeds, minBathsintegerMinimum bedrooms and bathrooms
keywordsstringAddress fragment, building name or other keyword
maxResultsintegerCap on dataset rows. Default 5 for a quick sample
enrichDetailsbooleanAdd remarks, extra photos and public price history
monitorMode, onlyPriceChanges, monitorStoreNamemixedCross-run price tracking settings
proxyConfigurationobjectApify Proxy; Residential Canada by default

Output

FieldWhat it contains
mlsNumber, propertyId, listingUrlListing identity and public URL
price, priceDisplayList price in CAD as a number and as shown
addressstreet, city, province, postalCode, text
lat, lonCoordinates
bedrooms, bathrooms, propertyType, buildingType, sqftProperty details when published
photoUrls, photoCountListing photos
agentName, agentPhone, brokerageNameListing agent and brokerage
transactionType, status, listedDateListing state as Realtor.ca reports it
publicRemarks, priceHistoryFilled with enrichDetails when Realtor.ca publishes them
priceChangeDetected, previousPrice, newPrice, priceChangeDate, priceChangeLabel, monitorDiffPrice-change signals
source, scrapedAtData route and collection time
{
"mlsNumber": "C13846098",
"propertyId": "30347209",
"listingUrl": "https://www.realtor.ca/real-estate/30347209/7-473-dupont-street-toronto-annex",
"transactionType": null,
"price": 1074900,
"priceDisplay": "$1,074,900",
"address": {
"street": "7 - 473 DUPONT STREET",
"city": "Toronto (Annex)",
"province": "Ontario",
"postalCode": "M6G1Y6",
"text": "7 - 473 DUPONT STREET|Toronto (Annex), Ontario M6G1Y6"
},
"lat": 43.6727215,
"lon": -79.4149301,
"bedrooms": 2,
"bathrooms": 2,
"propertyType": "Single Family",
"buildingType": "Apartment",
"sqft": 130.06322,
"photoUrls": [
"https://cdn.realtor.ca/listings/TS639263952302970000/reb82/highres/8/c13846098_1.jpg"
],
"photoCount": 1,
"agentName": "Jordan Example",
"agentPhone": "(416) 555-0142",
"brokerageName": "RE/MAX HALLMARK BIBBY GROUP REALTY",
"listedDate": "639264096302930000",
"status": "1",
"publicRemarks": null,
"priceChangeDetected": false,
"previousPrice": null,
"newPrice": 1074900,
"priceChangeDate": null,
"priceChangeLabel": null,
"priceHistory": [],
"monitorDiff": null,
"source": "property-search",
"scrapedAt": "2026-10-01T01:38:33.453Z"
}

Pricing

This Actor uses Pay per event plus Apify platform usage. Each run charges one Actor Start event, one Listing scraped event per listing row saved, and one Listing detail enriched event per listing when enrichDetails succeeds. Platform usage, including the Residential Canada proxy, is billed on top at Apify's standard rates. The live Pricing tab on this page shows the current event prices.

Worked example: a city pull with maxResults at 100 costs up to 100 Listing scraped events plus one Actor Start event. Turning on enrichDetails for the same run adds up to 100 Listing detail enriched events. With onlyPriceChanges on, only the listings whose price moved are saved and billed.

API example

curl -X POST "https://api.apify.com/v2/acts/khadinakbar~realtor-ca-listings-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"city": "Toronto", "maxPrice": 700000, "maxResults": 25}'
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("khadinakbar/realtor-ca-listings-scraper").call(run_input={
"city": "Vancouver",
"minBeds": 2,
"maxResults": 50,
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["mlsNumber"], listing["price"], listing["address"]["text"])

Use with AI agents (MCP)

Connect the Actor through Apify MCP in Claude, ChatGPT or Cursor and ask:

Find two-bedroom condos for sale in downtown Toronto under 900,000 dollars. Return price, address, bathrooms and the listing link, cheapest first.

The agent sends city, maxPrice, minBeds and sortBy set to price-asc, then reads rows back with get-dataset-items. It should cite listingUrl and scrapedAt for each listing. Each saved row is one Listing scraped event, so agents should set maxResults to the number of listings the user wants to see and turn on enrichDetails only for a shortlist.

Best results

Starting situationHelpful actionExpected outcome
You want a precise neighbourhoodCopy the map extent from a Realtor.ca map URL into startUrls or mapBoundingBoxListings inside that exact area
You want price dropsTurn on monitorMode and schedule the same inputPrice-change fields from the second run onward
You need remarks and historyRun mlsNumbers with enrichDetails onFuller rows for a shortlist
You want a quick sampleKeep maxResults at 5A low-cost preview of the data
You track several citiesGive each city its own monitorStoreNameSeparate snapshots per market

Builder's note

I built monitor mode around a snapshot in your own key-value store because I wanted price changes you can trace to a real earlier observation, not a guessed history. I learned that people search Realtor.ca by place far more than by keyword, so the Actor accepts a city name, a map box or a pasted map URL and turns each into the same search.

FAQ

Does it cover US listings?

It covers Canadian listings on Realtor.ca. For US homes, use a Zillow Actor.

When are previousPrice and monitorDiff filled?

From the second run with monitorMode on and the same monitorStoreName, once a snapshot exists to compare against.

Why is publicRemarks empty?

Remarks and price history come from listing details. Turn on enrichDetails to fill them when Realtor.ca publishes them.

Responsible use

This Actor reads public listing information from Realtor.ca. Agent names and phone numbers are business contact details; use them in line with Canadian anti-spam law, privacy laws such as PIPEDA, and Realtor.ca's terms of use, and honor opt-outs. REALTOR® and Realtor.ca are trademarks of their owners, and this independent Actor is not affiliated with them. For questions, open a ticket in the Issues tab.