# Domain.com.au Property Scraper (`haketa/domain-com-au-scraper`) Actor

Domain.com.au scraper & API for Australian real estate: search property for sale & rent and export address, price, beds, baths, parking, land size, property type, agent & agency, inspection times, photos and coordinates. Australia property market data and lead gen — fast, no login.

- **URL**: https://apify.com/haketa/domain-com-au-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 70 total users, 6 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 2.00 out of 5 stars

## Pricing

from $2.00 / 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

## Domain.com.au Scraper — Australian Property Listings, Prices, Auctions, Agents & Geo

> **The most complete Domain.com.au scraper on Apify.** This **Domain.com.au scraper** pulls live for-sale, for-rent and recently-sold property listings from **[Australia's #2 real estate portal](https://www.domain.com.au/)** — every address, price / price guide, auction date, beds / baths / parking, land size, property type, agent & agency, image gallery and latitude/longitude — normalized into one clean, flat JSON schema. **No login, no coding.**

Export to **JSON, CSV, Excel, or API**.

> Built for property investors, buyer's agents, valuers and appraisers, mortgage brokers, PropTech & real-estate apps, relocation services, property journalists and housing researchers who need structured **Domain.com.au data** at scale.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/haketa/domain-com-au-scraper)
[![Live Data](https://img.shields.io/badge/Data-Live%20at%20Run%20Time-orange)]()
[![Scale](https://img.shields.io/badge/Scale-1%2C000%2B%20Listings%20Pagination-brightgreen)]()
[![Pay Per Event](https://img.shields.io/badge/Pricing-Pay%20Per%20Event-yellow)]()
[![Coverage](https://img.shields.io/badge/Markets-All%20AU%20Suburbs-purple)]()
[![Region](https://img.shields.io/badge/Region-Australia-red)]()
[![No Auth](https://img.shields.io/badge/Authentication-None%20Required-success)]()
[![Listing Types](https://img.shields.io/badge/Types-Sale%20%E2%80%A2%20Rent%20%E2%80%A2%20Sold-lightgrey)]()

***

### ⚡ At a glance

| Feature | Details |
|---|---|
| **Target Portal** | Domain.com.au (`domain.com.au`) — Australia's leading residential property marketplace |
| **Listing Modes** | 3 channels: **For Sale** (`sale`), **For Rent** (`rent`), and **Recently Sold** (`sold`) |
| **Search & Filters** | 28 built-in capital-city & prestige suburbs + `customSuburbs` + `startUrls` + Property Types, Bedrooms, Price Range (AUD), and `auctionOnly` |
| **Core Property Data** | Listing ID, URL, Street Address, Suburb/State/Postcode, GPS Latitude/Longitude, Parsed Price & Price Type, Beds/Baths/Car Spaces, Land Size, Agent & Agency, Image Gallery, Status Flags |
| **Rich Detail Mode** | Optional `scrapeDetails: true` adds Headline, Full Description, Features, Open-Home Inspection Times, School Catchments, Agent Mobile Phone & Profile URL, Days on Market, and Floorplan URL |
| **Pagination & Scale** | Unlimited auto-pagination per suburb (`maxPages: 0` default) governed by `maxListings` (`1,000+` listings supported), 100% deduplicated on `listingId` |
| **Proxy & Speed** | Australian Residential Proxy default — ~100–400 listings in 25–50 seconds |
| **Output Formats** | JSON, CSV, Excel (XLSX), XML, HTML Table, REST API & Webhooks |

***

### 🔎 Why scrape Domain.com.au?

**[Domain.com.au](https://www.domain.com.au/)** is the Nine Entertainment-owned real estate marketplace that anchors the Australian residential property market. It carries hundreds of thousands of live **for-sale, for-rent and recently-sold** listings across every suburb, state and territory — each with price guides, auction dates, agent contacts, beds/baths/parking, land size, school-catchment data, photos and precise map coordinates.

That data powers an enormous amount of business: investors comping suburbs, buyer's agents building shortlists, valuers assembling sold-sales bundles, mortgage brokers sizing deals, PropTech apps needing a listings backbone, and journalists covering Saturday auctions. Collecting it by hand — copy-pasting prices and addresses suburb by suburb — is slow, error-prone and impossible to keep fresh day over day.

This **Domain.com.au scraper** does it for you in seconds. Point it at any suburb (or paste a Domain search URL), hit Start, and it returns a clean, de-duplicated, analytics-ready dataset you can download or pipe straight into your warehouse, CRM or dashboard.

**Common reasons people scrape Domain.com.au:**

- 🏠 **Suburb comp scans** — pull every active 3-bed house in a suburb and compare against last week's run
- 🔨 **Auction pipelines** — assemble Saturday-auction lists with dates, agents and guides per metro
- 📉 **Price-reduction tracking** — a leading indicator of softening markets and motivated vendors
- 📍 **Mapping & heatmaps** — every record carries `latitude`/`longitude` for choropleths and proximity analysis
- 📞 **Agent & agency lead-gen** — `agentName`, `agentPhone` (mobile), `agentProfileUrl`, `agencyName` ready for a CRM
- 💰 **Rent & yield analytics** — weekly rents by bedroom count and property type per postcode
- 🎓 **Relocation & school-catchment research** — filter family-friendly suburbs by catchment and beds

***

### ✨ What this Domain.com.au scraper does

The actor fetches Domain search-result pages and (optionally) individual listing pages over high-speed **HTTP/2 — no headless browser** — and extracts the structured property data directly. It then normalizes and flattens every record and pushes it to your Apify dataset.

- ✅ **Three listing modes** — `sale`, `rent` and `sold` listings from any Australian suburb
- ✅ **Flexible targeting** — a 28-suburb picker of capital-city and prestige areas, a free-text `customSuburbs` field for any `suburb-state-postcode` slug, or paste ready **Domain.com.au** search / listing **Start URLs**
- ✅ **Server-side filters** — property type, min/max bedrooms, min/max price, and auction-only
- ✅ **Automatic deep pagination** — walks result pages suburb-by-suburb and returns **hundreds to thousands of de-duplicated listings** (deduped on Domain's `listingId`), controlled by `maxListings` and `maxPages` (`0` = unlimited)
- ✅ **Rich core fields on every card** — `listingId`, `url`, full `address`, `suburb`, `state`, `postcode`, `latitude`, `longitude`, `priceDisplay` + parsed `price`/`priceType`, `propertyType`, `bedrooms`, `bathrooms`, `carSpaces`, `landSize`, `agentName`, `agencyName`, `agentPhoto`, the `images` gallery, plus `tags` and the `isAuction` / `isNewListing` / `isPriceReduced` / `isUnderContract` / `isHotProperty` flags
- ✅ **Optional deep detail** (`scrapeDetails: true`) — visits each listing page for `description`, `headline`, structured `features`, `inspectionTimes`, `schoolCatchments`, `agentPhone`, `agentProfileUrl`, `dateListed`, `daysOnMarket` and `status`
- ✅ **Multi-format price parser** — turns `Auction`, `Offers Over $785,000`, `$839,000 - $869,000`, `$650 pw`, `Contact Agent`, `EOI`, `Guide` and more into a canonical numeric `price` + `priceType` enum
- ✅ **Resilient extraction** — automatic session rotation over **AU residential** IPs with retry handling so parallel suburb searches never drop pages
- ✅ **Export anywhere** — **JSON, CSV, Excel, XML, HTML** or the Apify **API**

> **Freshly verified:** a broad 6-metro run returned **401 de-duplicated listings in 46 seconds** with **0 duplicate `listingId`s** and no value bugs; on a targeted multi-suburb run, standard listings returned `priceDisplay`, `propertyType`, `address`, `agentName`, `agencyName`, `images`, `latitude`/`longitude` and the `beds`/`baths` count at ~100%.

***

### 🎯 Use cases

- **Property investors & buyer's agents** — suburb comp scans, auction-watch pipelines, stale-listing / motivated-vendor finders (`daysOnMarket` + `isPriceReduced`), and hyper-local rent analytics for yield models.
- **Valuers, appraisers & mortgage brokers** — build comparable-sales bundles with `soldPrice`, `bedrooms`, `bathrooms`, `landSize`; pre-populate LMI and broker comparison sheets; track market velocity by `daysOnMarket`.
- **PropTech apps & real-estate portals** — a structured-data backbone with parsed price guides and normalized property types; saved-search diff alerts; AVM training data from recent sold prices.
- **Real-estate agencies & vendor advocates** — benchmark agency market share per suburb, recruit performing agents by listing volume, and enrich CRM feeds with current inventory.
- **Mortgage brokers & lenders** — pipeline outreach to premium-listing agents, refinance triggers from recent nearby sales, and first-home-buyer concierge curation under a price threshold.
- **Relocation & migration services** — brief inbound expats with rent ranges, filter family-friendly suburbs by `schoolCatchments`, and map proximity to an employer using `latitude`/`longitude`.
- **Journalists & data reporters** — same-day Saturday auction lists, price-reduction trend tracking, and agency league tables.
- **Academic & government housing research** — rental-affordability quartiles, housing-supply mapping, and auction-vs-private-treaty market-temperature indicators.

***

### 📥 Input

Pick a **Listing Type** and one or more **suburbs**, then optionally add filters. Leave everything as-is and click **Start** for a ready mixed sample across major capital cities — no setup required.

| Parameter | Type | Description |
|---|---|---|
| `listingType` | string (enum) | `sale`, `rent`, or `sold`. Drives which Domain section is searched. Default `sale`. |
| `suburbs` | array\<string> | One or more suburb slugs from the dropdown (28 capital-city & prestige areas, e.g. `bondi-beach-nsw-2026`, `south-yarra-vic-3141`, `surfers-paradise-qld-4217`). Defaults to a Sydney/Melbourne/Brisbane sample. |
| `customSuburbs` | array\<string> | Advanced. Any extra suburb not in the dropdown, in `name-state-postcode` form (e.g. `manly-nsw-2095`, `new-farm-qld-4005`). |
| `startUrls` | array\<string> | Advanced. Paste ready Domain.com.au search or individual listing URLs for fully custom filtered searches. |
| `propertyTypes` | array\<string> | Filter to `house`, `apartment`, `townhouse`, `villa`, `land`, `rural`, `unitBlock`, `retire`, `studio`. Empty = all types. |
| `minBedrooms` / `maxBedrooms` | integer | Bedroom range (0 = no limit). |
| `minPrice` / `maxPrice` | integer | Price range in AUD (for rentals, interpreted as weekly rent; 0 = no limit). |
| `auctionOnly` | boolean | When `true`, keep only listings going to auction. Default `false`. |
| `scrapeDetails` | boolean | When `true`, visit each listing page for description, features, inspection times, school catchments, agent phone & profile. Richer but slower. Default `false`. |
| `maxListings` | integer | Hard cap on total listings across all suburbs. `0` = unlimited (`1,000+` supported). A bare default run is auto-capped at a ~120-listing mixed sample. Prefill `100`. |
| `maxPages` | integer | Max result pages per suburb (each page ≈ 20 listings). `0` = unlimited (governed by `maxListings`). Default `0`. |
| `proxyConfiguration` | object | Apify proxy. **Australian residential is the default and strongly recommended** — Domain blocks datacenter IPs and geo-restricts non-AU traffic. |
| `requestDelay` | integer (ms) | Delay between requests. Keep above 1000 ms for reliability. Default `1500`. |
| `maxConcurrency` | integer | How many suburbs to search in parallel (1–10). Default `2`. |

#### Example input

```json
{
  "listingType": "sale",
  "suburbs": [
    "bondi-beach-nsw-2026",
    "south-yarra-vic-3141",
    "surfers-paradise-qld-4217"
  ],
  "customSuburbs": ["new-farm-qld-4005"],
  "propertyTypes": ["house", "apartment"],
  "minBedrooms": 2,
  "maxBedrooms": 4,
  "minPrice": 800000,
  "maxPrice": 3500000,
  "auctionOnly": false,
  "scrapeDetails": true,
  "maxListings": 300,
  "maxPages": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "AU"
  },
  "requestDelay": 1200,
  "maxConcurrency": 3
}
```

***

### 📤 Output

Every record uses one flat schema regardless of `sale` / `rent` / `sold`, so downstream warehouses ingest the whole dataset without branching logic. Fields are `null` when the underlying listing omits them.

#### Example output item (search mode — fields on every card)

```json
{
  "listingId": "2021290672",
  "listingType": "sale",
  "saleMethod": null,
  "url": "https://www.domain.com.au/604-12-16-weemala-street-surfers-paradise-qld-4217-2021290672",
  "promoType": "premiumplus",
  "price": null,
  "priceType": "unknown",
  "priceDisplay": "Submit All Offers. Must be sold!",
  "priceMin": null,
  "priceMax": null,
  "isAuction": false,
  "auctionDate": null,
  "address": "604/12-16 Weemala Street",
  "suburb": "Surfers Paradise",
  "state": "QLD",
  "postcode": "4217",
  "latitude": -27.998634,
  "longitude": 153.42148,
  "propertyType": "Apartment / Unit / Flat",
  "bedrooms": 2,
  "bathrooms": 2,
  "carSpaces": 2,
  "landSize": null,
  "agentName": "Tayla Moody",
  "agencyName": "Ray White Malan + Co - Broadbeach",
  "agentPhoto": "https://rimh2.domainstatic.com.au/.../contact_2029394.jpeg",
  "tags": ["New"],
  "isNewListing": true,
  "isPriceReduced": false,
  "images": [
    "https://rimh2.domainstatic.com.au/.../2021290672_1_1_261031_023719-w1920-h1280",
    "https://rimh2.domainstatic.com.au/.../2021290672_2_1_261031_023719-w1920-h1280"
  ],
  "searchSuburb": "surfers-paradise-qld-4217",
  "searchType": "sale",
  "scrapedAt": "2026-11-01T23:40:33.690Z"
}
```

#### Example output item (detail mode — `scrapeDetails: true`)

```json
{
  "listingId": "2021270427",
  "listingType": "sale",
  "url": "https://www.domain.com.au/64-warners-avenue-bondi-beach-nsw-2026-2021270427",
  "price": 2500000,
  "priceType": "auction",
  "priceDisplay": "Auction Guide $2,500,000",
  "isAuction": true,
  "address": "64 Warners Avenue",
  "suburb": "Bondi Beach",
  "state": "NSW",
  "postcode": "2026",
  "propertyType": "House",
  "bedrooms": 3,
  "bathrooms": 2,
  "carSpaces": 1,
  "agentName": "Oliver Lavers",
  "agentPhone": "0411 294 232",
  "agentProfileUrl": "https://www.domain.com.au/real-estate-agent/oliver-lavers-1632498",
  "agencyName": "TRG",
  "headline": "Classic Bondi Charm with Exceptional Potential in Prized Pocket",
  "description": "Rich in original period charm and character, this c1930s semi presents an outstanding opportunity...",
  "features": ["Swimming Pool", "Secure Parking", "Balcony / Deck", "Dishwasher"],
  "inspectionTimes": [
    "2026-10-29T09:00:00 - 2026-10-29T09:30:00",
    "2026-10-31T09:00:00 - 2026-10-31T09:30:00"
  ],
  "dateListed": "2026-10-23T13:12:13.023",
  "daysOnMarket": 2,
  "status": "new",
  "images": ["https://rimh2.domainstatic.com.au/.../2021270427_1_1_261023_021213-w3497-h2389"]
}
```

#### Field reference

**Identifiers & URLs**

| Field | Description |
|---|---|
| `listingId` | Domain's internal listing ID — stable across runs, ideal for dedup and change detection |
| `url` | Canonical listing URL on domain.com.au |
| `listingType` / `searchType` | `sale`, `rent` or `sold` |
| `saleMethod` | `auction` on search-mode auctions; richer values (`privateTreaty`, `eoi`, …) when `scrapeDetails` is on and Domain supplies them |
| `promoType` | Domain's promotion tier (`standard`, `premium`, `premiumplus`, `eliteProject`, …) |
| `status` | Listing status (`new`, `active`, `underContract`, …) — populated on detail runs |

**Pricing**

| Field | Description |
|---|---|
| `price` | Normalized numeric price in AUD (weekly rent for rentals). `null` when the listing shows text only (e.g. "Auction", "Contact Agent") |
| `priceType` | Parsed price type — `fixed`, `range`, `guide`, `offersOver`, `auction`, `eoi`, `contactAgent`, `perWeek`, `perWeekRange`, `unknown` |
| `priceDisplay` | Original display string ("Auction Guide $2,500,000", "$839,000 - $869,000", "$650 pw") |
| `priceMin` / `priceMax` | Lower/upper bound when the display is a range |
| `priceGuide` | Free-text estimated-price guide (detail mode, when present) |
| `soldPrice` / `soldDate` | Final sale price & date (sold listings where the agent discloses them) |

**Address & geo**

| Field | Description |
|---|---|
| `address` | Street address as displayed (may be partial pre-launch) |
| `suburb` / `state` / `postcode` | Suburb name, two-letter state code, 4-digit postcode |
| `latitude` / `longitude` | Precise map coordinates — present on virtually every record |
| `councilArea` | Local Government Area (detail mode, when disclosed) |

**Property attributes**

| Field | Description |
|---|---|
| `propertyType` | `House`, `Apartment / Unit / Flat`, `Townhouse`, `Villa`, `Land`, `Rural`, etc. |
| `bedrooms` / `bathrooms` / `carSpaces` | Counts (integers) |
| `landSize` / `buildingSize` | Size in m² where the agent lists it |

**Agent & agency**

| Field | Description |
|---|---|
| `agentName` | Primary listing agent |
| `agentPhone` | Agent's published mobile (detail mode) |
| `agentPhoto` | Agent headshot image URL |
| `agentProfileUrl` | Agent's Domain profile page (detail mode) |
| `agencyName` | Agency / brokerage brand |
| `agencyWebsite` / `agencyProfileUrl` | Agency links (detail mode, when Domain exposes them) |

**Rich detail (populated on `scrapeDetails: true`)**

| Field | Description |
|---|---|
| `headline` | Agent-written listing headline |
| `description` | Full listing description text |
| `features` | Array of feature strings (e.g. `"Swimming Pool"`, `"Secure Parking"`, `"Dishwasher"`) |
| `inspectionTimes` | Array of open-home strings (e.g. `"2026-10-29T09:00:00 - 2026-10-29T09:30:00"`), or `["By Appointment Only"]` |
| `schoolCatchments` | Array of catchment-school strings (e.g. `"Bondi Beach Public School (Primary, Government)"`) when Domain lists them |
| `images` | Full-resolution image URLs |
| `floorplanUrl` / `virtualTourUrl` | Floor-plan and 3D-tour/video URLs, when the agent uploads them |
| `nbnConnection` / `energyRating` | Free-text, agent-disclosed — frequently `null` |
| `dateListed` / `daysOnMarket` | First-listed timestamp and days on market |

**Flags & metadata**

| Field | Description |
|---|---|
| `tags` | Raw Domain tag strings (`New`, `Hot Property`, `Price Reduced`, `Under Contract`) |
| `isAuction` / `isNewListing` / `isPriceReduced` / `isUnderContract` / `isHotProperty` | Convenience booleans derived from the listing |
| `auctionDate` / `auctionLocation` | Auction date (ISO-8601) and venue, for auction listings |
| `searchSuburb` | The suburb slug used in the request (traces records back to inputs) |
| `scrapedAt` | ISO-8601 extraction timestamp |

> **Honest note on coverage.** Core fields (`listingId`, `url`, `address`, `suburb`, `state`, `postcode`, `latitude`, `longitude`, `priceDisplay`, `priceType`, `propertyType`, `beds`/`baths`, `agentName`, `agencyName`, `images`) return at or near **100%** on standard listings. Some fields are intentionally conditional: numeric `price` is `null` whenever a listing shows text only ("Auction", "Contact Agent", "Submit All Offers") — the text is always preserved in `priceDisplay`. `soldPrice`/`soldDate` apply to sold listings; `auctionDate`/`auctionLocation` to auctions. `description`, `features`, `agentPhone`, `inspectionTimes`, `schoolCatchments`, `floorplanUrl`, `nbnConnection` and `energyRating` come from the detail page (`scrapeDetails: true`) and depend on what the agent discloses — several (school catchments, floor plan, NBN, energy, agent email) are often sparse because Domain does not reliably publish them. **Project / off-the-plan development** listings (`/project/...` URLs, common when searching whole-metro "region" slugs) describe a building rather than one unit, so they legitimately carry no per-unit price or bed/bath count but still return address, geo, agency and images.

***

### 🔁 Pagination & scale

Each Domain search page returns about **20 listings**. For every suburb (or Start URL) the actor discovers `totalPages` / `totalListings`, then walks pages `1..N` — appending `?page=N` — until it hits `maxPages` (default `0` = unlimited), the global `maxListings` cap, the last real page, or an empty page. Independent suburbs run in a small staggered worker pool (`maxConcurrency`) for fast parallel extraction.

All records are **de-duplicated on `listingId`** within a run (the fresh verification returned 401 and 80 listings with **zero** duplicates). When a user requests `maxListings: 1000+` and the initial suburbs finish all their pages before reaching `maxListings`, the scraper automatically expands across major Australian regions so your target count is reached.

***

### ⚙️ How to use

1. **On Apify Console** — open the actor, pick a **Listing Type** and one or more **suburbs** (or paste a Domain search URL in **Start URLs**), set `maxListings`, and click **Start**. Keep the default **AU residential** proxy.
2. **Choose an export** — download results as **JSON, CSV, Excel, XML or HTML** from the dataset tab.
3. **Via API** — `POST https://api.apify.com/v2/acts/haketa~domain-com-au-scraper/runs?token=YOUR_TOKEN` with your input JSON, then fetch items from the run's `defaultDatasetId`.
4. **On a schedule** — use Apify's Scheduler (hourly/daily/weekly/cron) to keep a dataset fresh.
5. **Integrate** — wire the Apify **Make / Zapier / n8n** connectors, the **Google Sheets** integration, or a **webhook** into Postgres/Snowflake/BigQuery, Slack, or your CRM.

#### API example (Python)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("haketa/domain-com-au-scraper").call(run_input={
    "listingType": "sale",
    "suburbs": ["bondi-beach-nsw-2026", "south-yarra-vic-3141"],
    "propertyTypes": ["house", "apartment"],
    "scrapeDetails": True,
    "maxListings": 200,
    "maxPages": 0,
})
for rec in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(rec["address"], "—", rec["priceDisplay"], f"({rec['bedrooms']}br/{rec['bathrooms']}ba)")
```

#### API example (cURL)

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~domain-com-au-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "listingType": "sold",
    "suburbs": ["south-yarra-vic-3141"],
    "propertyTypes": ["house"],
    "scrapeDetails": true,
    "maxListings": 100,
    "maxPages": 0
  }'
```

***

### 💡 Tips

- **Pick specific suburbs** for the cleanest data — whole-metro "region" slugs (`sydney-region-nsw`) mix in many off-the-plan **project** listings that carry no per-unit price/beds.
- **Turn on `scrapeDetails`** when you need description, features, agent phone, inspection times or days-on-market — but leave it off for fast, cheap price/address/geo sweeps.
- **Build an auction watch** by combining `auctionOnly: true` with `scrapeDetails: true` to get `auctionDate` + guide + agent per suburb.
- **Filter prices downstream** — Australian listings often show text instead of a number; use `priceType` and `priceDisplay` alongside numeric `price` so you never drop a "Contact Agent" listing.
- **Use `startUrls`** to leverage Domain's own URL filters (`bedrooms=`, `price=`, `excludeunderoffer=1`) when you need a combination the picker doesn't expose.
- **Keep AU residential + `requestDelay` ≥ 1000 ms** — it keeps multi-page extraction smooth and reliable.

***

### ❓ FAQ

**How many results can I get, and how fast?**
There's no hard cap. A broad 6-metro verification run returned **401 de-duplicated listings in about 46 seconds** (search mode). Set `maxListings: 1000` (or `0` for unlimited) with `maxPages: 0` for deep metro-wide runs; detail-enriched runs add one extra fetch per listing.

**Do I need proxies or a login?**
No login or API key — just an Apify token. Proxies **are** needed: Domain geo-restricts non-AU traffic, so the actor defaults to **Australian residential** proxy. Keep that default.

**What export formats are supported?**
**JSON, CSV, Excel, XML and HTML**, plus the Apify dataset **API** and webhooks.

**Is there a Domain.com.au API?**
Domain's own API is gated behind a commercial partner agreement. This actor is a turnkey **Domain.com.au API** alternative: run it on demand or on a schedule and read results via Apify's REST API.

**How fresh is the data?**
Live at run time. Whatever is visible on domain.com.au the moment the actor runs is what lands in your dataset. Schedule it to track changes day over day.

**Can I filter by price, bedrooms or property type?**
Yes — `minPrice`/`maxPrice`, `minBedrooms`/`maxBedrooms` and `propertyTypes` filter server-side. Land size, building size and features are returned as fields; filter those downstream in SQL/Sheets/Pandas, or use `startUrls` with Domain's own URL filters.

**Does it handle sold listings and auctions?**
Yes. Set `listingType: "sold"` for recently-sold properties (with `soldPrice`/`soldDate` where disclosed), or use `auctionOnly: true` to keep only auction listings with `auctionDate`.

**Why is numeric `price` empty on some listings?**
Because the listing shows text, not a number ("Auction", "Contact Agent", "Offers Over $785,000" parses, "Submit All Offers" doesn't). The display text is always preserved in `priceDisplay`, and `priceType` tells you which convention it used.

**Can I extract agent contact details?**
Yes — `agentName`, `agentPhoto` and `agencyName` come on every card, and `agentPhone` (mobile) + `agentProfileUrl` populate on detail runs (`scrapeDetails: true`). Agent **email** is only occasionally present; treat it as a bonus rather than a guarantee.

**Does this work for realestate.com.au?**
No — this actor is Domain-specific.

***

### 🔗 Related scrapers

Need property data from other countries — or marketplaces that pair well with Australian property research? These companion scrapers by **haketa** cover the most-requested catalogues:

- [Realtor.ca Scraper (Canada)](https://apify.com/haketa/realtor-ca-scraper) — Canadian MLS listings across all provinces
- [ImmobilienScout24 Scraper (Germany)](https://apify.com/haketa/immobilienscout24-scraper) — Germany's largest property marketplace
- [Daft.ie Scraper (Ireland)](https://apify.com/haketa/daft-scraper) — Irish homes and rentals nationwide
- [Immoweb.be Property Scraper (Belgium)](https://apify.com/haketa/immoweb-scraper) — Belgian residential & commercial
- [Boliga Scraper (Denmark)](https://apify.com/haketa/boliga-scraper) — Danish listings & sold prices
- [Apartments.com Scraper (US)](https://apify.com/haketa/apartments-com-scraper) — US apartment marketplaces
- [SEEK Scraper (Australia/NZ)](https://apify.com/haketa/seek-scraper) — Australian job listings for relocation use cases

***

### 📋 Changelog

- **v1.3 (2026-11)** — Changed `maxPages` default from `5` to `0` (unlimited pages per suburb governed by `maxListings`), added automatic multi-region expansion so `maxListings: 1000+` runs always reach full target volume, added `maxItems` input alias support, and updated documentation with `⚡ At a glance` summary.
- **v1.2 (2026-07)** — Added parallel suburb worker pool (`maxConcurrency`), soft-block detection with fresh-IP retry, and multi-format AUD price parser (`auction`, `offersOver`, `range`, `guide`, `eoi`, `perWeek`).
- **v1.0 (2026-04)** — Initial release supporting Domain.com.au `sale`, `rent`, and `sold` listings, 28 built-in Australian suburbs, custom suburb slugs, and optional `scrapeDetails` enrichment.

# Changelog

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

# Actor input Schema

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

What kind of listings do you want? Properties for sale, rentals, or recently sold homes.

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

Pick one or more popular Australian suburbs and regions to search. Leave everything as-is to run a ready mixed sample across major capital cities.

## `customSuburbs` (type: `array`):

Optional. Add extra suburbs not in the dropdown above. Format: suburb-state-postcode, e.g. manly-nsw-2095 or south-yarra-vic-3141. Leave empty unless you need a specific suburb.

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

Optional. Paste ready Domain.com.au search or listing page links for fully custom filtered searches. Most users can leave this empty and use the suburb picker above.

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

Filter to specific property types, or leave empty to include all types.

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

Only show properties with at least this many bedrooms. Leave at 0 for no minimum.

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

Only show properties with at most this many bedrooms. Leave at 0 for no maximum.

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

Only show properties priced at or above this amount. Leave at 0 for no minimum.

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

Only show properties priced at or below this amount. Leave at 0 for no maximum.

## `auctionOnly` (type: `boolean`):

Turn on to keep only properties going to auction.

## `scrapeDetails` (type: `boolean`):

Turn on to visit each listing page for extra data: full description, features, inspection times, school catchments and floor plans. More complete, but slower.

## `maxListings` (type: `integer`):

Total number of listings to collect across all suburbs. Set 0 for unlimited.

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

How many result pages to read per suburb. Each page returns about 20 listings. Set 0 for unlimited (governed by Max Listings).

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

Proxy settings. Australian residential proxies are strongly recommended for reliable results — keep the default.

## `requestDelay` (type: `integer`):

Delay between requests in milliseconds. Keep above 1000 for reliable results.

## `maxConcurrency` (type: `integer`):

How many suburbs to search at the same time. Higher finishes faster; lower is gentler on the site. Leave empty for the recommended default.

## Actor input object example

```json
{
  "listingType": "sale",
  "suburbs": [
    "sydney-nsw-2000",
    "melbourne-vic-3000",
    "brisbane-city-qld-4000"
  ],
  "customSuburbs": [],
  "startUrls": [],
  "propertyTypes": [],
  "minBedrooms": 0,
  "maxBedrooms": 0,
  "minPrice": 0,
  "maxPrice": 0,
  "auctionOnly": false,
  "scrapeDetails": false,
  "maxListings": 100,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  },
  "requestDelay": 1500,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All extracted Domain.com.au property records for this run.

## `overviewTable` (type: `string`):

A clean, human-readable table of the scraped properties.

# 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 = {
    "suburbs": [
        "sydney-nsw-2000",
        "melbourne-vic-3000",
        "brisbane-city-qld-4000"
    ],
    "customSuburbs": [],
    "startUrls": [],
    "maxListings": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AU"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/domain-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 = {
    "suburbs": [
        "sydney-nsw-2000",
        "melbourne-vic-3000",
        "brisbane-city-qld-4000",
    ],
    "customSuburbs": [],
    "startUrls": [],
    "maxListings": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AU",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/domain-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 '{
  "suburbs": [
    "sydney-nsw-2000",
    "melbourne-vic-3000",
    "brisbane-city-qld-4000"
  ],
  "customSuburbs": [],
  "startUrls": [],
  "maxListings": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  }
}' |
apify call haketa/domain-com-au-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/domain-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/Tc4g3gH0nZR4bOMzE/builds/07IapOV5pwNaYa7bA/openapi.json
