# Realtor.ca Scraper — Listings, Details & Agents (`muhammadafzal/realtor-ca-api-scraper`) Actor

Realtor.ca scraper for Canadian listings, full property details, agent contacts, brokerages, photos, and MLS data. MCP-ready at $0.005 per record.

- **URL**: https://apify.com/muhammadafzal/realtor-ca-api-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 realtor.ca records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Realtor.ca Scraper — Listings, Details & Agents

**Realtor.ca Scraper** extracts Canadian property listings, full property-page details, REALTOR agent profiles, and brokerage contacts from public Realtor.ca pages. Use it for Canadian housing research, property monitoring, brokerage intelligence, and compliant real-estate lead workflows. Do not use it for US realtor.com data or private MLS fields. It returns one normalized record per listing or agent with stable, MCP-friendly fields and charges **$0.005 per record returned** plus the small Actor-start event.

The Actor accepts Realtor.ca map searches, city real-estate pages, individual property pages, city/province REALTOR directories, and individual agent profiles. It automatically recognizes each URL type, uses a real browser with consistent Canadian proxy sessions, captures Realtor.ca JSON search responses when available, and falls back to public DOM and JSON-LD data when the internal response shape changes.

### What data can I extract with Realtor.ca Scraper?

| Data group | Included fields |
|---|---|
| Listing identity | `propertyId`, `mlsNumber`, `listingUrl`, `address` |
| Price and layout | `price`, `currency`, `bedrooms`, `bathrooms`, `sizeInterior` |
| Property classification | `propertyType`, `buildingType`, `ownershipType` |
| Full page details | `description`, `timeOnRealtor`, `features`, `imageUrls` |
| Map data | `latitude`, `longitude` when present in the captured search payload |
| Listing agent | `agentId`, `agentName`, `agentTitle`, `agentPhone`, profile and website URLs |
| Brokerage | `officeName`, `officeAddress`, `officePhone`, `officeWebsite` |
| Agent profile | `languages`, `specialties`, `tradingAreas`, public social links |
| Provenance | `recordType`, `sourceUrl`, `sourceSearchUrl`, `scrapedAt`, `warnings` |

Optional fields are always present as `null`, `[]`, or `{}`. This consistent shape is useful for database imports and for AI agents using the Apify MCP server, because consumers do not need to guess whether an absent key means “not available” or “parser failure.”

### Realtor.ca Scraper use cases

- Monitor new Canadian property listings within a saved map boundary.
- Build market snapshots by MLS number, property type, price, bedrooms, or brokerage.
- Enrich listing summaries with public descriptions, photos, property facts, and agent contacts.
- Research REALTOR coverage, languages, specialties, and trading areas in a Canadian city.
- Compare brokerage inventory or create internal dashboards for mortgage, inspection, staging, and PropTech teams.
- Schedule repeat runs and compare datasets to detect listing additions, removals, and price changes.
- Give an AI agent a narrow Realtor.ca search/detail tool with predictable input, output, and billing.

This Actor does not provide sold-history databases, owner identities, buyer or tenant data, private broker remarks, showing instructions, or any other login-only MLS information.

### How to use Realtor.ca Scraper

1. Open Realtor.ca and configure the map, city search, property page, or REALTOR directory you need.
2. Copy the resulting URL into `startUrls`.
3. Set `maxResults` to your required record and billing cap.
4. Leave detail enrichment enabled for richer records, or disable it for the fastest search-card export.
5. Run the Actor and export its dataset as JSON, CSV, Excel, XML, RSS, or JSONL.

#### Supported URL examples

```text
https://www.realtor.ca/map#ZoomLevel=10&Center=45.25%2C-75.79&...
https://www.realtor.ca/on/toronto/real-estate
https://www.realtor.ca/real-estate/30023436/example-listing
https://www.realtor.ca/realtors/ab/edmonton
https://www.realtor.ca/agent/1946468/example-agent
```

The scraper is Canada-only. A `realtor.com` URL is rejected with a soft, actionable status message rather than being sent to the wrong extractor.

### Input

```json
{
  "startUrls": [
    { "url": "https://www.realtor.ca/realtors/ab/edmonton" },
    { "url": "https://www.realtor.ca/on/ottawa/real-estate" }
  ],
  "maxResults": 50,
  "enrichPropertyDetails": true,
  "enrichAgentProfiles": true,
  "responseFormat": "detailed"
}
```

| Input | Default | Notes |
|---|---:|---|
| `startUrls` | Small Ottawa map search | One or more supported Realtor.ca URLs |
| `maxResults` | `10` | Hard cap across all URLs; range 1–1000 |
| `enrichPropertyDetails` | `true` | Visits each listing page for full public details |
| `enrichAgentProfiles` | `true` | Visits each agent page for qualifications and office data |
| `responseFormat` | `detailed` | `concise` keeps core fields; `detailed` adds bounded enrichment |

Proxy, concurrency, retry, and fingerprint settings are intentionally managed by the Actor. Realtor.ca is protected by Imperva and can reject datacenter or inconsistent sessions; exposing these settings would make successful runs harder for most users and AI agents.

### Output

```json
{
  "recordType": "listing",
  "sourceUrl": "https://www.realtor.ca/real-estate/30023436/example",
  "sourceSearchUrl": "https://www.realtor.ca/on/ottawa/real-estate",
  "scrapedAt": "2026-07-13T12:00:00.000Z",
  "propertyId": "30023436",
  "mlsNumber": "X13554518",
  "listingUrl": "https://www.realtor.ca/real-estate/30023436/example",
  "address": "116 PASSAGEWAY PRIVATE, Ottawa, Ontario K2M1H6",
  "price": 840000,
  "currency": "CAD",
  "bedrooms": "2 + 1",
  "bathrooms": "3",
  "sizeInterior": "1500 - 2000 sqft",
  "propertyType": "Single Family",
  "buildingType": "Row / Townhouse",
  "ownershipType": "Freehold",
  "description": "Bright end-unit bungalow with an open-concept main floor...",
  "timeOnRealtor": "9 minutes",
  "latitude": null,
  "longitude": null,
  "imageUrls": ["https://cdn.realtor.ca/listings/example.jpg"],
  "agentId": "2135240",
  "agentName": "Example Agent",
  "agentTitle": "Salesperson",
  "agentPhone": "613-555-0100",
  "agentWebsite": null,
  "agentProfileUrl": "https://www.realtor.ca/agent/2135240/example",
  "agentPhotoUrl": null,
  "officeName": "Example Brokerage",
  "officeAddress": "Ottawa, Ontario",
  "officePhone": "613-555-0101",
  "officeWebsite": null,
  "languages": [],
  "specialties": [],
  "tradingAreas": [],
  "socialLinks": { "facebook": null, "instagram": null, "linkedin": null, "twitter": null },
  "features": { "Annual Property Taxes": "$5,752 (CAD)", "Parking Type": "Attached Garage" },
  "warnings": []
}
```

The `OUTPUT` key in the default key-value store contains the final run summary: pushed listing/agent counts, source modes, failed URLs, warnings, runtime, response format, charge count, and billed result-event total.

### How much does scraping Realtor.ca cost?

The Actor uses transparent pay-per-event billing:

| Event | Price |
|---|---:|
| Actor start | $0.00005, scaled by allocated memory |
| Schema-valid listing or agent record | $0.005 |

Examples: 10 records cost about **$0.05**, 100 records cost **$0.50**, and 1,000 records cost **$5.00**, plus the small start event and any platform usage option shown by Apify. The Actor prints the maximum result-event cost before scraping and charges only after a valid record has been stored. `maxResults`, Apify’s paid-dataset cap, and the run’s total-charge cap are all enforced before another charge can occur.

### API and MCP examples

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('muhammadafzal/realtor-ca-api-scraper').call({
  startUrls: [{ url: 'https://www.realtor.ca/realtors/ab/edmonton' }],
  maxResults: 25,
  enrichAgentProfiles: true,
  responseFormat: 'concise'
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient('MY_APIFY_TOKEN')
run = client.actor('muhammadafzal/realtor-ca-api-scraper').call(run_input={
    'startUrls': [{'url': 'https://www.realtor.ca/on/toronto/real-estate'}],
    'maxResults': 20,
    'responseFormat': 'detailed',
})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

For MCP clients, configure `https://mcp.apify.com/?tools=muhammadafzal/realtor-ca-api-scraper`. The concise response format is best when the agent needs to compare many records; detailed format is better for analyzing a small number of properties or agents.

### Reliability and limits

Realtor.ca can present Imperva/GeoTest challenges. The Actor uses a low-concurrency Playwright browser, Canadian residential proxy sessions, persistent cookies, browser fingerprints, retries, session retirement on 403/429 responses, a canary page, and partial-result preservation. Search extraction uses two layers: intercepted Realtor.ca JSON when available and stable public card selectors as a fallback. Property pages additionally use JSON-LD and labeled public detail sections.

Fields vary by listing and real-estate board. Missing optional values remain null rather than being guessed. A detail-page failure returns the already captured search-card record with a warning when that is truthful. If every request is blocked, the run fails honestly instead of returning a misleading empty success.

### Legal and responsible use

Realtor.ca’s [Terms of Use](https://www.realtor.ca/terms-of-use) state that its content is intended for private, non-commercial use and expressly prohibit web/data scraping, collection, storage, reorganization, manipulation, AI training, and republication. Building or running this Actor does not grant permission from Realtor.ca, CREA, a brokerage, or a listing owner. Before use, obtain any required authorization and legal advice, and comply with copyright, database rights, privacy law, PIPEDA, Quebec Law 25, CASL, contracts, and applicable real-estate-board rules.

Do not use the Actor to create a competing public listing database, republish photos or descriptions, send spam, infer sensitive traits, or retrieve data beyond the public page. Use the smallest amount of data necessary for a lawful purpose, retain it only as long as needed, and honour deletion or correction obligations.

### Other dedicated scrapers

- [Realtor Lead Scraper](https://apify.com/muhammadafzal/realtor-lead-scraper)
- [Fast Realtor.com Agents Scraper](https://apify.com/muhammadafzal/fast-realtor-agents-api-scraper)
- [Google Maps Scraper](https://apify.com/muhammadafzal/google-maps-scraper)
- [Apartments.com Email Scraper](https://apify.com/muhammadafzal/apartments-com-email-scraper)
- [Idealista Scraper](https://apify.com/muhammadafzal/idealista-scraper)
- [Domain.com.au Scraper](https://apify.com/muhammadafzal/domain-scraper)
- [Craigslist Scraper](https://apify.com/muhammadafzal/craigslist-scraper)
- [Auto Dealer Lead Scraper](https://apify.com/muhammadafzal/auto-dealer-lead-scraper)
- [Lawyer Lead Scraper](https://apify.com/muhammadafzal/lawyer-lead-scraper)
- [Shopify Product Scraper](https://apify.com/muhammadafzal/shopify-product-scraper)

### FAQ

#### How many results can I scrape with Realtor.ca Scraper?

Up to 1,000 records per run through `maxResults`. Start small because detail enrichment adds one browser request per record.

#### Can I integrate Realtor.ca Scraper with other apps?

Yes. Use Apify Integrations, webhooks, Zapier, Make, datasets, schedules, or the REST API.

#### Can I use Realtor.ca Scraper with the Apify API?

Yes. Call the Actor synchronously or asynchronously and read its default dataset and `OUTPUT` summary.

#### Can I use Realtor.ca Scraper through an MCP Server?

Yes. Add this Actor through Apify’s hosted MCP server and use `concise` output for lower token usage.

#### Do I need proxies to scrape Realtor.ca?

Cloud runs use Canadian residential proxies automatically. Direct local runs may be blocked and are mainly intended for parser/schema testing.

#### Is it legal to scrape Realtor.ca data?

Realtor.ca’s terms expressly prohibit scraping and restrict content to private, non-commercial use. Obtain permission and qualified legal advice before running the Actor.

#### Your feedback

Report a failing URL, run ID, expected record type, and missing field in the Actor’s Issues tab. Do not include private credentials or personal data.

# Actor input Schema

## `startUrls` (type: `array`):

Use this when you have Realtor.ca map/search, property-detail, agent-directory, or agent-profile URLs. Enter one URL per item, for example 'https://www.realtor.ca/realtors/ab/edmonton'. Defaults to a small Ottawa listing search. This is not for the US realtor.com domain.

## `maxResults` (type: `integer`):

Use this when you need a hard output and billing cap across all URLs. Enter an integer such as 50. Defaults to 10 and accepts 1 through 1000. This limits pushed records, not source pages visited during retries.

## `enrichPropertyDetails` (type: `boolean`):

Use this when listing searches should visit each property page for descriptions, features, photos, agents, and brokerages. For example, enable it for comparable-sales research. Defaults to true and adds one browser request per listing. This setting does not affect direct property-detail URLs, which are always fully parsed.

## `enrichAgentProfiles` (type: `boolean`):

Use this when agent-directory URLs should open each profile for languages, specialties, trading areas, websites, and office details. For example, enable it for Canadian brokerage lead research. Defaults to true and adds one browser request per agent. This setting does not change direct agent-profile URLs, which are always fully parsed.

## `responseFormat` (type: `string`):

Use this when an AI agent or export needs a smaller or richer record. Choose 'concise' for core listing/contact fields or 'detailed' for descriptions, photos, features, languages, and specialties. Defaults to 'detailed'. This does not return Realtor.ca's unnormalized internal payload.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.realtor.ca/realtors/ab/edmonton"
    }
  ],
  "maxResults": 50,
  "enrichPropertyDetails": true,
  "enrichAgentProfiles": true,
  "responseFormat": "concise"
}
```

# Actor output Schema

## `results` (type: `string`):

Schema-valid listing and agent records from the default dataset.

## `summary` (type: `string`):

Run counts, warnings, timing, and charge totals stored under OUTPUT.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.realtor.ca/map#ZoomLevel=10&Center=45.250322%2C-75.799950&LatitudeMax=45.70243&LongitudeMax=-75.06867&LatitudeMin=44.79459&LongitudeMin=-76.53123&Sort=6-D&PGeoIds=g30_f241etq5&GeoName=Ottawa%2C%20ON&PropertyTypeGroupID=1&TransactionTypeId=2&PropertySearchTypeId=0&Currency=CAD&HiddenListingIds=&IncludeHiddenListings=false"
        }
    ],
    "maxResults": 10,
    "enrichPropertyDetails": true,
    "enrichAgentProfiles": true,
    "responseFormat": "detailed"
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/realtor-ca-api-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://www.realtor.ca/map#ZoomLevel=10&Center=45.250322%2C-75.799950&LatitudeMax=45.70243&LongitudeMax=-75.06867&LatitudeMin=44.79459&LongitudeMin=-76.53123&Sort=6-D&PGeoIds=g30_f241etq5&GeoName=Ottawa%2C%20ON&PropertyTypeGroupID=1&TransactionTypeId=2&PropertySearchTypeId=0&Currency=CAD&HiddenListingIds=&IncludeHiddenListings=false" }],
    "maxResults": 10,
    "enrichPropertyDetails": True,
    "enrichAgentProfiles": True,
    "responseFormat": "detailed",
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/realtor-ca-api-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.realtor.ca/map#ZoomLevel=10&Center=45.250322%2C-75.799950&LatitudeMax=45.70243&LongitudeMax=-75.06867&LatitudeMin=44.79459&LongitudeMin=-76.53123&Sort=6-D&PGeoIds=g30_f241etq5&GeoName=Ottawa%2C%20ON&PropertyTypeGroupID=1&TransactionTypeId=2&PropertySearchTypeId=0&Currency=CAD&HiddenListingIds=&IncludeHiddenListings=false"
    }
  ],
  "maxResults": 10,
  "enrichPropertyDetails": true,
  "enrichAgentProfiles": true,
  "responseFormat": "detailed"
}' |
apify call muhammadafzal/realtor-ca-api-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=muhammadafzal/realtor-ca-api-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/i3EccSY3EfCPWkyIh/builds/tXpkxMNbT9lEY8RTV/openapi.json
