# Domain.com.au $1.50/1k Property + Full Agent Data (/w EMAILS) (`memo23/domain-com-au-scraper`) Actor

Scrape Domain.com.au rent / sale / sold listings — 66 fields per row incl. coordinates, photos, school catchment, suburb profile + full agent enrichment (mobile, photo, lifetime sales/leasing stats). Pure HTTP via residential proxies, no browser. JSON or CSV out

- **URL**: https://apify.com/memo23/domain-com-au-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Real estate, Automation, Agents
- **Stats:** 72 total users, 16 monthly users, 100.0% runs succeeded, 1 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Domain.com.au — Rent, Sale & Sold Property + Agent Scraper

**The deepest Domain.com.au dataset on Apify.** One actor for rent / sale / sold listings, agents, and agencies — and every property row is built from Domain's own structured API, not brittle HTML scraping. Each listing row carries **66+ fields**: exact GPS coordinates, every photo + floorplan, the full nearby **school catchment** (~12 schools with sector, gender, distance), a **suburb profile**, **agent mobile + email inline**, and for sold listings the **actual sold price + date**. Agent and agency rows add **lifetime sales/leasing stats** and **individual customer reviews** (star rating, text, reviewer, date, property). Pure HTTP via residential proxies — no browser, no third-party services.

### How it works

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-domain.png" alt="How it works" width="100%" />
</p>

All-in-one Domain.com.au scraper — paste any mix of URL kinds in the same input list and the actor auto-classifies each one:

| Input | Row(s) emitted |
|---|---|
| **Rent listing** — `/rent/{suburb}-{state}-{postcode}/` | **N listing rows** — one per property (`rowType: "listing"`). Paginated automatically via `?page=N` (20 results per page). Each row carries the full property record + agency block + per-listing agent array + nearby school catchment (~13 schools) + suburb profile. |
| **Sale listing** — `/sale/{suburb}-{state}-{postcode}/` | Same flat-per-property pattern, `listingMode: "sale"`. May include `/project/...` new-development URLs in CBD areas — those emit a separate placeholder row (`rowType: "project"`). |
| **Sold listing** — `/sold-listings/{suburb}-{state}-{postcode}/` | Same flat-per-property pattern, `listingMode: "sold"`. Capped at 12 months by Domain (older sale history needs property-profile URLs — out of scope for v1). |
| **Filtered search** — `/sale/melbourne-region-vic/house/3-bedrooms/?bathrooms=2-any&price=200000-9000000&carspaces=5-any&landsize=12138-4046000&features=builtinwardrobes` | Every Domain UI filter is supported — deep filter paths and query-string filters both pass through unchanged. The classifier reads the leading `/rent/`, `/sale/`, or `/sold-listings/` segment and routes accordingly. |
| **Property detail URL** — `/{slug}-{state}-{postcode}-{listingId}` | 1 listing row, no pagination. Useful for refreshing a known listing or scraping bookmarked properties. |
| **Agent profile URL** — `/real-estate-agent/{slug}-{agentId}` | 1 agent row (`rowType: "agent"`) with full contact details, lifetime sales + leasing counts, recent listing IDs, bio. |
| **Agency profile URL** — `/real-estate-agencies/{slug}-{agencyId}` | 1 agency row (`rowType: "agency"`) — name + branding (logo, hero image, colours), contact (phone / mobile / email / address), social (web / Facebook / Twitter / Instagram / LinkedIn / YouTube / video URL), full agent roster with each agent's phone + mobile + photo, lifetime stats (forSale / forRent / sold / leased / auctioned), reviews (overall star rating + count), suburb stats (median sold price, average days on market, total sale amount), active-suburbs list, REINSW badge flag, HTML-stripped description. |

Mix any of these in the same `startUrls[]` array — the actor auto-classifies each one. JSON + CSV.

> **Listing rows are flat with the agents denormalized into every row.** Each property's `agentsEnriched[]` array carries every agent's full profile inline (no separate agent rows from listing URLs). Agents are deduped by ID across the run, so 50 listings sharing one agent = 1 agent fetch, not 50.

> Pure HTTP. No Playwright, no Puppeteer, no headless Chromium, no third-party services.

***

Under the hood the actor is built around a tight HTTP recipe with residential proxy routing, automatic retry on transient errors, and structured data parsing from each page's server-rendered state. End-to-end live test: **5/5 properties** parsed with full agent enrichment, **0 hard failures**, **0 stale rows**. Specifically:

1. **Residential proxy routing** — every request is routed through a rotating residential pool. Datacenter IPs aren't used. Defaults to Apify Residential with `country=AU`; user can override via `input.proxy`.
2. **Auto retry on transient errors** — listing pages occasionally return thin or empty bodies. The actor detects that and retries with a fresh session before giving up.
3. **Structured page parsing** — every Domain page ships rich server-rendered state with the full property record, school catchment, suburb profile, agency block, and per-listing agent array. The parser reads that directly — no DOM execution, no client-side script wait, no fragile CSS selectors.
4. **Agent dedupe cache** — each unique agent ID is fetched at most once per run, then merged into every listing that references them.
5. **Native pagination** — page navigation uses Domain's own page counters; the walk stops at `totalPages` or `maxItems`, whichever comes first.

***

### Input

Field | Type | Required | Notes
\--- | --- | --- | ---
`startUrls` | `string[]` | yes | Any mix of listing / detail / agent URLs (or bare query-string-filtered URLs). Auto-classified.
`enrichAgent` | `boolean` | no | Default `true`. Fetches each unique agent profile to populate `agentsEnriched[]` with full contact details + lifetime stats + bio. Cached by agent ID, so duplicate references across listings share one fetch. Disable for cheaper property-only runs (~40% faster).
`maxItems` | `integer` | no | Safety cap on **total dataset rows**, not URLs. A rent URL with 935 results emits up to 935 listing rows. Default `200`. Free-tier users are capped at `100`.
`maxConcurrency` | `integer` | no | Detail pages fetched in parallel. Default `8`. Sweet spot 6–10.
`minConcurrency` | `integer` | no | Minimum parallelism. Default `1`.
`maxRequestRetries` | `integer` | no | Per-URL retry budget. Transient errors are auto-detected and don't count against this. Default `5`.
`proxy` | `object` | no | Default: Apify Residential AU (`{ useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"], apifyProxyCountry: "AU" }`). Override with your own residential pool if desired.

#### Example input

```json
{
  "startUrls": [
    "https://www.domain.com.au/rent/sydney-nsw-2000/",
    "https://www.domain.com.au/sale/melbourne-vic-3000/?bedrooms=2-any&price=0-800000",
    "https://www.domain.com.au/sold-listings/brisbane-city-qld-4000/",
    "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
    "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822/"
  ],
  "enrichAgent": true,
  "maxItems": 500,
  "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "AU" }
}
```

That yields up to **500 rows**: rent + sale + sold listings paginated through, 1 direct detail row, and 1 standalone agent row. The agent referenced by the 38 Bridge St listing is deduped against any earlier listing referencing the same agent.

***

### Output schema

Four row shapes, distinguished by the `rowType` field: `listing`, `agent`, `agency`, `project`.

#### `rowType: "listing"`

```jsonc
{
  "rowType":             "listing",
  "sourceUrl":           "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
  "canonicalUrl":        "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
  "listingId":           18121983,
  "listingMode":         "rent",            // "rent" / "sale" / "sold"
  "listingType":         "RESIDENTIAL",     // RESIDENTIAL / COMMERCIAL / RURAL / PROJECT
  "status":              "LIVE",            // LIVE / LEASED / SOLD / WITHDRAWN

  "headline":            "Furnished CBD studio with city views",
  "description":         "...HTML-stripped, line-break-preserving body...",
  "propertyType":        "APARTMENT_UNIT_FLAT",
  "propertyTypes":       ["APARTMENT_UNIT_FLAT"],
  "bedrooms":            1,
  "bathrooms":           1,
  "carspaces":           0,
  "landAreaSqm":         null,
  "buildingAreaSqm":     null,
  "isRural":             false,
  "energyEfficiencyRating": null,
  "structuredFeatures": [
    { "category": "Indoor", "name": "Built in wardrobes", "source": "SUGGESTED" }
    /* up to ~20 features */
  ],

  "address": {
    "displayAddress":    "38 Bridge St, Sydney NSW 2000",
    "streetNumber":      "38",
    "unitNumber":        null,
    "street":            "Bridge St",
    "suburb":            "Sydney",
    "state":             "NSW",
    "postcode":          "2000",
    "lat":               -33.8632149,
    "lng":               151.2106999
  },

  "priceDisplay":        "$800 per week",
  "priceExact":          800,
  "priceFrom":           null,
  "priceTo":             null,
  "canDisplayPrice":     true,
  "bondAmount":          3200,                  // rent only — null for sale/sold

  "dateListed":          "2026-05-15T16:03:18+10:00",
  "dateCreated":         "2026-05-15T15:42:11",
  "dateUpdated":         "2026-05-15T16:03:18",
  "dateAvailable":       "2026-05-20T00:00:00",
  "leasedDate":          null,                  // rent only when LEASED
  "soldDate":            null,                  // sale/sold only

  "photos":              [ /* up to ~30 imgix-hosted CDN URLs */ ],
  "floorplans":          [],
  "photosCount":         7,
  "floorplansCount":     0,
  "hasPhoto":            true,
  "hasFloorplan":        false,
  "virtualTourUrl":      null,
  "matterportUrl":       null,

  "inspections": [
    { "openingDateTime": "2026-05-18T10:00:00", "closingDateTime": "2026-05-18T10:30:00" }
  ],
  "inspectionsCount":              1,
  "inspectionByAppointmentOnly":   false,
  "auctionDateTime":               null,        // auction sale listings only
  "saleMethod":                    null,        // PRIVATE_TREATY / AUCTION / EOI / etc.

  "agency": {
    "agencyId":           6877,
    "name":               "Sydney Cove Property",
    "phone":              "02 92411288",
    "website":            "http://www.sydneycoveproperty.com.au/",
    "profileUrl":         "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877",
    "logoUrl":            "https://rimh2.domainstatic.com.au/...",
    "bannerUrl":          "https://rimh2.domainstatic.com.au/...",
    "backgroundColour":   "#FFFFFf",
    "isArchived":         false
  },
  "agentNames":          ["Cherie Xue", "Robert McFadden"],
  "agentIds":             [1487822, 1951517],
  "agentsEnriched": [
    {
      "agentId":             1487822,
      "agentIdInternal":     "6877-A31464",
      "fullName":            "Cherie Xue",
      "jobTitle":            "Sales representative",
      "profileTier":         "platinum",
      "hasEmail":            true,
      "mobileNumber":        null,
      "landlineNumber":      "02 9241 1288",
      "photoUrl":            "https://rimh2.domainstatic.com.au/.../contact_1487822.jpeg",
      "agencyId":            6877,
      "agencyName":          "Sydney Cove Property",
      "agencyAddress":       "Level 1 / 111 George St, The Rocks NSW 2000",
      "personalWebsiteUrl":  "http://sydneycoveproperty.com/agents/.../Cherie-Xue",
      "facebookUrl":         "https://www.facebook.com/Sydneycoveproperty",
      "twitterUrl":          "https://twitter.com/sydneycove",
      "instagramUrl":        "https://www.instagram.com/Sydney_Cove/",
      "linkedInUrl":         "",
      "youTubeChannelUrl":   "",
      "agentVideoUrl":       "https://www.youtube.com/watch?v=...",
      "totalForSale":        0,
      "totalForRent":        31,
      "totalSold":           0,
      "totalLeased":         147,
      "totalJointLeased":    101,
      "totalSoldAndAuctioned":  0,
      "recentListingIds":    [18122017, 18121983, 18118956 /* ... */],
      "bio":                 "Rui (Cherie) Xue - Licence No: ..."
    }
    /* + remaining agents on this listing */
  ],

  "schoolsCount": 13,
  "schools": [
    {
      "schoolId":          "4299",
      "name":              "Fort Street Public School",
      "educationLevel":    "primary",
      "sector":            "Government",
      "gender":            "CoEd",
      "yearRange":         null,
      "distance":          612.4,
      "distanceUnit":      "m",
      "rating":            null,
      "inCatchment":       true
    }
    /* + ~12 more, mix of primary and secondary, government and non-government */
  ],

  "suburbProfile": {
    "type":              "SUBURB",
    "address":           { "suburb": "Sydney", "state": "NSW", "postcode": "2000" },
    "statistics":        { /* median price, days-on-market, demographic highlights, property age distribution */ }
  },

  // Denormalised page-info flags (Domain's own digitalData layer)
  "daysListed":              0,
  "displayedLabels":         "New listing",
  "hasDescription":          true,
  "descriptionHasEmail":     false,
  "descriptionHasPhone":     true,
  "hasSOI":                  false,             // Statement of Information (Victoria-mandated)
  "hasDisplayPrice":         true,
  "hasVirtualTour":          false,

  "providerAdId":            "R2637954",        // Third-party feed ID
  "providerSystem":          "alchemy",

  // Search context — populated when the row came from a listing-URL fan-out.
  // `null` when the row came from a direct detail URL.
  "searchContext": {
    "discoveryUrl":  "https://www.domain.com.au/rent/sydney-nsw-2000/",
    "resultPosition": 1,              // 1-based position within the search page (1..20)
    "pageNumber":     1,
    "totalPages":     47,
    "totalResults":   935,             // total result count across all pages
    "mode":           "rent"           // rent / sale / sold
  },

  "scrapedAt":               "2026-05-15T20:39:45.418Z"
}
```

**Total fields per listing row: 66** (counting `agentsEnriched[]` items as one field, not N, and the `searchContext` block as one field).

#### `rowType: "agent"`

Emitted only when an agent profile URL is in `startUrls`. Standalone agent rows. The same agent data is also denormalized into every listing row's `agentsEnriched[]`, so you don't need to scrape agent URLs separately unless you want flat agent rows.

```jsonc
{
  "rowType":         "agent",
  "sourceUrl":       "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822",
  "agentId":         1487822,
  "agentIdInternal": "6877-A31464",
  "fullName":        "Cherie Xue",
  "jobTitle":        "Sales representative",
  "profileTier":     "platinum",                // platinum / gold / silver / standard
  "hasEmail":        true,
  "mobileNumber":    null,                      // null if agent only lists landline
  "landlineNumber":  "02 9241 1288",
  "photoUrl":        "https://rimh2.domainstatic.com.au/.../contact_1487822.jpeg",
  "agencyId":        6877,
  "agencyName":      "Sydney Cove Property",
  "agencyAddress":   "Level 1 / 111 George St, The Rocks NSW 2000",
  "personalWebsiteUrl": "http://sydneycoveproperty.com/agents/.../Cherie-Xue",
  "facebookUrl":     "https://www.facebook.com/Sydneycoveproperty",
  "twitterUrl":      "https://twitter.com/sydneycove",
  "instagramUrl":    "https://www.instagram.com/Sydney_Cove/",
  "linkedInUrl":     "",
  "youTubeChannelUrl": "",
  "agentVideoUrl":   "https://www.youtube.com/watch?v=...",
  // Lifetime stats from Domain's own ContactStatistics record
  "totalForSale":    0,
  "totalForRent":    31,
  "totalSold":       0,
  "totalLeased":     147,
  "totalSoldAndAuctioned":      0,
  "totalJointSoldAndAuctioned": 0,
  "totalJointLeased":           101,
  "totalAuctioned":             0,
  "recentListingIds": [18122017, 18121983, 18118956, 18118228 /* ... */ ],
  "bio":             "Rui (Cherie) Xue - Licence No: 2 0 3 0 3 4 6 8 Born in the Shandong Province in China, Cherie moved to Australia in 2006...",
  // Reviews (RateMyAgent) — aggregate + individual; empty when the agent has none
  "overallStarRating": 5,
  "numberOfReviews":   24,
  "reviews": [
    {
      "title":         "Professional and knowledgeable",
      "description":   "Cherie was fantastic from start to finish, kept us informed at every step...",
      "reviewerName":  "James W.",
      "starRating":    5,
      "isRecommended": true,
      "reviewType":    "vendor",              // vendor / buyer
      "reviewedOn":    "2024-08-14T10:21:00+10:00",
      "reviewUrl":     "https://www.ratemyagent.com.au/real-estate-agent/cherie-xue/reviews/...",
      "propertyType":  "Apartment", "bedrooms": 2, "bathrooms": 1, "carparks": 1,
      "streetAddress": "1203/...", "suburb": "Sydney", "state": "New South Wales", "postcode": "2000"
    }
    /* + more */
  ],
  "testimonials":    [],
  "scrapedAt":       "2026-05-15T20:39:45.418Z"
}
```

#### `rowType: "agency"`

Emitted when an agency profile URL is in `startUrls`. Standalone agency rows with the full agency record from Domain's Apollo Client state: branding, contact details, social URLs, lifetime portfolio statistics, suburb market stats, agent roster (with each agent's contact info), reviews, and active-suburbs list.

```jsonc
{
  "rowType":          "agency",
  "sourceUrl":        "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877",
  "agencyId":         6877,
  "agencyIdInternal": "QWdlbmN5OjY4Nzc=",          // Apollo Relay-style opaque id
  "name":             "Sydney Cove Property",
  "profileUrl":       "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877",
  "profileTier":      "platinum",                   // platinum / gold / silver / standard
  "depthTier":        "platinum",
  "isArchived":       false,
  "hasReinswBadge":   true,                         // NSW industry credential
  "description":      "Sydney Cove Property is Sydney's leading independent real estate agency specialising in prestige properties...",

  // Contact
  "phone":            "02 92411288",
  "mobile":           "",
  "email":            "info@sydneycoveproperty.com",
  "address":          "Level 1 / 111 George St, The Rocks NSW 2000",

  // Social + web presence
  "website":              "http://www.sydneycoveproperty.com.au/",
  "facebookUrl":          null,
  "twitterUrl":           null,
  "instagramUrl":         null,
  "linkedInUrl":          null,
  "youtubeChannelUrl":    null,
  "agencyVideoUrl":       "https://youtu.be/MVkdN6b34iI",

  // Branding
  "logoUrl":          "https://rimh2.domainstatic.com.au/.../logo_6877.GIF",
  "heroUrl":          "https://rimh2.domainstatic.com.au/.../hero_6877.jpeg",
  "backgroundColour": "#7da3c4",
  "logoColour":       "#7da3c4",

  // Lifetime statistics
  "totalForSale":           25,
  "totalForRent":           32,
  "totalSold":              84,
  "totalLeased":            270,
  "totalSoldAndAuctioned":  84,
  "totalAuctioned":         0,

  // Reviews — aggregate + individual reviews (sourced from RateMyAgent)
  "overallStarRating":  5,
  "numberOfReviews":    7,
  "reviewsProfileUrl":  "https://www.ratemyagent.com.au/real-estate-agency/sydney-cove-property-ao727/sales/overview",
  "reviewsLastUpdated": "2026-05-28T00:49:21",
  "reviews": [
    {
      "title":         "Exceptional CBD Agent",
      "description":   "Bryn is a 6 star agent. His ongoing efforts and updates are second to none...",
      "reviewerName":  "Gavin Shatford",
      "starRating":    5,
      "isRecommended": true,
      "reviewType":    "vendor",
      "reviewedOn":    "2021-06-02T15:03:55+10:00",
      "reviewUrl":     "https://www.ratemyagent.com.au/real-estate-agent/bryn-fowler/reviews/...",
      "propertyType":  "Apartment", "bedrooms": 2, "bathrooms": 1, "carparks": 0,
      "streetAddress": "605/4 Bridge Street", "suburb": "Sydney", "state": "New South Wales", "postcode": "2000"
    }
    /* + up to 5 recent reviews */
  ],

  // Suburb / market statistics (their primary trading area)
  "averageDaysOnMarket": 45.28,
  "averageSoldPrice":    1075739.13,
  "totalSaleAmount":     74226000,
  "activeSuburbs":       ["Sydney", "Darlinghurst", "Dolls Point", "Parramatta", "Woolloomooloo", "Baulkham Hills"],

  // Agent roster (full team for this agency)
  "agentsCount": 6,
  "agents": [
    {
      "agentId":        900362,
      "fullName":       "Bryn Fowler",
      "profileUrl":     "https://www.domain.com.au/real-estate-agent/bryn-fowler-900362",
      "landlineNumber": "02 8259 3333",
      "mobileNumber":   "0423 663 663",
      "photoUrl":       "https://rimh2.domainstatic.com.au/.../contact_900362.jpeg"
    }
    /* + 5 more agents */
  ],

  "scrapedAt":        "2026-05-19T20:00:00.000Z"
}
```

**Total fields per agency row: 38** (counting the `agents[]` and `reviews[]` arrays as one field each).

#### `rowType: "project"`

Emitted when Domain serves a `/project/{id}/{slug}/` URL inside a listing-search results page (common in CBD sale searches for new-development apartments). v1 emits a placeholder with the source URL; the full project schema (developer, available stock, completion date, price range) is on the v2 roadmap.

```jsonc
{
  "rowType":   "project",
  "sourceUrl": "https://www.domain.com.au/project/1923/380-melbourne-melbourne-vic/",
  "scrapedAt": "2026-05-15T20:39:45.418Z",
  "note":      "Project listing — full schema lands in v2. See sourceUrl for the page."
}
```

***

### Pricing

Pay-per-event. All nested data — photos, school catchment, suburb profile, agent enrichment, reviews — is bundled into the per-row price at no extra charge.

Event | When billed | Rate
\--- | --- | ---
**Actor start** (`apify-actor-start`) | Once when a run starts | **$0.05 / run**
**Result** (`apify-default-dataset-item`) | Each row pushed to the dataset (1 listing / agent / agency / project = 1 row) | **$1.50 / 1,000 rows**
**Additional data** (`additional-data`) | Only when optional email enrichment (`enrichEmails`) is enabled | **$0.0005 / enriched email**

A typical 1,000-row run costs **~$1.55** ($0.05 start + $1.50 results). That **undercuts every paid Domain scraper** on the Store (easyapi $2.99/1k + $0.09/run, agenscrape $2.50/1k) while returning the deepest schema — and one bundled actor replaces competitors' *separate* property and agent SKUs. Set `enrichAgent: false` for cheaper, property-only runs (the per-row rate is unchanged).

#### Free tier

Non-paying Apify users are capped at **100 items per run**. A paying account removes the cap (`maxItems` still applies, default `200`).

***

### What makes this richer than the competition

We surveyed the Domain.com.au actors on the Apify marketplace (May 2026). Most are running stale code from 2024 and have not kept pace with Domain's modernised site. This actor is a clean-slate build with substantially richer output:

Capability | Competitor actors | **This actor**
\--- | --- | ---
Built on Domain's **structured API** (not brittle HTML scraping) | ❌ (HTML scraping → breaks on site changes / soft-blocks) | ✅ block-resistant |
Returns reliable data on the live site (Jun 2026) | hit-and-miss | ✅ Live-tested clean |
**Individual customer reviews** for agents & agencies (rating, text, reviewer, date, property) | ❌ (none surface review text) | ✅ |
**Actual sold price + date** on sold listings (even when the display price is withheld) | partial | ✅ |
Three modes (rent + sale + sold) in **one actor** | ❌ (split across separate SKUs) | ✅ |
URL auto-classification (paste any mix) | ❌ | ✅ |
Pure HTTP, no headless browser | mixed (some use Puppeteer) | ✅ |
No paid third-party services | mixed | ✅ |
Per-listing **agent enrichment** (mobile, photo, lifetime stats, social, bio) | partial (1 actor surfaces names only) | ✅ |
**Agent dedupe cache** — each unique agent fetched once per run | ❌ (others either skip agents or re-fetch per listing) | ✅ |
**School catchment** included (~13 schools per listing) | ❌ | ✅ |
**Suburb profile** included (median price, demographics, market activity) | ❌ | ✅ |
Per-listing lat/lng from Domain's own geolocation | partial (some geocode externally) | ✅ |
Per-row **search context** (resultPosition, pageNumber, totalResults) | ❌ | ✅ |
Flat row shape — no nested arrays you have to flatten | mixed | ✅ |
Auto-paginates with native page counters | partial | ✅ |
66 fields per listing row | typical 12–25 | ✅ |

Most older Domain actors emit 12–25 fields per row and don't enrich agents. This actor returns property + agent + school + suburb data in one row, with strict freshness on Domain's current site behaviour.

***

### Notes & limitations

- **Site evolution.** Domain.com.au occasionally rotates its page structure or anti-bot policy. When that happens, the actor may need a 1-day patch. We monitor live runs and ship updates within 24–48 hours when behaviour shifts.
- **Listing rows carry the agent's real email and mobile.** Every agent attached to a rent, sale, or sold listing arrives with `email`, `mobileNumber`, and `landlineNumber` filled in — across 42,000+ agents seen this way, 99.9% had an email and 88% a mobile. Standalone **agent-profile rows** (`rowType: "agent"`, from `/real-estate-agent/` URLs) are the exception: that surface exposes `hasEmail: true|false` rather than the address itself, so scrape the agent through a listing when you want the email. Domain still hides some mobiles where the agent didn't opt in to public display (`mobileNumber: null`).
- **`/sold-listings/` caps at 12 months** by Domain. Older sale history needs `/property-profile/{slug}` URLs — out of scope for v1, on the v2 roadmap.
- **Commercial listings** live on `commercialrealestate.com.au` (a Domain sibling site) and are out of scope for v1.
- **New-development `/project/{id}/` listings** are emitted as placeholder rows (just `sourceUrl`). The full project schema lands in v2.
- **Apify free-tier cap** at 100 items per run. Upgrade to a paying plan to lift the cap.
- **Domain occasionally A/B tests** the page structure — we monitor parser drift and patch within 24–48 hours when fields shift.
- **No API alternative.** Domain Group runs a paid B2B Developer Portal with structured access. If you have enterprise volume and budget, that's the right path. This actor is for ad-hoc lead generation, market analytics, and pricing research — no contract, pay-per-row.

***

### Support

Issues, feature requests, or custom output shapes? Open a ticket on the actor's Apify page or message the maintainer.

***

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/domain-com-au-scraper`).

**Purpose:** Scrape Domain.com.au rent, sale, and sold listings plus individual property, agent, and agency profiles — built on Domain's own structured API, with agent enrichment, school catchment, and suburb profile bundled into each listing row.

**Minimal input:**

```json
{ "startUrls": ["https://www.domain.com.au/rent/sydney-nsw-2000/"], "maxItems": 25 }
```

Mix any URL kinds in `startUrls` — listing search (`/rent/`, `/sale/`, `/sold-listings/`, with query-string or deep-path filters), property detail, `/real-estate-agent/{slug}-{id}`, and `/real-estate-agencies/{slug}-{id}` are auto-classified.

**Output:** one row per unit, tagged by `rowType` (`listing` / `agent` / `agency` / `project`). Listing rows carry rowType, sourceUrl, listingId, listingMode, listingType, status, headline, description, propertyType, bedrooms, bathrooms, carspaces, address {displayAddress, suburb, state, postcode, lat, lng}, priceDisplay, priceExact, bondAmount, dateListed, photos, floorplans, agency {agencyId, name, phone, website}, agentNames, agentIds, agentsEnriched\[], schools\[], suburbProfile, searchContext, scrapedAt. Agent and agency rows add lifetime sales/leasing stats and individual reviews\[].

**Behaviors an agent should know:**

- Always set `maxItems` — it caps total dataset rows (default 200, free tier 100); a single rent URL can emit 900+ paginated rows.
- `enrichAgent` (default true) fetches each unique agent once per run, deduped by ID; set false for cheaper property-only runs.
- Agent `email` and `mobileNumber` come with every listing row at no extra cost; only standalone agent-profile rows fall back to `hasEmail: true|false`.
- `enrichEmails` (default false) is opt-in and billed per email found. It targets the AGENCY, not the agent — a business contact email plus website for the office behind the listing, which the agent's own email does not give you.
- Billing: pay-per-event — $0.05 per run start plus $1.50 per 1,000 rows; `enrichEmails` adds $0.0005 per email found.
- Hard limits: `/sold-listings/` caps at 12 months; `/project/` URLs emit placeholder rows only; commercial listings are out of scope.

***

### ⚠️ Disclaimer

This Actor accesses publicly available data on Domain.com.au for legitimate research, market intelligence, and business-analysis purposes. Use of this Actor must comply with Domain.com.au's Terms of Service and all applicable laws including the **Australian Privacy Act 1988**, GDPR (where the data subject is in the EU), and the **Spam Act 2003** (for any subsequent agent outreach). The Actor's authors are not responsible for any misuse. Users must:

- Respect rate limits and avoid overloading Domain.com.au's infrastructure
- Not use scraped data to violate user privacy or terms — agent contact details in particular are subject to the Australian Privacy Principles and may not be used for unsolicited commercial communications without consent
- Use the data in compliance with applicable jurisdictions
- Not republish scraped content in violation of copyright

**Domain.com.au is a registered trademark of Domain Holdings Australia Limited (ASX: DHG).** This Actor is not affiliated with, endorsed by, or sponsored by Domain Holdings Australia. If you are Domain Holdings Australia and would like to discuss commercial access via the official Domain Group Developer Portal, please contact the maintainer.

We do not store any scraped data; the Actor returns it directly to your Apify dataset for your authorized use.

***

### SEO Keywords

domain.com.au scraper, domain.com.au api, domain.com.au property data, australian real estate scraper, sydney property scraper, melbourne property scraper, brisbane property scraper, perth property scraper, adelaide property scraper, australia rental listings scraper, australia property for sale scraper, australia sold listings scraper, real estate agent data scraper, domain.com.au listings api, australian property market data, australian housing market scraper, real estate api australia, agent enrichment scraper, suburb profile data australia, school catchment data australia, australia auction data scraper, sold property history australia, apify domain.com.au, domain.com.au crawler, residential property data api, australian property comps data

# Actor input Schema

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

Full domain.com.au URLs to crawl. Listing URLs are paginated automatically until `Maximum items to scrape` is reached. Filtered URLs (with query strings or deep path segments) are passed through unchanged — every Domain UI filter is respected.

## `enrichAgent` (type: `boolean`):

When enabled, each unique real-estate agent referenced in a listing is fetched once per run to enrich the row with full agent details: full name, job title, mobile / landline, photo, agency, lifetime sales + leasing counts, recent listing ids, and bio. Cached by agent id, so duplicate references across listings share a single fetch. Default ON — disable for cheaper property-only runs.

## `enrichEmails` (type: `boolean`):

If enabled, finds a contact email for each result from its own website (or by discovering it from the name). Adds contactEmail + contactWebsite columns plus a detailed emailEnrichment object. Billed per contact email found; only charged when an email is returned, never for misses.

## `qualifyByPayment` (type: `boolean`):

Requires "Enrich with contact emails". Scans each business's website — reusing the pages already fetched for email discovery, so no extra cost or time — for payment processors and e-commerce platforms (Stripe, Shopify, PayPal, Paddle, Lemon Squeezy, WooCommerce, Square, Chargebee and more). Adds takesPayments (is this a real paying business?), paymentProcessors (which stack), stripeLiveKey (the public key if exposed) and paymentConfidence. Turn raw contacts into monetization-qualified leads. No extra charge — included with each enriched company.

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

Hard cap on the number of properties collected. Domain listings paginate 20 results per page; use this cap to control billing.

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

Maximum number of detail pages processed in parallel. Higher = faster but more proxy bandwidth + higher risk of transient errors. 6-10 is the sweet spot.

## `minConcurrency` (type: `integer`):

Minimum number of detail pages processed in parallel.

## `maxRequestRetries` (type: `integer`):

Number of retries before a failed request is given up. Transient errors (thin or empty bodies) are auto-detected and retried; this counter covers other failures too.

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

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you. Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.domain.com.au/rent/sydney-nsw-2000/",
    "https://www.domain.com.au/sale/melbourne-vic-3000/?bedrooms=2-any&price=0-800000",
    "https://www.domain.com.au/sold-listings/brisbane-city-qld-4000/",
    "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
    "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822",
    "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877"
  ],
  "enrichAgent": true,
  "enrichEmails": false,
  "qualifyByPayment": false,
  "maxItems": 200,
  "maxConcurrency": 8,
  "minConcurrency": 1,
  "maxRequestRetries": 5
}
```

# 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 = {
    "startUrls": [
        "https://www.domain.com.au/rent/sydney-nsw-2000/",
        "https://www.domain.com.au/sale/melbourne-vic-3000/?bedrooms=2-any&price=0-800000",
        "https://www.domain.com.au/sold-listings/brisbane-city-qld-4000/",
        "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
        "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822",
        "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/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 = { "startUrls": [
        "https://www.domain.com.au/rent/sydney-nsw-2000/",
        "https://www.domain.com.au/sale/melbourne-vic-3000/?bedrooms=2-any&price=0-800000",
        "https://www.domain.com.au/sold-listings/brisbane-city-qld-4000/",
        "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
        "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822",
        "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/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 '{
  "startUrls": [
    "https://www.domain.com.au/rent/sydney-nsw-2000/",
    "https://www.domain.com.au/sale/melbourne-vic-3000/?bedrooms=2-any&price=0-800000",
    "https://www.domain.com.au/sold-listings/brisbane-city-qld-4000/",
    "https://www.domain.com.au/38-bridge-st-sydney-nsw-2000-18121983",
    "https://www.domain.com.au/real-estate-agent/cherie-xue-1487822",
    "https://www.domain.com.au/real-estate-agencies/sydneycoveproperty-6877"
  ]
}' |
apify call memo23/domain-com-au-scraper --silent --output-dataset

```

## MCP server setup

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