# Realcommercial.com.au Scraper: Prices, Yield & Agents (`kotaro001/realcommercial-com-au-scraper`) Actor

Scrape realcommercial.com.au across five channels: for sale, for lease, sold, leased and investment. Get price as printed, tenure, areas, zoning, NABERS, agent phone, brochure PDFs and price-change tracking.

- **URL**: https://apify.com/kotaro001/realcommercial-com-au-scraper.md
- **Developed by:** [Tuyen Tran](https://apify.com/kotaro001) (community)
- **Categories:** Real estate
- **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.58`. Both datasets are public: open the JSON or CSV link in a browser, no login and no run needed.

**List run** — `LNtqUSPdSzbtvk8K9` · **20 rows** · 49 columns · 162.8 s · charged `apify-actor-start` 1, `listing-scraped` 20.
[JSON](https://actors.zapstackguides.com/samples/realcommercial-list.json) · [CSV](https://actors.zapstackguides.com/samples/realcommercial-list.csv)

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

Fill rate on the 20-row list sample: `priceNumeric` 4/20, `floorAreaSqm` 20/20, `agent1_phone` 0/20. Empty cells are honest: the portal prints "Contact Agent", "Prices on Application" or "Under Offer", so `priceNumeric` stays null instead of guessing.

| # | Address | Price | Tenure | Floor / land (sqm) | Source |
|---|---|---|---|---|
| 1 | Merchant, 3 Hosking Place, Sydney, NSW, 2000 | Prices on Application | vacant | 167 / — | [Open](https://www.realcommercial.com.au/for-sale/property-merchant-3-hosking-place-sydney-nsw-2000-504052495) |
| 2 | City Mutual Building, 503/66 Hunter Street, Sydney, NSW, 2000 | Under Offer | vacant | 64 / — | [Open](https://www.realcommercial.com.au/for-sale/property-city-mutual-building-503-66-hunter-street-sydney-nsw-2000-504986440) |
| 3 | Central Square, 323 Castlereagh Street, Sydney, NSW, 2000 | Contact Exclusive Selling Agents | any | 26065 / — | [Open](https://www.realcommercial.com.au/for-sale/property-central-square-323-castlereagh-street-sydney-nsw-2000-505231648) |

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 Realcommercial.com.au Scraper do?

Scrape **realcommercial.com.au listings** for offices, warehouses, retail, development land and commercial farming across five separate channels: `for-sale`, `for-lease`, `sold`, `leased` and `invest`. Every row carries the address, printed price, tenure, floor and land areas, agent contacts and lifecycle fields. The Free plan can return up to **50 results per run** for evaluation.

It is an API-friendly commercial property data tool. It does not log in, read private data or mix the five channels into one undifferentiated list.

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

Commercial listings hide more than residential ones: price is often “Contact Agent”, areas are missing, and the sale, lease and investment markets have different fields. This actor keeps those differences visible instead of flattening them into a misleading average.

| # | Feature | What it means for you | Measured on live runs |
|---|---|---|---|
| 1 | Five channels, never mixed | Choose `for-sale`, `for-lease`, `sold`, `leased` or `invest`; the output keeps `channel` and `tenure`. | Each channel has its own site path and field set. |
| 2 | Site-style filters | Filter by `state`, `suburb`, `postcode`, `propertyTypes`, `tenure`, price, floor area, land area and car spaces; `startUrls` remains available. | 9 commercial property types supported. |
| 3 | Real price numbers only | `priceDisplay` keeps the printed text; `priceNumeric` is filled only when exactly one amount is printed. | No guess when the site prints a range or “Contact Agent”. |
| 4 | Change-only alerts | `onlyEmitChanges: true` returns new, repriced and removed listings with `changeStatus` and `priceHistory`. | `daily_active` is the full snapshot; `changes_only` is the delta. |
| 5 | Detail cache | `includeDetails: true` adds agent phone, agency phone, zoning, NABERS and brochure PDFs; each page is reused for `detailCacheDays`. | Three repeat runs: 8 pages, then 2, then 0; 30 s down to 9 s. |
| 6 | Invest cashflow columns | The `invest` channel exposes `annualIncomeDisplay`, `estimatedYield`, `tenancySummary`, `tenantCount`, `fullyLeased` and `netIncome`. | 21/21 invest rows carried tenancy data in the Sprint 4 run. |

#### Price wording is not a price change

`changeStatus` is `NEW`, `PRICE_DROP`, `PRICE_INCREASE`, `REMOVED` or `UNCHANGED`. Empty price text is not a change, “By Negotiation” to “Contact Agent” is not a change, and a price that moves between the list card and the detail page is updated without a false alert.

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

| Field group | Fields | List mode | Needs `includeDetails: true` |
|---|---|---|---|
| Identity | `listingId`, `sourcePortal`, `listingUrl` | Yes | No |
| Address | `fullAddress`, `street`, `suburb`, `state`, `postcode`, `latitude`, `longitude` | Yes | Coordinates often from detail |
| Listing | `channel`, `propertyTypes`, `tenure` | Yes | No |
| Price | `priceDisplay`, `priceNumeric`, `priceSource` | Yes | No |
| Areas | `floorAreaSqm`, `landAreaSqm`, `carSpaces` | Yes | No |
| Lifecycle | `changeStatus`, `daysOnMarket`, `priceHistory` | Yes | No |
| Agent | `agent1_name`, `agent1_phone` | Name when published | **Yes** for phone |
| Agency | `agency_name`, `agency_phone` | Sometimes | **Yes** |
| Commercial | `zoning`, `nabersRating`, `brochurePdfUrls` | No | **Yes** |
| Invest | `annualIncomeDisplay`, `estimatedYield`, `tenancySummary`, `tenantCount`, `fullyLeased`, `netIncome` | No | Invest rows after detail parsing |

The five channels are deliberately separate:

- **`for-sale`** — asking price, tenure, floor and land area.
- **`for-lease`** — lease listings with areas and car spaces.
- **`sold`** — sold listings; price only when the site publishes it.
- **`leased`** — leased listings.
- **`invest`** — tenanted investments with income, yield and tenancy summary.

A missing value is `null`, never a guessed zero. `estimatedYield` exists only when the listing prints a yield; it is not invented from rent and price.

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

1. Pick a `channel` and enter `state`, `suburb` and `postcode`.
2. Choose `propertyTypes` (for example `["offices"]` or `["industrial-warehouse"]`) and optionally `tenure`, price and area filters.
3. Set `maxPages`, `maxItems`, and turn on `includeDetails` when you need agent phone, zoning, NABERS or brochure links; set `maxDetails` and `detailCacheDays`.
4. Press **Run**. For a daily feed, save it as a task, schedule 07:00 Australia/Sydney, and set `onlyEmitChanges: true`.

The first run builds the baseline. The second run returns only what changed. A new `stateKey` can inherit `first_seen_at`, `priceHistory` and valid cached detail from the central warehouse, so the first run is useful immediately.

### How much does it cost to scrape realcommercial.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.

**Pre-calculated 1,000-listing total** (one actor start plus the rows):

1. List only, `includeDetails: false`: **$2.005** on Standard (Free/Bronze), **$1.604** on Silver+.
2. Full details, `includeDetails: true`: **$8.005** on Standard (Free/Bronze), **$6.404** on Silver+.

### Input parameters and configuration examples

| Parameter | What it does | Example |
|---|---|---|
| `channel` | `for-sale`, `for-lease`, `sold`, `leased` or `invest` | `"for-sale"` |
| `state`, `suburb`, `postcode` | Location filter | `"NSW"`, `"Sydney"`, `"2000"` |
| `propertyTypes` | Offices, industrial-warehouse, retail, land-development, showrooms, hotel-leisure, medical, farming, other | `["offices"]` |
| `tenure` | `any`, `vacant` or `tenanted` | `"vacant"` |
| `maxPages` | Result pages to read | `2` |
| `includeDetails` | Add phone, zoning, NABERS and documents | `true` |
| `maxDetails` | Maximum detail pages | `10` |
| `detailCacheDays` | Detail reuse window; `0` means always fresh | `30` |
| `maxItems` | Maximum rows returned | `50` |
| `onlyEmitChanges` | Return only new, changed or removed rows | `true` |
| `minPrice`, `maxPrice` | Price range filter | `500000`, `5000000` |
| `minFloorArea`, `maxFloorArea` | Floor area in square metres | `100`, `2000` |
| `minLandArea`, `maxLandArea` | Land area in square metres | `500`, `10000` |
| `minDaysOnMarket` | Keep only listings at least this old | `60` |
| `startUrls` | Advanced exact search URL | `["https://www.realcommercial.com.au/for-sale/nsw/offices/"]` |

**Office search with detail**

```json
{
  "channel": "for-sale",
  "state": "NSW",
  "suburb": "Sydney",
  "postcode": "2000",
  "propertyTypes": ["offices"],
  "tenure": "any",
  "maxPages": 2,
  "includeDetails": true,
  "maxDetails": 10,
  "detailCacheDays": 30,
  "maxItems": 50
}
```

**Daily lease-change feed**

```json
{
  "channel": "for-lease",
  "state": "VIC",
  "suburb": "Melbourne",
  "postcode": "3000",
  "propertyTypes": ["industrial-warehouse"],
  "onlyEmitChanges": true,
  "includeRemovedListings": true,
  "stateKey": "melbourne-industrial-lease",
  "maxItems": 50
}
```

### Output example

A real commercial row from a Cloud run, shortened:

```json
{
  "listingId": "505230580",
  "sourcePortal": "realcommercial.com.au",
  "channel": "for-sale",
  "propertyTypes": ["Offices"],
  "tenure": "vacant",
  "fullAddress": "11 Bourke Street, Tamworth, NSW, 2340",
  "suburb": "Tamworth",
  "state": "NSW",
  "postcode": "2340",
  "priceDisplay": "Contact agent for price",
  "priceNumeric": null,
  "changeStatus": "NEW",
  "daysOnMarket": 51,
  "floorAreaSqm": 207,
  "landAreaSqm": 482,
  "carSpaces": 9,
  "agent1_name": "Jack Parfitt",
  "agent1_phone": "0400777498",
  "agency_name": "Knight Frank - TAMWORTH",
  "listingUrl": "https://www.realcommercial.com.au/for-sale/nsw/tamworth-2340/offices/",
  "priceHistory": [
    {"date": "2026-11-02", "event": "listed", "from": null, "to": "Contact agent for price"}
  ]
}
```

Download the dataset as JSON, HTML, CSV or Excel from the run, or consume 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 the suite, export the tables, and join on `fullAddress` (or `suburb` plus `postcode` for commercial) to combine residential asking prices with commercial income and yield data.

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

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

No. The actor uses the Apify proxy and handles bot protection. You choose channel, location and row limit.

#### How do I track daily price drops and removed listings?

Run once, save as a task, schedule daily and set `onlyEmitChanges: true`. Later runs return new, repriced and removed rows.

#### How do I get agent phone numbers or full commercial details?

Set `includeDetails: true` with `maxDetails` above zero. The detail page supplies `agent1_phone`, `agency_phone`, `zoning` and `nabersRating`.

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

Yes. Use the dataset export for Sheets, the API for n8n or Zapier, and Apify MCP for an AI agent. Flat columns need no parser.

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

This actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by REA Group or realcommercial.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 private commercial feed, lease-expiry tracking or a CRM integration? Contact **actors@zapstackguides.com** with your states, property types and refresh schedule.

# Changelog

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

# Actor input Schema

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

Each channel is a separate branch of the site and never mixes with the others.

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

One entry per search: 'Sydney, NSW', 'nsw', or a 4-digit postcode '2000'. One source per entry.

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

Slugs: offices, industrial-warehouse, retail, land-development, showrooms-bulky-goods, hotel-leisure, medical-consulting, commercial-farming, other.

## `tenure` (type: `string`):

Tenure filter. vacant-possession maps to vacant; tenanted-investment maps to tenanted. Ignored on sold and leased.

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

Lowest asking price in AUD. Listings priced 'Contact Agent' have no number and are filtered out by the site.

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

Highest asking price in AUD.

## `minFloorArea` (type: `integer`):

Smallest floor area in square metres.

## `maxFloorArea` (type: `integer`):

Largest floor area in square metres.

## `minLandArea` (type: `integer`):

Smallest land area in square metres.

## `maxLandArea` (type: `integer`):

Largest land area in square metres.

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

Minimum on-site car spaces.

## `keywords` (type: `string`):

Free text such as 'freehold', 'cold storage', 'crane'.

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

Paste search links you already filtered in a browser. The channel is read from the path.

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

Max pages per search.

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

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

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

Max detail pages.

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

Detail cache (days).

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

Max rows.

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

Australian state. Accepts NSW/VIC/QLD and lowercase aliases; empty means all states.

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

Suburb name, for example Sydney. Used with state and postcode.

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

Four-digit postcode, for example 2000.

## `runMode` (type: `string`):

Legacy switch for changes mode. Use onlyEmitChanges.

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

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

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

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

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

Adds agent phone, agency, zoning, areas, documents and coordinates. Billed per detail row.

## `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
{
  "channel": "for-sale",
  "locations": [],
  "propertyTypes": [
    "offices"
  ],
  "tenure": "any",
  "maxPages": 1,
  "details": false,
  "maxDetails": 10,
  "detailCacheDays": 30,
  "maxItems": 25,
  "state": "nsw",
  "suburb": "Sydney",
  "postcode": "2000",
  "runMode": "daily_active",
  "minDaysOnMarket": 0,
  "includeRemovedListings": false,
  "stateKey": "default",
  "onlyEmitChanges": false,
  "includeDetails": false,
  "suburbs": []
}
```

# Actor output Schema

## `listings` (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 = {
    "channel": "for-sale",
    "locations": [],
    "propertyTypes": [
        "offices"
    ],
    "tenure": "any",
    "maxPages": 1,
    "maxItems": 25,
    "state": "nsw",
    "runMode": "daily_active"
};

// Run the Actor and wait for it to finish
const run = await client.actor("kotaro001/realcommercial-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 = {
    "channel": "for-sale",
    "locations": [],
    "propertyTypes": ["offices"],
    "tenure": "any",
    "maxPages": 1,
    "maxItems": 25,
    "state": "nsw",
    "runMode": "daily_active",
}

# Run the Actor and wait for it to finish
run = client.actor("kotaro001/realcommercial-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 '{
  "channel": "for-sale",
  "locations": [],
  "propertyTypes": [
    "offices"
  ],
  "tenure": "any",
  "maxPages": 1,
  "maxItems": 25,
  "state": "nsw",
  "runMode": "daily_active"
}' |
apify call kotaro001/realcommercial-com-au-scraper --silent --output-dataset

```

## MCP server setup

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