Realtor.ca Listings & Price Changes Scraper
Pricing
from $5.00 / 1,000 listing scrapeds
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
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
a month ago
Last modified
Categories
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
cityname, an exactmapBoundingBox, Realtor.castartUrls, or a list ofmlsNumbers. - Clean numbers.
priceis a number in CAD next to the display string, andlat/lonplace each listing on a map. - Listing contact on the row.
agentName,agentPhoneandbrokerageNamecome with every listing. - Price-drop tracking you can trust.
monitorModestores a snapshot in your own key-value store and fillspreviousPrice,newPrice,priceChangeDetectedandmonitorDiffon the next run. - Filters that match the site.
transactionType,propertyGroup,minPrice,maxPrice,minBeds,minBaths,keywordsandsortBy.
Best fit for this Actor
- Best fit for Canadian residential and commercial listings on Realtor.ca, for sale or for rent.
- Use
cityfor a quick market pull andmapBoundingBoxfor a precise neighbourhood. - Use
mlsNumberswithenrichDetailswhen 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.
| Request | Input 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}
| Field | Type | What it controls |
|---|---|---|
city | string | Canadian city name, for example Toronto or Calgary |
mapBoundingBox | object | LatitudeMin, LatitudeMax, LongitudeMin, LongitudeMax, optional ZoomLevel |
startUrls | array | Realtor.ca map search URLs or listing URLs |
mlsNumbers | array | MLS reference numbers for direct lookups |
transactionType | string | for-sale or for-rent. Default for-sale |
propertyGroup | string | residential or commercial. Default residential |
sortBy | string | date-desc, date-asc, price-asc, price-desc |
minPrice, maxPrice | integer | Price range in CAD |
minBeds, minBaths | integer | Minimum bedrooms and bathrooms |
keywords | string | Address fragment, building name or other keyword |
maxResults | integer | Cap on dataset rows. Default 5 for a quick sample |
enrichDetails | boolean | Add remarks, extra photos and public price history |
monitorMode, onlyPriceChanges, monitorStoreName | mixed | Cross-run price tracking settings |
proxyConfiguration | object | Apify Proxy; Residential Canada by default |
Output
| Field | What it contains |
|---|---|
mlsNumber, propertyId, listingUrl | Listing identity and public URL |
price, priceDisplay | List price in CAD as a number and as shown |
address | street, city, province, postalCode, text |
lat, lon | Coordinates |
bedrooms, bathrooms, propertyType, buildingType, sqft | Property details when published |
photoUrls, photoCount | Listing photos |
agentName, agentPhone, brokerageName | Listing agent and brokerage |
transactionType, status, listedDate | Listing state as Realtor.ca reports it |
publicRemarks, priceHistory | Filled with enrichDetails when Realtor.ca publishes them |
priceChangeDetected, previousPrice, newPrice, priceChangeDate, priceChangeLabel, monitorDiff | Price-change signals |
source, scrapedAt | Data 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 ApifyClientclient = 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 situation | Helpful action | Expected outcome |
|---|---|---|
| You want a precise neighbourhood | Copy the map extent from a Realtor.ca map URL into startUrls or mapBoundingBox | Listings inside that exact area |
| You want price drops | Turn on monitorMode and schedule the same input | Price-change fields from the second run onward |
| You need remarks and history | Run mlsNumbers with enrichDetails on | Fuller rows for a shortlist |
| You want a quick sample | Keep maxResults at 5 | A low-cost preview of the data |
| You track several cities | Give each city its own monitorStoreName | Separate 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.