# Centris Property Details Scraper (`ocrad/centris-property-details-scraper`) Actor

Extract property details from Centris URLs, effortlessly scrape detailed property data including prices, photos, financial details, schools nearby, listing brokers and more. Perfect for real estate analysis, investment research, or market insights.

- **URL**: https://apify.com/ocrad/centris-property-details-scraper.md
- **Developed by:** [Ocrad](https://apify.com/ocrad) (community)
- **Categories:** Real estate, Automation, Lead generation
- **Features:** Limited permissions
- **Stats:** 61 total users, 3 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $5.00 / 1,000 property records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Centris Property Details Scraper

***

#### 🔍 **What it does**

This Actor scrapes **extensive property details** from Centris.ca. By simply providing property listing URLs or search pages, you can retrieve detailed and structured property information including parking details, financial assesment, and broker insights.

With this Actor, you can:

- **Get Basic Property Insights**: Extract details like address, rooms, coordinates, price...
- **Access Deep Property Insights**: Extract granular details like municipal assessments, tax history, parking specifications...
- **Extract Broker Information**: Complete broker profiles with contact details, social media, and agency information.

***

#### 💼 **Use cases**

- **Real Estate Market Research**: Analyze Quebec property markets with comprehensive data sets.
- **Investment Property Analysis**: Evaluate opportunities with detailed financial and location data.
- **Competitive Analysis**: Understand pricing trends and property features in target areas.
- **Lead Generation**: Extract broker and agency contact information for business development.
- **Educational Research**: Access school ratings and education data for family-oriented property decisions.

***

#### **📝 Example Output**

```json
{
    "listing_id": "25219975",
    "url": "https://www.centris.ca/en/houses~for-sale~saint-odilon-de-cranbourne/25219975",
    "category": "House",
    "address": "123 Rue Principal, Saint-Odilon-de-Cranbourne, QC G0R 2Y0",
    "price": 425000,
    "price_currency": "CAD",
    "description": "Magnificent property located in a peaceful area with stunning views. This well-maintained home features modern amenities and spacious living areas perfect for families.",
    "rooms": 8,
    "beds_total": 4,
    "baths_total": 2,
    "baths_full": 2,
    "baths_half": 0,
    "residential_units": 1,
    "number_of_units": 1,
    "coordinates": {
        "latitude": 46.2453,
        "longitude": -70.8942
    },
    "lot_sqft": 43560,
    "year_built": 1995,
    "building_style": "Two storey",
    "additional_features": "Fireplace, Hardwood floors, Central air conditioning",
    "pool": "Above ground",
    "parking_total": 2,
    "parking_driveway": 2,
    "financial_details": {
        "title": "Financial details",
        "details": {
            "Municipal assessment": {
                "items": [
                    {"item": "Land", "amount": 85000},
                    {"item": "Building", "amount": 340000}
                ],
                "total": 425000
            },
            "Municipal taxes": {
                "items": [
                    {"item": "Property tax", "amount": 3200}
                ],
                "total": 3200
            }
        }
    },
    "photos": [
        {"href": "https://photos.centris.ca/property/25219975/photo1.jpg"},
        {"href": "https://photos.centris.ca/property/25219975/photo2.jpg"},
        {"href": "https://photos.centris.ca/property/25219975/photo3.jpg"}
    ],
    "listing_brokers": [
        {
        "id": "105001",
        "profile_id": "dd8729989e6c4a0d80875c5a3b06b316",
        "photo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDD1EEACDDDDDDDDDDC&t=c&w=190&h=220&sm=m",
        "url": null,
        "name": "Stéfany Lavigne, courtier immobilier inc.",
        "job_title": "Business corporation owned by a Certified Residential and Commercial Real Estate Broker AEO",
        "broker_entity": null,
        "phone_numbers": [],
        "website": null,
        "social_media": {
          "facebook": null,
          "instagram": null,
          "linkedin": null,
          "twitter": null,
          "youtube": null
        },
        "agency": {
          "name": "PROPRIO DIRECT",
          "type": null,
          "logo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDDD1DE7DDDDDDDDDDB&t=b&w=120&h=90"
        }
      },
      {
        "id": "106155",
        "profile_id": "dd8729989e6c4a0d80875c5a3b06b316",
        "photo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDD1EEAADDDDDDDDDDA&t=c&w=190&h=220&sm=m",
        "url": null,
        "name": "Charles-Etienne Gouger, courtier immobilier inc.",
        "job_title": "Business corporation owned by a Residential Real Estate Broker",
        "broker_entity": null,
        "phone_numbers": [],
        "website": null,
        "social_media": {
          "facebook": null,
          "instagram": null,
          "linkedin": null,
          "twitter": null,
          "youtube": null
        },
        "agency": {
          "name": "PROPRIO DIRECT",
          "type": null,
          "logo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDDD1DE7DDDDDDDDDDB&t=b&w=120&h=90"
        }
      },
      {
        "id": "105001",
        "profile_id": "dd8729989e6c4a0d80875c5a3b06b316",
        "photo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDD1EEACDDDDDDDDDDC&t=c&w=190&h=220&sm=m",
        "url": null,
        "name": "Stéfany Lavigne, courtier immobilier inc.",
        "job_title": "Business corporation owned by a Certified Residential and Commercial Real Estate Broker AEO",
        "broker_entity": null,
        "phone_numbers": [],
        "website": null,
        "social_media": {
          "facebook": null,
          "instagram": null,
          "linkedin": null,
          "twitter": null,
          "youtube": null
        },
        "agency": {
          "name": "PROPRIO DIRECT",
          "type": null,
          "logo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDDD1DE7DDDDDDDDDDB&t=b&w=120&h=90"
        }
      },
      {
        "id": "106155",
        "profile_id": "dd8729989e6c4a0d80875c5a3b06b316",
        "photo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDD1EEAADDDDDDDDDDA&t=c&w=190&h=220&sm=m",
        "url": null,
        "name": "Charles-Etienne Gouger, courtier immobilier inc.",
        "job_title": "Business corporation owned by a Residential Real Estate Broker",
        "broker_entity": null,
        "phone_numbers": [],
        "website": null,
        "social_media": {
          "facebook": null,
          "instagram": null,
          "linkedin": null,
          "twitter": null,
          "youtube": null
        },
        "agency": {
          "name": "PROPRIO DIRECT",
          "type": null,
          "logo": "https://mspublic.centris.ca/media.ashx?id=ADDD250DDDD1DE7DDDDDDDDDDB&t=b&w=120&h=90"
        }
      }
    ],
}
```

#### 🎯 **How It Works**

- **Input**: Provide Centris.ca property listing URLs or search page URLs.
- **Processing**: The Actor navigates through listings, extracts comprehensive data, and handles dynamic content like LocalLogic education widgets.
- **Output**: Receive structured **comprehensive JSON** data with all relevant property details.

***

#### ⚙️ **Configuration**

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | Array | `['https://www.centris.ca/en/properties~for-sale']` | Starting URLs for property search |
| `maxItems` | Number | `100` | Maximum number of properties to extract |
| `showFinancialDetails` | Boolean | `false` | Include detailed financial information |
| `showPhotos` | Boolean | `false` | Extract property photos |
| `showListingBrokers` | Boolean | `false` | Include broker and agency information |
| `proxy` | Boolean | `true` | Use proxy rotation for requests |

##### Example Input

```json
{
  "startUrls": ["https://www.centris.ca/en/properties~for-sale"],
  "maxItems": 50,
  "showFinancialDetails": true,
  "showPhotos": true,
  "showListingBrokers": true
}
```

#### 💬 **Support and Feedback**

Need help or have suggestions? Reach out to us via Apify support channels or leave feedback directly on the Actor's page. We're committed to maintaining compatibility with Centris.ca and providing reliable data extraction.

#### ✨ **Coming next**

1. **Education Data**.
2. **Transit Data**.
3. **Amenities Data**.

\--

#### **Is it legal to scrape Centris data?**

It is legal to scrape publicly available data such as property prices, financial details, or street address. However, you should be aware that the results from your Centris scrape might contain personal information.

Personal data is protected by GDPR (EU Regulation 2016/679), and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, please consult your lawyers. You can also read our blog post on the legality of web scraping.

### Performance Optimizations

#### Speed Improvements Made

This scraper has been optimized for maximum performance:

**🚀 Parallel Processing**

- **Concurrency**: Now uses dynamic concurrency (up to 5 parallel requests) instead of sequential processing
- **Queue-based Architecture**: Uses Crawlee's built-in request queue for efficient URL management
- **Parallel Property Extraction**: Properties are now processed simultaneously rather than one-by-one

**⚡ Reduced Timeouts & Waits**

- **Faster Timeouts**: Reduced timeouts from 30s to 10-15s for faster failure detection
- **Minimal Delays**: Removed unnecessary `waitForTimeout()` calls
- **Optimized Selectors**: Uses the most specific selectors first for faster element finding

**🎯 Smart Resource Management**

- **Request Limits**: Optimized request limits to avoid over-processing
- **Early Termination**: Stops processing immediately when target count is reached
- **Duplicate Prevention**: Efficient tracking of processed URLs

**📊 Education Data Optimization**

- **Reduced Timeouts**: 5s timeouts instead of 15s+ for iframe operations
- **Institution Limits**: Caps institutions at 10 per category for speed
- **Faster Selectors**: Uses most reliable selectors first
- **Quick Failures**: Fails fast if education data isn't available

#### Performance Comparison

| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| Concurrency | 1 (sequential) | 5 (parallel) | **5x faster** |
| Timeout Settings | 15-30s | 5-10s | **2-3x faster failure detection** |
| Property Processing | Sequential navigation | Parallel processing | **3-5x faster** |
| Education Data | 20-30s per property | 5-10s per property | **2-3x faster** |

#### Configuration for Speed

```javascript
// For maximum speed (basic data only)
{
    "maxItems": 100,
    "includeNearbySchools": false,  // Fastest
    "showFinancialDetails": false,  // Faster  
    "showPhotos": false,           // Faster
    "showListingBrokers": false,   // Faster
    "proxy": true
}

// For balanced speed and data richness
{
    "maxItems": 100,
    "includeNearbySchools": true,   // Some slowdown
    "showFinancialDetails": true,   // Minimal impact
    "showPhotos": true,            // Minimal impact
    "showListingBrokers": true,    // Minimal impact
    "proxy": true
}
```

#### API (OpenAPI)

When the Actor runs with a web server, you can talk to it over HTTP at the run’s **container URL** (see run details or `containerUrl` in the API). The API is described by an **OpenAPI 3.0** schema:

- **Schema file**: [`.actor/openapi.yaml`](.actor/openapi.yaml)

It defines endpoints such as:

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/` | GET | Health check |
| `/openapi.json` | GET | OpenAPI spec (JSON) |
| `/run` | POST | Start extraction (body = Actor input) |
| `/run` | GET | Run status or summary |
| `/output` | GET | Run output (OUTPUT key) |
| `/run-summary` | GET | Run summary |
| `/run-config` | GET | Run configuration used |
| `/results` | GET | Dataset metadata |

The server listens on the port in `ACTOR_WEB_SERVER_PORT` (default `4321`).

#### Expected Performance

- **Basic scraping** (no extra features): ~2-5 properties/minute
- **With education data**: ~1-3 properties/minute
- **100 properties**: 20-50 minutes (depending on features enabled)

# Actor input Schema

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

List of Centris.ca URLs to start scraping from. Can be search pages or individual property pages.

## `maxItems` (type: `integer`):

Maximum number of properties to extract. Set to 0 for unlimited.

## `includeNearbySchools` (type: `boolean`):

Extract nearby schools, daycares with scores and descriptions from LocalLogic integration. This may slow down the extraction.

## `showFinancialDetails` (type: `boolean`):

Extract detailed financial information including municipal assessments and tax data.

## `showPhotos` (type: `boolean`):

Extract high-resolution property images from Centris photo galleries.

## `showListingBrokers` (type: `boolean`):

Extract complete broker profiles with contact details, social media, and agency information.

## `proxyConfiguration` (type: `object`):

Proxy settings for requests (Apify Proxy, groups, country, or custom URLs).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.centris.ca/en/properties~for-sale"
    }
  ],
  "maxItems": 5,
  "includeNearbySchools": false,
  "showFinancialDetails": false,
  "showPhotos": false,
  "showListingBrokers": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Scraped property listings (one JSON object per property).

## `overview` (type: `string`):

Table view of the dataset.

# 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.centris.ca/en/properties~for-sale"
        }
    ],
    "maxItems": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("ocrad/centris-property-details-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.centris.ca/en/properties~for-sale" }],
    "maxItems": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("ocrad/centris-property-details-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).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.centris.ca/en/properties~for-sale"
    }
  ],
  "maxItems": 5
}' |
apify call ocrad/centris-property-details-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ocrad/centris-property-details-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9eEeeJKWfGey048be/builds/FMvlmahmKFcV2ayx6/openapi.json
