# Housesigma $1💰 Property Listings, Sold History & Agents (`abotapi/housesigma-com`) Actor

From $1/1K. Scrape housesigma.com listings across Ontario, BC, and Alberta. Search by city or paste URLs to extract prices, addresses, photos, room dimensions, school scores, price history, HouseSigma estimates, and sold statistics.

- **URL**: https://apify.com/abotapi/housesigma-com.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 26 total users, 1 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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?

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

## HouseSigma Scraper: Canadian Property Listings, Sold History and Agents

HouseSigma Scraper turns HouseSigma into structured Canadian real estate data. Search Ontario, British Columbia and Alberta by city with full filters, or paste listing and area links, and get clean records: addresses, prices, every photo, room dimensions, school scores, price history, the HouseSigma price estimate and community sold statistics. Five modes cover filtered search, direct links, listing IDs, the agent directory and community sold-price stats. Export to JSON, CSV or Excel, or pull results straight into your app through the API. No login or cookies required.

### Why This Scraper?

- **No login or cookies required.** The actor mints its own anonymous session and runs out of the box, with nothing to copy from your own account first.
- **Five modes, not one.** Search by filters, scrape pasted links, fetch listing details by ID, browse the agent directory, or pull community sold-price statistics, all from one actor.
- **Rich detail per property.** Turn on full details and get every photo, the virtual tour link, all rooms with dimensions, key facts, property features, full price history, nearby school scores, the HouseSigma price estimate and community sold trends.
- **Filters applied at the source.** Status, property type, price, bedrooms, bathrooms, garage spaces, size, listing age, assignment or resale, community and sort order all narrow the search before a single result page is fetched.
- **Stable, structured output.** Every listing comes back as the same flat field set, so a layout change on the site does not reshape your data.
- **Built for recurring monitoring.** Incremental mode tracks one search across scheduled runs and returns only what is new or changed, and a separate resume option continues one interrupted run without re-scraping what it already saved.
- **Optional export to the apps you use.** Pipe results into Notion, Linear or Airtable through MCP connectors, on top of the regular dataset.

### Use Cases

- **Home buyers and agents:** track new listings and price changes across specific cities or filters as soon as they appear.
- **Market research and appraisal:** pull recent sold prices, days on market and community statistics to price a property or a neighborhood.
- **Real estate investors:** screen large areas for detached homes, condos or land in a price and size range, then rank by price or recency.
- **Lead generation:** build a directory of agents by city with their listing volume, property-type mix and active inventory.
- **Data teams and dashboards:** schedule recurring pulls of the same search and receive only new, updated or expired listings on each run.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live listing.

| Field | Example |
| --- | --- |
| `idListing` | `"00000000000000AB"` |
| `url` | `"https://housesigma.com/on/toronto-real-estate/1-sample-st/home/00000000000000AB/"` |
| `status` | `"For Sale"` |
| `saleOrLease` | `"Sale"` |
| `propertyType` | `"Detached"` |
| `address` | `"1 Sample Street"` |
| `municipality` / `community` | `"Toronto"` / `"Sample Community"` |
| `province` | `"Ontario"` |
| `bedrooms` / `bathrooms` | `3` / `2` |
| `priceListed` / `priceListedText` | `1200000` / `"1,200,000"` |
| `priceSold` | `"(Sign-in required)"`: HouseSigma only shows sold prices to signed-in users, so anonymous runs return this placeholder |
| `mlNum` | `null` when the source masks it for anonymous sessions, otherwise the MLS number |
| `latitude` / `longitude` | `43.6500` / `-79.3800` |
| `sizeText` | `"1500 ft²"` |
| `dateListed` / `daysOnMarket` | `"2026-01-01"` / `12` |
| `photos` | `["https://cache16.housesigma.com/file/pix/00000000/0000_1.jpg", "..."]` (full details only) |
| `virtualTour` | link or `null` (full details only) |
| `keyFacts` | `{ "Tax": "$0,000 / 2025", "Lot Size": "00 x 000 feet", "Parking": "2 garages" }` (full details only) |
| `rooms` | `[{ "type": "Living", "level": "Main", "dimensions": "0.00 x 0.00" }]` (full details only) |
| `schools` | nearby school names and scores (full details only) |
| `priceHistory` | `[{ "price": "1,200,000", "status": "For Sale", "date_start": "2026-01-01" }]` (full details only) |
| `estimate` | `{ "priceInt": 1180000, "confidence": 0.8, "rentInt": 3500 }` (full details only) |
| `communityStats` | median sold price, average days on market and related trends for the area (full details only) |

Full-detail and search records also carry extra flat fields: `taxAnnual`, `maintenanceFee`, `crossStreet`, `openHouseDate`, `assessment`, `listingPriceChange`, `postalCode`, `brokerage`, `listAgentName`, `bedroomString`, `priceOrigin`, `priceTag`, `idCommunity`, `idMunicipality`, `dateStart`, `dateAddedDays` and more. The Output tab has a view per record kind: Overview, Listing details, Agents, Agent listings, Community stats and Changes (incremental).

Note: HouseSigma only shows sold prices and the MLS numbers of sold and leased records to signed-in users. `priceSold` therefore comes back as `"(Sign-in required)"`, and `mlNum` is `null` on sold and leased records. Every other field, including the full address, photos, rooms, price history and community trends, is returned in full.

Agent directory mode and agent-specific runs return agent records instead of listings: `agentId`, `slug`, `name`, `avatar`, `title`, `brokerage`, `languages` and a profile `url`, plus, when you name specific agents, a fuller profile with `about` text, career stats, top cities and property-type mix, and that agent's own listings tagged with `agentSlug` and a lightweight price estimate. Community mode returns one record per community with `idCommunity`, `idMunicipality`, `community`, `municipality`, `province` and nested `detail` / `soldPriceStats` objects covering median sold price, days on market and volume trends for that area.

### How to Use

1. Pick a **mode**: `search` (filters), `url` (paste listing or area links), `detail` (listing IDs), `agent` (directory or named agents), or `community` (sold-price stats).
2. For search, set the province, cities or communities and filters. For url or detail, paste the links or IDs instead. Turn **Fetch full details** on for the complete photo, room, school and estimate payload, or off for a faster, lighter run of search-card fields only.
3. Set **Max results** (and optionally **Max pages**) to control run size and cost, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

**Search a city for properties on sale, with full details:**

```json
{
  "mode": "search",
  "province": "ON",
  "locations": ["Toronto"],
  "status": ["for-sale"],
  "fetchDetails": true,
  "maxItems": 50
}
```

**Filtered search (3+ bedroom detached homes, 800k to 1.5M, cheapest first):**

```json
{
  "mode": "search",
  "locations": ["Mississauga", "Brampton"],
  "status": ["for-sale"],
  "propertyTypes": ["detached"],
  "minBedrooms": 3,
  "minPrice": 800000,
  "maxPrice": 1500000,
  "sortBy": "price-asc",
  "maxItems": 100
}
```

**Scrape specific listing links:**

```json
{
  "mode": "url",
  "urls": ["https://housesigma.com/on/toronto-real-estate/1-sample-st/home/00000000000000AB/"]
}
```

**Community sold-price statistics:**

```json
{
  "mode": "community",
  "province": "ON",
  "locations": ["Danforth"]
}
```

#### Supported URL shapes

`url` mode accepts these link types. **If you leave `urls` untouched, `url` mode scrapes one example of each shape below.** This is a change from earlier versions, where the default was a single sample listing, so trim the list to what you need.

| Shape | Example | What you get |
|---|---|---|
| Listing detail page | `https://housesigma.com/on/toronto-real-estate/410-90-niagara-street/home/aQmD7zn5m8Z7J9Bo/` | One full listing record |
| City / area listings page | `https://housesigma.com/on/toronto-real-estate/` | Every listing in that city, paged |
| Province map page | `https://housesigma.com/on/map/` | Listings across the province (ON, BC, AB) |
| Other-province city page | `https://housesigma.com/bc/vancouver-real-estate/` | Listings for that city in its own province |
| Paginated area page | `https://housesigma.com/on/toronto-real-estate/?page=2` | The walk starts at that result page; an incremental run treats it as a partial scope and skips EXPIRED marking |
| Agent profile page | `https://housesigma.com/on/agents/sneh-shekhada/` | The agent profile plus that agent's listings |
| Legacy agents directory | `https://housesigma.com/h5/en/agents` | The agent directory |

Any other link logs a warning (`Unrecognized URL`) and is skipped, and the run does not mark that scope as fully scanned. A city name in `locations` is resolved through the site's own search; if none of the names match, the run fails with a clear error.

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/housesigma-com").call(run_input={"mode": "search", "locations": ["Toronto"], "status": ["for-sale"]})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(listing["address"], listing["priceListedText"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/housesigma-com').call({ mode: 'search', locations: ['Toronto'], status: ['for-sale'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Max results, Max pages and long crawls

Leave **Max pages** empty to walk every result page for each location (a hard cap of 200 pages per location always applies); set it to cap how many pages (20 listings each) a single location can use. For an unbounded pull, a checkpoint survives a platform migration or a killed and resurrected run by remembering which records were already saved, and **`resumeFromRunId`** lets you continue the same catalogue walk in a brand-new run: paste a previous run or dataset ID and this run skips everything already collected there, appending only new records.

#### Resume and Incremental mode

`resumeFromRunId` and `incrementalMode` solve two different problems. **Resume** continues **one** specific interrupted run. **Incremental mode** is for scheduling this **same search** again and again (for example daily) and getting only what changed, without pasting any run or dataset ID.

Turn on `incrementalMode` and each run classifies every record against the state saved from the last run on the same search (kept internally, keyed by search mode, locations and filters, or by your own `stateKey`):

- `NEW`: not seen before.
- `UPDATED`: seen before, and at least one field changed (`changedFields` lists which).
- `UNCHANGED`: seen before, nothing changed. Suppressed (not returned or billed) unless `emitUnchanged` is on.
- `EXPIRED`: previously tracked, not found this run. Only produced when a run fully scans the tracked search, not capped by Max results, not cut short by Max pages, and not a resume, and only when `emitExpired` is on.
- `REAPPEARED`: a record that was previously marked `EXPIRED` and has now been found again. This can only happen after an earlier run with `emitExpired` on actually marked that record `EXPIRED` during a complete scan. A search that never turns `emitExpired` on will only ever see `NEW`, `UPDATED` and `UNCHANGED`, never `REAPPEARED`.

**What is compared.** Every output field of the record (price, status, dates, photos, rooms, estimate price and so on) is compared with the saved copy, and the fields that differ are listed in `changedFields`. Days on market and its text (`domText`), the day counters (`dateAddedDays`, `dateListDays`, `dateEndDays`), the estimate popularity score and estimate date, and the per-card scores change on their own with the clock, so they are left out of the comparison: they stay in your output, but they never make a record `UPDATED`. Add your own noisy fields under **Ignore fields when detecting changes** (`ignoreFieldsForChanges`); use a dotted path for a nested field (`estimate.confidence`, or `rooms.size` for every room). Changing this list never causes a one-time wave of `UPDATED` rows, because the saved copy is re-compared with the current list.

**EXPIRED is never guessed from a partial scan.** A run that was capped by Max results or Max pages, stopped on a repeated page, lost a result page or a location/agent/community/listing (could not be fetched or resolved), or hit a search that returns its maximum of 4000 results, does not mark anything `EXPIRED`; the previous state of those records is kept.

Every record also carries `firstSeenAt` / `lastSeenAt` in incremental mode. The detail-enrichment surcharge is billed only for records that actually reach the dataset; a suppressed `UNCHANGED` record's detail page may still be fetched (needed to compute the fingerprint) but is never charged.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record, not the full JSON. Each item becomes one entry with a **title** (the listing's link for property records, or the agent's title or name for agent records) and its key fields flattened to plain text (price, beds and baths, URL, and more). Nested objects collapse to their main value, and long lists trim to the first few names. The **complete record always stays in the Apify dataset**; the connector copy is a readable digest for browsing in your app.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip; the export only runs when a connector is selected.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search`, `url`, `detail`, `agent`, or `community`. |
| `province` | string | `ON` | `ON`, `BC`, or `AB`. |
| `locations` | array | none (prefill: `["Toronto"]`) | City or community names. Empty searches the whole province. Used by `search` and `community` modes. |
| `status` | array | `["for-sale"]` | `for-sale`, `for-rent`, `sold`, `leased`, `de-listed`; `de-listed` is split into its own delisted statuses. |
| `propertyTypes` | array | `[]` | Detached, Semi-Detached, Freehold Townhouse, Condo Townhouse, Condo Apt, Link, Multiplex, Vacant Land, Other. Empty means all types. |
| `minPrice` | integer | none | Minimum price in CAD. |
| `maxPrice` | integer | none | Maximum price in CAD. |
| `minBedrooms` | integer | none | Minimum bedrooms (5 means 5+). |
| `maxBedrooms` | integer | none | Maximum bedrooms (5 means 5+). |
| `minBathrooms` | integer | none | Minimum bathrooms. |
| `minGarage` | integer | none | Minimum garage spaces. |
| `minSqft` | integer | none | Minimum interior size in square feet. |
| `maxSqft` | integer | none | Maximum interior size in square feet. |
| `listingDays` | integer | none | Only listings first listed within the last N days (0 or empty means any age). |
| `listingType` | string | `all` | `all`, `assignment` (pre-construction assignment sales) or `resale`. |
| `community` | string | none | Narrow a city search to one community, e.g. `Alliance` with location `Barrie`. If it is not found the whole city is searched. |
| `soldDays` | integer | `90` | For `sold` / `leased` / `de-listed` status: only include records from the last N days. |
| `sortBy` | string | `newest` | `newest`, `price-asc`, `price-desc`. |
| `urls` | array | one example of each supported link type (see **Supported URL shapes**) | Listing links, city or area pages, province map pages, agent profiles or the agents directory. Used by `url` mode. |
| `listings` | array | `[]` | Listing IDs or full listing links. Used by `detail` mode. |
| `agents` | array | `[]` | Agent profile links or bare slugs. Leave empty to scrape the whole province agent directory instead. Used by `agent` mode. |
| `agentCategory` | string | `sold` | Which of a named agent's listings to pull: `sold`, `active`, or `toured`. |
| `fetchDetails` | boolean | `true` | Open each listing's detail page for photos, rooms, schools, price history, community stats and the HouseSigma estimate. Turn off for a faster, lighter run of search-card fields only. |
| `maxItems` | integer | `50` | Stop after this many records. `0` means no limit. |
| `maxPages` | integer | none | Maximum result pages (20 listings each) to walk per location. Leave empty (or 0) to walk every result page, up to a hard cap of 200 pages per location; higher values are clamped to 200. |
| `resumeFromRunId` | string | none | A previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Records already collected there (matched by listing, agent, or community ID) are skipped, so this run only saves the new ones. |
| `incrementalMode` | boolean | `false` | Turn on for daily or recurring monitoring of the same search. See "Resume and Incremental mode" above. |
| `stateKey` | string | none | Optional. Name an incremental-mode monitoring campaign, or share state across differently configured runs. Leave empty to derive a key automatically from the search mode, locations and filters. |
| `emitUnchanged` | boolean | `false` | Incremental mode only. Also return (and bill) records that have not changed since the last run, marked `UNCHANGED`. |
| `emitExpired` | boolean | `false` | Incremental mode only. Also return (and bill) records present in a previous run but no longer found, marked `EXPIRED`. Only produced when a run fully scans the tracked search. |
| `ignoreFieldsForChanges` | string\[] | `[]` | Incremental mode only. Extra field names (dotted path for nested fields) that never trigger `UPDATED`; they stay in the output. Days on market and its text, the day counters (`dateAddedDays`, `dateListDays`, `dateEndDays`), estimate popularity score and date, and per-card scores are always ignored. |
| `proxy` | object | Apify Proxy | Connection settings. The default works on paid plans; residential (optionally pinned to Canada) is supported but not required. |
| `mcpConnectors` | array | none | Optional: send a summary of each record to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | none | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. Does not affect the dataset. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live listing.

```json
{
  "idListing": "00000000000000AB",
  "url": "https://housesigma.com/on/toronto-real-estate/1-sample-st/home/00000000000000AB/",
  "status": "For Sale",
  "saleOrLease": "Sale",
  "propertyType": "Detached",
  "address": "1 Sample Street",
  "municipality": "Toronto",
  "community": "Sample Community",
  "province": "Ontario",
  "mlNum": "X00000000",
  "bedrooms": 3,
  "bathrooms": 2,
  "priceListed": 1200000,
  "priceListedText": "1,200,000",
  "priceSold": "(Sign-in required)",
  "latitude": 43.6500,
  "longitude": -79.3800,
  "sizeText": "1500 ft²",
  "dateListed": "2026-01-01",
  "daysOnMarket": 12,
  "photos": ["https://cache16.housesigma.com/file/pix/00000000/0000_1.jpg"],
  "virtualTour": null,
  "keyFacts": { "Tax": "$0,000 / 2025", "Lot Size": "00 x 000 feet", "Parking": "2 garages" },
  "rooms": [{ "type": "Living", "level": "Main", "dimensions": "0.00 x 0.00" }],
  "priceHistory": [{ "price": "1,200,000", "status": "For Sale", "date_start": "2026-01-01" }],
  "estimate": { "priceInt": 1180000, "confidence": 0.8, "rentInt": 3500 }
}
```

### Plan Requirement

A paid Apify plan is required, because the actor reads pages through Apify Proxy and free plans do not include proxy access. The default Apify Proxy setting is enough: datacenter connections load listings, agents and community data, and residential is not required. If the selected connection is refused, the log says: `The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable.` If no page can be read at all, the run fails with one of these messages instead of finishing with an empty dataset:

- `The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid.`
- `No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested HouseSigma pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again.`
- `Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later.`

### FAQ

#### How much does it cost?

You pay per record returned, and the optional full-detail payload (photos, rooms, price history, estimate and more) carries a separate detail-enrichment charge that only applies to records that actually reach the dataset. Current rates: **$0.002 per record**, **$0.0007 per record for the detail-enrichment charge** (only when full details are on), and a **$0.05 actor-start charge** per run (BRONZE tier prices, tiered by Apify plan). The **Pricing** tab always shows the live rates. Use **Max results** to cap the cost of any run.

#### Is it legal to scrape HouseSigma?

This actor collects only publicly available listing data. You are responsible for how you use it: follow HouseSigma's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price and size are generally factual data, but photos and some third-party content may carry separate rights.

#### Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new and updated records, and unchanged ones are not billed. Turning on `emitExpired` also reports listings that dropped out of the tracked search, but only once a run has fully scanned it, and only a record that was previously marked `EXPIRED` this way can later come back as `REAPPEARED`.

#### What's the difference between Resume and Incremental mode?

**Resume** (`resumeFromRunId`) continues one specific interrupted run so it doesn't re-scrape what it already saved. **Incremental mode** is for running the same search again and again on a schedule and getting a diff each time. Turning both on together only works to bootstrap a brand-new monitoring campaign from a resumed dataset; if incremental state already exists for that search, the run fails with a clear message asking you to drop `resumeFromRunId` or pick a different `stateKey`.

#### Why did my run fail instead of returning an empty dataset?

The run fails immediately, with a clear message, if it cannot open a session with HouseSigma at all, or if `resumeFromRunId` doesn't point to a run or dataset your account can read, or if Incremental mode and Resume are combined in a way that would conflict with existing saved state. Once a session is open, an individual request that gets refused is retried and, if it still fails, skipped with a warning instead of failing the whole run, so a search that partially succeeds returns whatever it could read rather than nothing at all.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 Want more real estate data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🏠 <a href="https://apify.com/abotapi/homely-com-au-scraper"><b>Homely.com.au</b></a><br>Scrape Homely.com.au properties for sale, rent, and sold, plus agent finder, suburb...</td><td>🏠 <a href="https://apify.com/abotapi/domain-com-au-scraper"><b>Domain.com.au</b></a><br>Extract enriched Domain.com.au property listings across buy, rent, and sold, with...</td></tr>
<tr><td>🏠 <a href="https://apify.com/abotapi/redfin-scraper"><b>Redfin Scraper</b></a><br>Scrape redfin.com home listings: price, beds, baths, sqft, lot, year built, coordinates...</td><td>🏠 <a href="https://apify.com/abotapi/homes-co-nz-scraper"><b>Homes.co.nz Scraper</b></a><br>Scrape Homes.co.nz listings by location or URL with pagination. Extract property details...</td></tr>
<tr><td>🏠 <a href="https://apify.com/abotapi/realtor-ca-scraper"><b>Realtor.ca</b></a><br>From $1/1K. Scrape Realtor.ca property listings with prices, descriptions, images, agent...</td><td>🏠 <a href="https://apify.com/abotapi/realestate-co-nz-scraper"><b>RealestateCo NZ</b></a><br>From $1/1K. Search and extract all real estate properties for sale, rent, and sold across...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/housesigma-com/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

What to scrape. 'search' uses the filters below. 'url' takes HouseSigma listing or area links. 'detail' takes listing IDs/links. 'agent' lists the agent directory. 'community' returns sold-price stats for a community.

## `province` (type: `string`):

Canadian province to search. HouseSigma currently covers Ontario, British Columbia and Alberta.

## `locations` (type: `array`):

City or community names to search, e.g. \['Toronto', 'Mississauga']. Each is resolved automatically. Leave empty to search the whole province. Used by 'search' and 'community' modes.

## `status` (type: `array`):

Which listing states to include.

## `propertyTypes` (type: `array`):

Filter by property type. Leave empty for all types.

## `minPrice` (type: `integer`):

Minimum price (CAD).

## `maxPrice` (type: `integer`):

Maximum price (CAD).

## `minBedrooms` (type: `integer`):

Minimum bedrooms.

## `maxBedrooms` (type: `integer`):

Maximum bedrooms (5 = 5+).

## `minBathrooms` (type: `integer`):

Minimum bathrooms.

## `minGarage` (type: `integer`):

Minimum garage spaces.

## `minSqft` (type: `integer`):

Minimum interior size in square feet.

## `maxSqft` (type: `integer`):

Maximum interior size in square feet.

## `soldDays` (type: `integer`):

For 'sold' / 'leased' / 'de-listed' status: only include records from the last N days.

## `listingDays` (type: `integer`):

Only listings first listed within the last N days (0 or empty = any age).

## `listingType` (type: `string`):

All listings, only pre-construction assignment sales, or only resale.

## `community` (type: `string`):

Narrow a city search to one community/neighbourhood, e.g. 'Alliance' with location 'Barrie'. Resolved automatically; if not found the whole city is searched.

## `sortBy` (type: `string`):

Result ordering.

## `urls` (type: `array`):

Listing links (/home/<id>/), city or area pages (/<prov>/<city>-real-estate/, optionally ?page=N to start at that result page), province map pages (/<prov>/map/), agent profiles (/<prov>/agents/<slug>/) or the legacy agents directory (/h5/en/agents). Used by 'url' mode. Left untouched, it scrapes one example of each of these shapes.

## `listings` (type: `array`):

Listing IDs (e.g. aQmD7zn5m8Z7J9Bo) or full listing links. Used by 'detail' mode.

## `agents` (type: `array`):

Agent profile links (.../agents/<slug>/) or bare slugs (e.g. matthew-schlotzhauer). In 'agent' mode each returns the agent's profile (bio, stats, top cities, property-type mix) plus their listings. Leave empty to scrape the whole province agent directory instead.

## `agentCategory` (type: `string`):

Which of an agent's listings to pull in 'agent' mode.

## `fetchDetails` (type: `boolean`):

Open each listing's detail page for all photos, rooms, schools, price history, community stats and the HouseSigma estimate. Turn off for a faster, lighter run that returns the rich search-card fields only.

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

Stop after this many records. 0 = no limit.

## `maxPages` (type: `integer`):

Maximum result pages (20 listings each) to walk per location. Leave empty (or 0) to walk every result page, up to a hard cap of 200 pages per location; higher values are clamped to 200.

## `proxy` (type: `object`):

Proxy configuration. The default Apify Proxy works on every plan. Residential (optionally pinned to Canada) is supported but not required.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Records already collected there (matched by listing/agent/community id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching records as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED records. A record is UPDATED when any output field changed (price, status, dates, photos, rooms, estimate price and so on, listed in changedFields), except days on market and its text, the added/listed/ended day counters, the estimate popularity score and date, per-card scores and anything you list under Ignore fields, which never trigger an update (they stay in the output). Records are never marked EXPIRED from a partial scan (capped, truncated, failed page or unresolved location). Turn on "Emit unchanged" or "Emit expired" only when you also want those records returned (and billed). State is kept separately per search (mode, locations, filters, fetchDetails); use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search mode, locations and filters — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search — not when Max results capped it, Max pages truncated it, or Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names to leave out of UPDATED change detection, in addition to the built-in handling. Use a dotted path for a nested field (for example estimate.confidence, or rooms.size for every room). Days on market and its text, the added/listed/ended day counters, the estimate popularity score and date, and the per-card scores never trigger UPDATED on their own. Ignored fields are still present in the output; they just cannot make a record count as changed.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. Notion gets a page per item; other connectors receive a best-effort write/digest. Leave empty to skip — this never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "province": "ON",
  "locations": [
    "Toronto"
  ],
  "status": [
    "for-sale"
  ],
  "propertyTypes": [],
  "soldDays": 90,
  "listingType": "all",
  "sortBy": "newest",
  "urls": [
    "https://housesigma.com/on/toronto-real-estate/410-90-niagara-street/home/aQmD7zn5m8Z7J9Bo/",
    "https://housesigma.com/on/toronto-real-estate/",
    "https://housesigma.com/on/map/",
    "https://housesigma.com/bc/vancouver-real-estate/",
    "https://housesigma.com/on/toronto-real-estate/?page=2",
    "https://housesigma.com/on/agents/sneh-shekhada/",
    "https://housesigma.com/h5/en/agents"
  ],
  "agentCategory": "sold",
  "fetchDetails": true,
  "maxItems": 50,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

## `detail` (type: `string`):

No description

## `agents` (type: `string`):

No description

## `agent_listings` (type: `string`):

No description

## `community` (type: `string`):

No description

## `changes` (type: `string`):

No description

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

No description

# 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 = {
    "mode": "search",
    "locations": [
        "Toronto"
    ],
    "urls": [
        "https://housesigma.com/on/toronto-real-estate/410-90-niagara-street/home/aQmD7zn5m8Z7J9Bo/",
        "https://housesigma.com/on/toronto-real-estate/",
        "https://housesigma.com/on/map/",
        "https://housesigma.com/bc/vancouver-real-estate/",
        "https://housesigma.com/on/toronto-real-estate/?page=2",
        "https://housesigma.com/on/agents/sneh-shekhada/",
        "https://housesigma.com/h5/en/agents"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/housesigma-com").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 = {
    "mode": "search",
    "locations": ["Toronto"],
    "urls": [
        "https://housesigma.com/on/toronto-real-estate/410-90-niagara-street/home/aQmD7zn5m8Z7J9Bo/",
        "https://housesigma.com/on/toronto-real-estate/",
        "https://housesigma.com/on/map/",
        "https://housesigma.com/bc/vancouver-real-estate/",
        "https://housesigma.com/on/toronto-real-estate/?page=2",
        "https://housesigma.com/on/agents/sneh-shekhada/",
        "https://housesigma.com/h5/en/agents",
    ],
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/housesigma-com").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 '{
  "mode": "search",
  "locations": [
    "Toronto"
  ],
  "urls": [
    "https://housesigma.com/on/toronto-real-estate/410-90-niagara-street/home/aQmD7zn5m8Z7J9Bo/",
    "https://housesigma.com/on/toronto-real-estate/",
    "https://housesigma.com/on/map/",
    "https://housesigma.com/bc/vancouver-real-estate/",
    "https://housesigma.com/on/toronto-real-estate/?page=2",
    "https://housesigma.com/on/agents/sneh-shekhada/",
    "https://housesigma.com/h5/en/agents"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/housesigma-com --silent --output-dataset

```

## MCP server setup

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

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/Nbl2FjXFVRwgRTHBm/builds/axf23rrMU6kF2xHHU/openapi.json
