# Duproprio Listings Extractor (`kawsar/duproprio-listings-extractor`) Actor

DuProprio scraper that turns any DuProprio search URL into structured listing data with prices, addresses, photos, and availability, so you can track Quebec real estate without copying it by hand.

- **URL**: https://apify.com/kawsar/duproprio-listings-extractor.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.99 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## DuProprio Listings Extractor: turn any DuProprio search into structured data

DuProprio Listings Extractor scrapes property listings from DuProprio search result pages and saves them as a structured dataset. Paste a search URL for rentals or homes for sale, run the actor, and you get prices, addresses, bedroom counts, availability dates, photo URLs, and a direct link for every listing. Pagination is handled for you, so a search with hundreds of results still only takes one run.

DuProprio is the largest for-sale-by-owner real estate site in Quebec. Its search pages are useful to browse but painful to copy data from. This actor does the copying.

### How it works

1. Build a search on [duproprio.com](https://duproprio.com) with whatever filters you want: region, price range, property type, sort order, for sale or for rent.
2. Copy the URL from your browser's address bar.
3. Paste it into the **DuProprio search URLs** field and run the actor.

The actor walks through every result page of each search URL until it runs out of listings or hits your **Max items** cap. If two of your searches overlap, duplicate listings are skipped.

### Input

| Field | Type | Default | What it does |
|-------|------|---------|--------------|
| `searchUrls` | array | required | One or more DuProprio search result URLs. Rentals and for-sale searches both work. |
| `maxItems` | integer | 100 | Stop after this many listings, across all search URLs. Hard cap is 1000. |
| `requestTimeoutSecs` | integer | 30 | Timeout for each page request, in seconds. |

Example input:

```json
{
    "searchUrls": [
        "https://duproprio.com/en/rental/search/list?search=true&regions[0]=8&parent=1&sort=-published_at"
    ],
    "maxItems": 100
}
```

### What data does this actor extract?

Each listing becomes one dataset item:

| Field | Example | Notes |
|-------|---------|-------|
| `listingId` | `"1133900"` | DuProprio's internal listing ID. |
| `listingUrl` | `"https://duproprio.com/en/rental/...-1133900"` | Direct link to the listing page. |
| `priceLabel` | `"$1,800 / monthly"` | Price exactly as shown on the site. |
| `priceValue` | `1800` | Numeric price, ready for sorting and spreadsheets. |
| `city` | `"Bécancour (Bécancour)"` | City and borough. |
| `streetAddress` | `"2088 avenue Monseigneur Moreau"` | Street address as published. |
| `bedrooms` | `3` | Parsed from the listing summary when present. |
| `listingSummary` | `"5 1/2 (3 bedrooms) for rent..."` | Short teaser text from the search card. |
| `availability` | `"Now"` | Move-in date for rentals. Usually empty for sales. |
| `tags` | `["With Parking"]` | Badges shown on the card, like Furnished or 3D Virtual Tour. |
| `coverImageUrl` | `"https://photos.duproprio.com/...600...jpg"` | Main listing photo. |
| `imageUrls` | `[...]` | Every published size of the listing photo (320, 600, and 1024 px wide). |
| `sourceUrl` | `"https://duproprio.com/en/rental/search/list?..."` | The search page this listing came from. |
| `pageNumber` | `1` | Which result page it appeared on. |
| `scrapedAt` | `"2026-08-09T06:41:47Z"` | UTC timestamp. |
| `error` | `null` | Set only when a page could not be fetched. |

Example output item:

```json
{
    "listingId": "1133900",
    "listingUrl": "https://duproprio.com/en/rental/centre-du-quebec/becancour-becancour/5-1-2-for-rent/hab-2088-avenue-monseigneur-moreau-1133900",
    "priceLabel": "$1,800 / monthly",
    "priceValue": 1800,
    "city": "Bécancour (Bécancour)",
    "streetAddress": "2088 avenue Monseigneur Moreau",
    "bedrooms": 3,
    "listingSummary": "5 1/2 (3 bedrooms) for rent. 5 1/2 fully furnished...",
    "availability": "Now",
    "tags": ["Available as of"],
    "coverImageUrl": "https://photos.duproprio.com/photos/public/for_rent/202605/1133900/5-1-2-becancour-600-15701380.jpg",
    "imageUrls": [
        "https://photos.duproprio.com/photos/public/for_rent/202605/1133900/5-1-2-becancour-600-15701380.jpg",
        "https://photos.duproprio.com/photos/public/for_rent/202605/1133900/5-1-2-becancour-320-15701380.jpg",
        "https://photos.duproprio.com/photos/public/for_rent/202605/1133900/5-1-2-becancour-1024-15701380.jpg"
    ],
    "sourceUrl": "https://duproprio.com/en/rental/search/list?search=true&regions%5B0%5D=8&pageNumber=1",
    "pageNumber": 1,
    "scrapedAt": "2026-08-09T06:41:47+00:00",
    "error": null
}
```

### Use cases

- **Rental hunting**: run a saved search on a schedule and get new apartments as a dataset instead of refreshing the site every morning
- **Market research**: pull asking prices for a whole region into a spreadsheet and see how the FSBO market moves week to week
- **Lead generation**: agents and brokers can monitor for-sale-by-owner listings in their territory
- **Price comparison**: line up DuProprio listings next to data from other real estate scrapers to spot under-priced properties
- **Portfolio tracking**: property managers can watch competing rentals in the same neighbourhoods

### FAQ

**Does it work for both rentals and homes for sale?**
Yes. Any DuProprio search list URL works: `/en/rental/search/list?...` for rentals and `/en/search/list?...` for sales. French URLs work too, as long as the page is a search result list.

**How do I scrape a specific region?**
Set the region filters on duproprio.com first, then copy the resulting URL. The region choices are encoded in the URL as `regions[0]=...` parameters, so the actor searches exactly what you saw in the browser.

**How many listings can it collect per run?**
Up to 1000 per run, controlled by the `maxItems` input. DuProprio shows 12 listings per result page and the actor keeps paging until it reaches your cap or the end of the results.

**Do I get the listing photos?**
Yes. Each item includes the cover photo plus every size variant DuProprio publishes for the search card (320, 600, and 1024 pixels wide). Full photo galleries live on the individual listing pages, which you can visit through `listingUrl`.

**Will it break if DuProprio changes its site?**
If the site's markup changes, some fields can come back empty. The actor fails soft: each page is parsed independently and fetch errors are recorded in the `error` field instead of killing the run.

### Tips

- Sort your search by newest first (`sort=-published_at`) and schedule the actor daily to build a change feed of new listings.
- Keep `maxItems` close to what you actually need. Smaller runs finish faster and cost less.
- The `priceValue` field is numeric on purpose: filter or sort on it directly in the Apify dataset view or after export to CSV or Excel.

Extract DuProprio listings once, or put the actor on a schedule and let the Quebec real estate data come to you.

# Actor input Schema

## `searchUrls` (type: `array`):

One or more DuProprio search result URLs to extract listings from. Build a search on duproprio.com (for sale or for rent, any region filters), then copy the URL from the address bar and paste it here. Pagination is handled automatically.

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

Maximum number of listings to extract per run, across all search URLs.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout in seconds.

## Actor input object example

```json
{
  "searchUrls": [
    "https://duproprio.com/en/rental/search/list?search=true&regions[0]=8&parent=1&sort=-published_at",
    "https://duproprio.com/en/search/list?search=true&regions[0]=6&parent=1"
  ],
  "maxItems": 10,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

## `listings` (type: `string`):

All extracted property listings, one row per listing.

# 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 = {
    "searchUrls": [
        "https://duproprio.com/en/rental/search/list?search=true&regions[0]=8&regions[1]=1&regions[2]=17&parent=1&pageNumber=1&sort=-published_at"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/duproprio-listings-extractor").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 = { "searchUrls": ["https://duproprio.com/en/rental/search/list?search=true&regions[0]=8&regions[1]=1&regions[2]=17&parent=1&pageNumber=1&sort=-published_at"] }

# Run the Actor and wait for it to finish
run = client.actor("kawsar/duproprio-listings-extractor").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 '{
  "searchUrls": [
    "https://duproprio.com/en/rental/search/list?search=true&regions[0]=8&regions[1]=1&regions[2]=17&parent=1&pageNumber=1&sort=-published_at"
  ]
}' |
apify call kawsar/duproprio-listings-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/duproprio-listings-extractor"
        }
    }
}

```

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/Sdg4tdpinRZGoZhWQ/builds/fWxvKdmsnYgebarzA/openapi.json
