# Property.com.au Scraper: Sold History & Estimates (`kotaro001/property-com-au-scraper`) Actor

Scrape property.com.au listings by suburb: price, beds, baths, land size, estimated value, weekly rent estimate and the full sale and rent history of each property. Filter by state, suburb, postcode, sale or rent, property type and bedrooms.

- **URL**: https://apify.com/kotaro001/property-com-au-scraper.md
- **Developed by:** [Tuyen Tran](https://apify.com/kotaro001) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 listings

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

### Live Sample Dataset & Verified Run Benchmark

Two runs on **2026-11-03** on Apify Cloud, build `0.1.76`. Both datasets are public: open the JSON or CSV link in a browser, no login and no run needed.

**List run** — `lQRu6ToUMRx51xYXO` · **30 rows** · 62 columns · 50.7 s · charged `apify-actor-start` 1, `listing-scraped` 30.
[JSON](https://actors.zapstackguides.com/samples/property-list.json) · [CSV](https://actors.zapstackguides.com/samples/property-list.csv)

**Detail run** — `kyXh2YRPCxOKpQbgt` · **3 rows** · 62 columns · 328.2 s · charged `listing-scraped` 3, `detail-scraped` 3.
[JSON](https://actors.zapstackguides.com/samples/property-detail.json) · [CSV](https://actors.zapstackguides.com/samples/property-detail.csv)

Fill rate on the 30-row list sample: `priceNumeric` 28/30, `sold_date` 30/30, `estimate_value` 0/30. Empty cells are honest: the portal prints “Contact Agent”, “Auction” or “Price withheld”, so `priceNumeric` stays null instead of guessing. The detail run is the place to see agent phone, description and history.

| # | Address | Price | Beds | Baths | Type | Source |
|---|---|---|---|---|---|---|
| 1 | 12/96 York Street, Richmond, Vic 3121 | $350,000 | 1 | 1 |  | [Open](https://www.property.com.au/vic/richmond-3121/york-st/12-96-pid-4187013/) |
| 2 | 23 Crown Street, Richmond, Vic 3121 | $1,720,000 | 3 | 2 |  | [Open](https://www.property.com.au/vic/richmond-3121/crown-st/23-pid-3171320/) |
| 3 | 35 Johnson Street, Richmond, Vic 3121 | $2,100,000 | 4 | 1 |  | [Open](https://www.property.com.au/vic/richmond-3121/johnson-st/35-pid-3499680/) |

Open the sample, compare the three rows with the source pages, check the $2.005 and $8.005 lines below, and note the 50-row free limit. That is the whole test, under five minutes.

### What does the Property.com.au Scraper do?

Scrape **property.com.au sold prices**, current listings and rent estimates for an Australian suburb without opening each page by hand. Rows carry the sale date, **years held**, estimated value, weekly rent estimate, planning overlays and school catchment when `includeDetails` is on. The Free plan can return up to **50 results per run** for testing.

It is an API-friendly property data tool, not a login or paywall bypass. It reads public listing pages and returns one flat row per property.

### Why scrape property.com.au with this Actor?

The site combines listings with a valuation model and a long sold history. This actor puts those layers into one table you can filter, join and schedule.

| # | Feature | What it means for you | Measured on live runs |
|---|---|---|---|
| 1 | Form filters | Choose `state`, `suburb`, `postcode`, `channel`, `propertyTypes`, rooms, land and price without assembling a URL. | Sold search reached 1,005 properties across 51 pages. |
| 2 | Change-only mode | `onlyEmitChanges: true` returns new, repriced and removed listings instead of the whole suburb every day. | Re-run with no movement returns 0 rows. |
| 3 | Sold timeline | `sold_date`, `last_sold_price`, `years_held` and `capital_growth_pct` come from the sold record and detail page. | Sold detail sample: 10/10 histories and years-held values. |
| 4 | Smart detail cache | `includeDetails: true` opens a property once and reuses it for `detailCacheDays`; a price change drops that cache entry. | Detail coverage 10/10 for estimate, rent estimate and overlays. |
| 5 | Flat output | One row per property, ready for CSV, Google Sheets or a warehouse; the core fields are flat. | 62 columns: 25 core fields plus portal and detail fields. |
| 6 | Automation-ready | Dataset export, API, scheduling, webhooks, n8n, Make, Zapier and Apify MCP for AI agents. | Works with the same input shape as the other two actors. |

#### The honest limit: no agent phone numbers

property.com.au publishes the **agency**, not the agent’s mobile number. This actor returns `agency_name` when details are on, but `agent1_phone` is not available from this source. Use the realestate.com.au actor when phone numbers are the priority.

### What data can you extract from property.com.au?

| Field group | Fields | List mode | Needs `includeDetails: true` |
|---|---|---|---|
| Identity | `listingId`, `sourcePortal`, `listingUrl` | Yes | No |
| Address | `fullAddress`, `suburb`, `state`, `postcode` | Yes | No |
| Sale | `priceDisplay`, `priceNumeric`, `sold_date`, `sold_days_ago` | Sold rows | Full sale history |
| Estimate | `rent_estimate_weekly`, `estimate_value`, `estimate_low`, `estimate_high` | No | **Yes** |
| History | `history`, `last_sold_date`, `last_sold_price`, `years_held`, `capital_growth_pct` | No | **Yes** |
| Property | `propertyType`, `bedrooms`, `bathrooms`, `carSpaces`, `landSizeSqm` | Yes | No |
| Risk | `flood_overlay`, `bushfire_overlay`, `heritage_overlay` | No | **Yes** |
| Schools | `schools`, `mobile_coverage` | No | **Yes** |
| Agency | `agency_name` | No | **Yes** |
| Lifecycle | `changeStatus`, `daysOnMarket`, `priceHistory` | Yes | No |

**`sold_date` is a real output field.** It is populated from the sold-date text or parsed from the “N days ago” label; when neither is printed, it stays `null` rather than being guessed.

### How to scrape property.com.au listings and price history

1. Enter `state`, `suburb` and `postcode` on the **Input** tab.
2. Choose `channel`: `buy`, `rent` or `sold`. `mode` is accepted as an alias for older tasks.
3. Set `maxPages`, `maxItems`, and optionally `propertyTypes`, `minBedrooms`, `maxBedrooms`, `minPrice` and `maxPrice`.
4. Turn on `includeDetails` to get estimates, rent, overlays, schools and agency; set `maxDetails` and `detailCacheDays`. Press **Run**, then schedule a daily task with `onlyEmitChanges: true`.

The first run starts the history. Later runs compare against it, so a new `stateKey` can still inherit the earliest `first_seen_at` and accumulated `priceHistory` from the central warehouse.

### How much does it cost to scrape property.com.au?

Pricing is **pay-per-event**. All Apify platform compute and residential/unblocker proxy usage is 100% included in the per-event price. You never pay a separate compute-unit or proxy surcharge.

- **List Mode (`includeDetails: false`): $2.005 per 1,000 listings** on the Apify Standard tier ($0.005 actor start + 1,000 × $0.002 per listing), or **~$1.60 per 1,000** on Apify Scale/Business discounted tiers.
- **Full Detail Mode (`includeDetails: true`): $8.005 per 1,000 listings with full details** on the Apify Standard tier ($0.005 actor start + 1,000 × $0.002 listing + 1,000 × $0.006 detail add-on), or **~$6.40 per 1,000** on discounted tiers. A 3-row detail test run costs exactly **$0.029**.
- **Free plan limit:** Free Apify accounts can extract **up to 50 rows per run**, enough to inspect the full schema, verify field fill rates and test a suburb before upgrading. Paid Apify plans unlock unlimited rows per run.
- Detail rows are billed whether they are live or served from the cache, because the customer receives the data in both cases.

### Input parameters and configuration examples

| Parameter | What it does | Example |
|---|---|---|
| `state`, `suburb`, `postcode` | Suburb filter | `"VIC"`, `"Richmond"`, `"3121"` |
| `channel` | `buy`, `rent` or `sold` | `"sold"` |
| `propertyTypes` | House, unit, townhouse, villa, land, acreage, rural | `["house"]` |
| `maxPages` | Result pages to read | `2` |
| `includeDetails` | Open each property page | `true` |
| `maxDetails` | Maximum detail pages | `10` |
| `detailCacheDays` | Reuse a detail page for this many days; `0` means always fresh | `30` |
| `maxItems` | Maximum rows returned | `50` |
| `onlyEmitChanges` | New, changed and removed rows only | `true` |
| `minPrice`, `maxPrice` | Post-load price filter | `700000`, `1400000` |
| `startUrls` | Advanced list/search URL input | `["https://www.property.com.au/vic/richmond-3121/sold/"]` |

**Sold-suburb run**

```json
{
  "channel": "sold",
  "state": "VIC",
  "suburb": "Richmond",
  "postcode": "3121",
  "propertyTypes": ["house"],
  "maxPages": 2,
  "includeDetails": true,
  "maxDetails": 10,
  "detailCacheDays": 30,
  "maxItems": 50
}
```

**Daily sold-price watch**

```json
{
  "channel": "sold",
  "state": "VIC",
  "suburb": "Richmond",
  "postcode": "3121",
  "onlyEmitChanges": true,
  "includeRemovedListings": true,
  "stateKey": "richmond-sold",
  "maxItems": 50
}
```

### Output example

A real sold record from a Cloud run, shortened:

```json
{
  "listingId": "1752836",
  "sourcePortal": "property.com.au",
  "channel": "sold",
  "fullAddress": "7 Watkin Street, Newtown, NSW 2042",
  "suburb": "Newtown",
  "state": "NSW",
  "postcode": "2042",
  "priceDisplay": "$1,650,000",
  "priceNumeric": 1650000,
  "sold_date": "15 Mar 2013",
  "changeStatus": "UNCHANGED",
  "daysOnMarket": 0,
  "bedrooms": 3,
  "bathrooms": 2,
  "carSpaces": null,
  "landSizeSqm": 111,
  "rent_estimate_weekly": 1360,
  "years_held": 13,
  "agency_name": "BresicWhitney - Inner West",
  "listingUrl": "https://www.property.com.au/nsw/newtown-2042/watkin-st/7-pid-1752836/"
}
```

Download the full result as JSON, HTML, CSV or Excel from the Dataset tab, or read it through the Apify API.

### 🇦🇺 Australian Real Estate Data Suite (6 Portals)

| Actor | Best for | Link |
|---|---|---|
| 🏠 Realestate.com.au Scraper: Price Drops & Agent Leads | Residential buy, rent and sold listings, daily price drops, agent phone numbers | https://apify.com/kotaro001/realestate-com-au-scraper |
| 📈 Property.com.au Scraper: Sold History & Estimates | Suburb sold prices, rent estimates, multi-year history, `years_held`, school zones | https://apify.com/kotaro001/property-com-au-scraper |
| 🏢 Realcommercial.com.au Scraper: Prices, Yield & Agents | Offices, warehouses, retail and farming; sale, lease, sold, leased and invest cashflow | https://apify.com/kotaro001/realcommercial-com-au-scraper |
| 🏡 OnTheHouse.com.au Scraper: Sold History & Valuations | Cotality AVM estimates, hidden contact-agent prices, multi-decade sale history, suburb medians and agent phones | https://apify.com/kotaro001/onthehouse-com-au-scraper |
| 🏛️ Allhomes.com.au Scraper: EER, Land Value & Rates | Canberra and ACT listings with EER, unimproved land value, UV year, annual rates and auction dates | https://apify.com/kotaro001/allhomes-com-au-scraper |
| 🌐 Domain.com.au Scraper: Prices, Schools & Suburb Trends | Sale, rent and sold listings with sale method, inspection times, school catchments, suburb medians, owner-occupier mix and agent phones | https://apify.com/kotaro001/domain-com-au-scraper |

**Pro Tip for investors and buyers’ agents:** run the same `state`, `suburb` and `postcode` across all three actors, export the CSV or Sheets tables, and join on `fullAddress` to compare the live asking price with the sold timeline, rent estimate and commercial income data.

### Frequently Asked Questions (FAQ) & Legal Disclaimer

#### Do I need to configure proxies to scrape property.com.au?

No. The actor manages the Apify proxy and the site’s request limits. You only choose the suburb and the number of pages.

#### How do I track daily sold prices and removed listings?

Run once, save the run as a task, schedule it daily, and set `onlyEmitChanges: true`. The next run returns new, changed and removed rows; `priceHistory` carries the dated price moves.

#### How do I get rent estimates, years held and school zones?

Set `includeDetails: true` and `maxDetails` above zero. The detail page provides `rent_estimate_weekly`, `years_held`, overlays and `schools`. `agency_name` is also available; agent phone numbers are not published by property.com.au.

#### Can I connect this Actor to Google Sheets, n8n, or AI Agents (MCP)?

Yes. Export JSON, CSV or Excel from the dataset, call the Apify API from n8n, Make, Zapier or a webhook, or use Apify MCP to let an AI agent query the actor.

#### Is it legal to scrape public property listings from property.com.au?

This actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by REA Group or property.com.au. It reads publicly available listing pages. How you use the data, and whether your use complies with the site’s terms and Australian law, is your responsibility.

**Custom work:** need a suburb watchlist, a bulk sold-history export or a CRM feed? Contact **actors@zapstackguides.com** with your postcodes and fields.

# Changelog

This Actor's version history is a separate document: https://apify.com/kotaro001/property-com-au-scraper/changelog.md

# Actor input Schema

## `state` (type: `string`):

Australian state. Accepts NSW/VIC/QLD (uppercase) and lowercase aliases.

## `suburb` (type: `string`):

Suburb name as it appears on property.com.au, e.g. Newtown.

## `postcode` (type: `string`):

Postcode of that suburb, e.g. 2042.

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

Legacy alias for channel. Kept for old tasks; use channel.

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

Leave empty for every type. Each selected type costs one page load.

## `bedrooms` (type: `integer`):

0 = any. Filtering is applied after the pages load, so pages must cover the suburb.

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

One page holds about 20 listings. Two pages cover most suburbs.

## `details` (type: `boolean`):

Legacy alias for includeDetails. Kept for old tasks; use includeDetails.

## `maxDetails` (type: `integer`):

Only used when the toggle above is on.

## `detailCacheDays` (type: `integer`):

Reuse a listing's valuation and history for this many days. 0 = always fetch fresh. A price change always refetches.

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

0 = no cap. Free-plan runs stop at 50 rows by design.

## `dealType` (type: `string`):

Legacy alias for channel. Kept for old tasks; use channel.

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

Optional search/list page URLs only. Do not pass a single property listing address.

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

Applied after the page is fetched; both portals ignore price in the URL.

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

Applied after the page is fetched.

## `includeRemovedListings` (type: `boolean`):

Emit a REMOVED row when a listing disappears from the search.

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

Named state slot: STATE\_<stateKey> in the key-value store.

## `onlyEmitChanges` (type: `boolean`):

Changes mode only emits new, changed or removed rows. Daily mode bills every row it emits.

## `channel` (type: `string`):

buy, rent or sold. Shared vocabulary with the other Australian property actors.

## `includeDetails` (type: `boolean`):

Adds estimated value, rent estimate, sale/rent history, agency and overlays. Billed per detail row.

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

Applied after the page loads; a listing without the field is dropped.

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

Applied after the page loads; a listing without the field is dropped.

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

Applied after the page loads; a listing without the field is dropped.

## `minCarSpaces` (type: `integer`):

Applied after the page loads; a listing without the field is dropped.

## `minLandSize` (type: `integer`):

Applied after the page loads; a listing without the field is dropped.

## `maxLandSize` (type: `integer`):

Applied after the page loads; a listing without the field is dropped.

## `minDaysOnMarket` (type: `integer`):

Keep only listings that have been advertised for at least this many days. 0 = no filter. Rows without a known days-on-market value are dropped when this is above 0.

## `suburbs` (type: `array`):

Optional. One or more areas such as 'Downer, ACT, 2602'. Each entry becomes its own search, and all rows land in one dataset. You can also separate entries with a semicolon in the suburb field.

## Actor input object example

```json
{
  "state": "VIC",
  "suburb": "newtown",
  "postcode": "2042",
  "mode": "sold",
  "propertyTypes": [],
  "bedrooms": 0,
  "maxPages": 1,
  "details": false,
  "maxDetails": 10,
  "detailCacheDays": 7,
  "maxItems": 25,
  "startUrls": [],
  "includeRemovedListings": false,
  "stateKey": "default",
  "onlyEmitChanges": false,
  "channel": "sold",
  "includeDetails": false,
  "minDaysOnMarket": 0,
  "suburbs": []
}
```

# Actor output Schema

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

No description

## `upgradeNotice` (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 = {
    "suburb": "newtown",
    "postcode": "2042"
};

// Run the Actor and wait for it to finish
const run = await client.actor("kotaro001/property-com-au-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 = {
    "suburb": "newtown",
    "postcode": "2042",
}

# Run the Actor and wait for it to finish
run = client.actor("kotaro001/property-com-au-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 '{
  "suburb": "newtown",
  "postcode": "2042"
}' |
apify call kotaro001/property-com-au-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kotaro001/property-com-au-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/mWCi4ygPFx9WCii38/builds/fGad9u7nPE0DP3fYO/openapi.json
