Domain.com.au – Buy, Rent, Sold & Price History avatar

Domain.com.au – Buy, Rent, Sold & Price History

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Domain.com.au – Buy, Rent, Sold & Price History

Domain.com.au – Buy, Rent, Sold & Price History

Extract enriched Domain.com.au property listings across buy, rent, and sold, with AI-enhanced content and deep structured data including descriptions, features, photos, GPS, agent contacts, suburb insights, school catchments, and complete sold and leased price history timelines.

Pricing

from $1.50 / 1,000 results

Rating

5.0

(1)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

15

Total users

5

Monthly active users

8 hours ago

Last modified

Share

Domain.com.au Property Scraper

Pull every listing on Domain.com.au, Australia's #2 property portal, with the full field surface across buy, rent, and sold modes.

Highlights: Property History & Property Insights. Beyond the standard listing fields, this scraper can enrich every record with Property History (the full sold/listed/leased price timeline per unit) and Property Insights (AVM value estimates, suburb market trends, and property-level intelligence such as planning overlays, school zoning, nearby childcare, NBN, and council). Together they turn a plain listing into a full valuation-and-history dossier. See Enriched output.

What you get per listing

Example record (shape only, values are illustrative placeholders):

{
"id": "0000000000",
"url": "https://www.domain.com.au/1-example-street-suburb-nsw-2000-0000000000",
"listingType": "buy",
"displayAddress": "1 Example Street, Sample Suburb NSW 2000",
"addressDisplayType": "FULL_ADDRESS",
"suburb": "Sample Suburb", "state": "NSW", "postcode": "2000",
"latitude": 0.0, "longitude": 0.0,
"price": "Contact Agent",
"bedrooms": 2, "bathrooms": 2, "parkingSpaces": 1,
"landSize": 415, "landSizeUnit": "m²",
"buildingSize": 95, "buildingSizeUnit": "m²",
"propertyType": "Apartment Unit Flat",
"headline": "Example listing headline.",
"description": "Example multi-paragraph description.",
"structuredFeatures": ["Air Conditioning", "Built-In Wardrobes", "Pool", "Security Access"],
"status": "NEW",
"inspection": {
"byAppointmentOnly": false,
"inspections": [
{ "start": "2026-01-03T13:45:00", "end": "2026-01-03T14:00:00", "time": "1:45pm", "dayOfWeek": "Saturday" }
]
},
"firstListedDate": "2026-01-01T00:00:00",
"agencyName": "Example Real Estate",
"agencyId": "QWdlbmN5OjAwMDAw",
"agencyProfileUrl": "https://www.domain.com.au/agencies/00000/",
"agencyAddress": {
"street": "Example Street", "streetNumber": "10",
"suburb": "Sample Suburb", "state": "NSW", "postcode": "2000"
},
"agencyBrandColour": "#000000",
"agents": [{
"id": "QWdlbnQ6MDAwMDAwMA==",
"name": "Jane Smith",
"phone": "0400 000 000",
"mobile": "0400 000 000",
"email": "jane@example.com.au",
"photo": "https://rimh2.domainstatic.com.au/.../contact_000000.JPG",
"profileUrl": "https://www.domain.com.au/real-estate-agent/0000000/"
}],
"tags": ["apartment_unit_flat", "new"]
}

35+ fields populated per listing, including:

  • Agent name, phone, mobile, email, headshot URL
  • Agency name, ID, profile URL
  • Full address (street, suburb, state, postcode) + lat/lng
  • Beds, baths, parking, land size
  • Property type
  • Headline and full description (multi-paragraph)
  • Structured features list (typically 15 to 20 per listing)
  • Status (NEW / UNDER_OFFER / SOLD / LEASED)
  • First-listed date, sold/leased dates where applicable
  • Hero image URL
  • Optional cross-source enrichment for property insights and extended listing fields when includePropertyInsights or includeExtendedListing is enabled.
  • Optional changeType / changedFields / firstSeenAt / lastSeenAt when incrementalMode is on — see Resume vs. Incremental mode.

Two modes (input)

Search mode

Filter by suburb plus listing type.

{
"mode": "search",
"listingType": "buy",
"locations": ["sydney-nsw-2000", "melbourne-vic-3000"],
"minBedrooms": 2,
"maxListings": 100,
"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "AU" }
}

URL mode

Paste Domain listing URLs, search URLs, or a mix. Listing type, property types, bedrooms, bathrooms, price and exclude-under-offer still narrow these results; sort order and the inspection/auction toggles do not.

Open-for-inspection URLs are supported. Paste a suburb URL whose path ends in /inspection-times/ (e.g. …/rent/<suburb-slug>/inspection-times/) to scrape only listings with a scheduled inspection in the next 7 days. Each result's inspection field carries the full schedule (start/end time, day of week). Pagination walks the whole filtered set automatically.

{
"mode": "url",
"urls": [
"https://www.domain.com.au/level-12-303-castlereagh-street-sydney-nsw-2000-2013554678",
"https://www.domain.com.au/1-alfred-street-sydney-nsw-2000-2019522695"
],
"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "AU" }
}

Proxy requirement

Apify Residential proxy, country AU or NZ. Residential exits are required for reliable reachability and for the optional cross-source enrichment paths.

Input fields

  • mode is search or url
  • listingType is buy (default), rent, or sold. Search mode: selects which listings to search. Any mode: when set to sold, also narrows a pasted URL's results to sold/leased listings.
  • locations is a list of suburb-state-postcode slugs (search mode only); accepts lowercase hyphens
  • sortBy orders results (search mode only). Does not sort a pasted URL's results by this key.
  • propertyTypes (search mode and any pasted URL; example ["apartment-unit-flat", "house"])
  • minBedrooms, maxBedrooms, minBathrooms, minPrice, maxPrice (search mode and any pasted URL)
  • excludeUnderOffer drops listings with status UNDER_OFFER (search mode and any pasted URL)
  • urls is a list of Domain listing URLs (URL mode only)
  • inspectionsOnly (search mode only) returns only listings with a scheduled inspection in the next 7 days; each result gets an inspection schedule. In URL mode, paste an /inspection-times/ URL instead.
  • auctionsOnly (search mode only) returns only listings going to auction in the next 7 days. Best paired with listingType: "buy". Domain has no auction URL to paste, so this toggle is the only way to filter auctions.
  • maxListings is the hard output cap (default 20; set to 0 for no limit)
  • maxPages is a coarse output cap, ~30 listings per page (default 0 = no limit; maxListings wins when both are set)
  • resumeFromRunId (optional) continues a large pull across separate runs: paste a previous run id (or its dataset id) and this run skips listings it already saved, appending only new ones
  • incrementalMode (optional, default off) — see Resume vs. Incremental mode below
  • stateKey (optional) — names an incremental-mode monitoring campaign explicitly
  • emitUnchanged (optional, default off) — also return (and bill) listings unchanged since the last incremental run
  • emitExpired (optional, default off) — also return (and bill) listings no longer found, once a run has fully scanned the tracked search
  • fetchPropertyHistory adds the sold/leased price-history timeline (needs residential AU)
  • includePropertyInsights adds suburb-level insights (median, days on market, demographics)
  • includeExtendedListing adds the cross-source indoor/outdoor feature split
  • mcpConnectors (optional) pipes results into your apps — see below
  • notionParentPageUrl (optional, Notion only) the page to create listing pages under
  • maxNotifyListings (optional) caps how many listings are written per connector (default 50)

Resume vs. Incremental mode

Two different features that are easy to conflate — both live under the same "🔁 Resume & recurring updates" input section:

  • resumeFromRunId continues one specific interrupted run. Paste a previous run/dataset id; this run skips listings already saved there and appends only new ones. Use it after a large pull got cut off.
  • incrementalMode is for scheduling this same search again and again (e.g. daily) and getting only what changed. The actor remembers its own baseline (in a key-value store, keyed by your search scope or an explicit stateKey) and classifies every listing as:
    • NEW — not seen before under this state key
    • UPDATED — a field changed since last run (changedFields lists which ones)
    • UNCHANGED — identical to last run (returned only when emitUnchanged: true)
    • REAPPEARED — was gone, is back (e.g. relisted)
    • EXPIRED — was tracked, no longer found (e.g. sold/leased/delisted) — returned only when emitExpired: true, and only once a run has fully scanned every location/URL in the search (a run capped by maxListings/maxPages, or using resumeFromRunId, never emits EXPIRED — it cannot tell "gone" apart from "not reached yet"). When incremental mode is on, every dataset row also gets firstSeenAt/lastSeenAt timestamps.

Turning on incrementalMode alongside resumeFromRunId is supported as a one-time bootstrap: the first run seeds the incremental baseline from the resumed dataset (so those listings aren't reported NEW again tomorrow) — but that combined run itself is treated as incomplete, so it never emits EXPIRED. After that, run with incrementalMode alone on a schedule.

The state key covers your search scope (locations/URLs, listing type, every filter, and the enrichment toggles) but deliberately excludes maxListings, maxPages, and resumeFromRunId — raising your item cap or continuing a resumed pull never starts a new baseline. Set stateKey yourself to name a campaign, or leave it blank to let the actor derive one automatically (two differently-configured searches then never share state).

A note on enrichment during incremental mode: if fetchPropertyHistory / includePropertyInsights / includeExtendedListing are on and the underlying cross-source lookup fails for a whole batch (a transient solver/session issue — not "no match found", which is a legitimate empty result), the actor carries forward that listing's last known-good enrichment values instead of reporting a false UPDATED from a fetch failure. A genuine data change (e.g. price) is still reported correctly either way.

marketInsights (from includePropertyInsights) is a suburb-wide aggregate — the same median price/rent and growth figures are attached to every listing in that suburb, confirmed by comparing two different addresses in the same run. It is still returned on every record, but is excluded from change detection: without this, every listing in a suburb would flip to a false UPDATED the moment the suburb aggregate refreshes, unrelated to that listing itself. valueEstimates, pcaInsights, and priceHistory are per-address and are NOT excluded — nor are core listing fields like price, priceGuide, status, inspection, or auction dates, which are exactly the real changes incremental mode exists to report.

Send results into your apps (MCP connectors)

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

What gets written to the connector: a condensed, human-readable summary of each record — not the full JSON. Each item becomes one entry with a title (the listing's name / address) and its key fields flattened to plain text (price, beds/baths, agent, URL, …). Nested objects are collapsed to their main value (e.g. an address object → its full-address text) and long lists are trimmed to the first few names. The complete, full-fidelity record always stays in the Apify dataset — the connector copy is a readable digest for browsing in your app.

  • Notion → one page per item (title + a summary body), created under the page you set in notionParentPageUrl.
  • Linear / Airtable / other → one record/issue per item with the same title + fields.

How to enable:

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

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

Tags

Each listing carries category tags you can filter or group on:

  • Property type (apartment_unit_flat, house, townhouse, ...)
  • Status (new, under_offer, sold, leased)
  • Sale method (auction when the price string indicates one)

Enriched output (when cross-source toggles are on)

The three optional toggles attach extra fields to each listing. Each is independent and can be enabled on its own.

Highlight: Property History & Property Insights. These are the two flagship enrichments. Property History (fetchPropertyHistory) gives you the full sold/listed/leased price timeline per unit, and Property Insights (includePropertyInsights) adds AVM value estimates, suburb market trends, and property-level intelligence (planning overlays, school zoning, nearby childcare, NBN, council). Together they turn a plain listing into a full valuation-and-history dossier.

⭐ Property History: fetchPropertyHistory: true, adds priceHistory[]

A timeline of past sale, listing, and lease events for the SPECIFIC unit (apartment listings need a unit number like 12/45 … in the address to match; bare-building addresses are skipped to avoid returning aggregate building data).

"priceHistory": [
{ "event": "listed_for_sale", "year": 2026, "price": "Auction Guide $1,000,000", "date": "1 Jan 2026", "agent": "Example Real Estate", "details": "Listed 1 Jan 2026 by Example Real Estate" },
{ "event": "sold", "year": 2018, "price": "$870,000", "date": "1 Jan 2018", "agent": "Example Real Estate", "details": "Sold 1 Jan 2018 by Example Real Estate" },
{ "event": "listed_for_sale", "year": 2018, "price": "$880,000", "date": "1 Dec 2017" },
{ "event": "sold", "year": 2012, "price": "$640,000", "date": "1 Jan 2012" }
]

Typical 0-10 events per unit. Empty when the cross-source index has no record for this specific unit.

⭐ Property Insights: includePropertyInsights: true, adds valueEstimates, marketInsights, pcaInsights

Three separate blocks for AVM valuation, suburb market trends, and property-level intelligence:

"valueEstimates": {
"sale": { "value": 1050000, "display": "$1.05M", "confidence": "MEDIUM", "range_min": 950000, "range_max": 1150000 },
"rental": { "value": 900, "display": "$900/wk", "confidence": "MEDIUM", "range_min": 800, "range_max": 1000 }
},
"marketInsights": {
"median_price": "$1,200,000",
"price_growth_12mo": "+5.2%",
"median_rent": "$950",
"rent_growth_12mo": "+8.1%"
},
"pcaInsights": {
"planningOverlays": { "bushfire": false, "flood": false, "heritage": true },
"council": "Sample Council",
"landDescription": "Lot 1 in Strata Plan 0000",
"internet": { "connectionType": "FTTP", "quality": "Excellent", "description": "NBN Fibre to the Premises" },
"schoolZoning": [
{ "name": "Sample Public School", "isZoned": true, "phase": "primary" },
{ "name": "Sample Secondary College", "isZoned": true, "phase": "secondary" }
],
"nearbyChildcare": [
{ "name": "Sample Early Learning Centre", "address": "1 Example St, Suburb, NSW 2000" }
],
"builtYear": 2005,
"mobileCoverage": "5G",
"mediaCounts": { "photos": 18, "floorPlans": 1, "videos": 0 }
}

includeExtendedListing: true, adds extendedListing

Indoor/outdoor feature split and a handful of listing-card fields Domain itself doesn't expose:

"extendedListing": {
"indoorFeatures": ["Air conditioning", "Built-in robes", "Dishwasher", "Floorboards", "Gas heating"],
"outdoorFeatures": ["Balcony / Deck", "Secure parking", "Shed"],
"studies": 1,
"buildingSize": 95,
"buildingSizeUnit": "m²",
// note: buildingSize / buildingSizeUnit are also returned at the top level
// of every record now, so this block only fills them in as a fallback.
"priceFrom": 950000,
"priceTo": 1050000,
"hasFloorplan": true,
"hasVideo": false,
"has3DTour": true,
"hasStatementOfInformation": false,
"constructionStatus": "existing",
"dateUpdated": "2026-01-15T09:00:00",
"auctionDate": "2026-02-15T11:00:00",
"soldPrice": null,
"daysOnMarket": 14,
"bond": null,
"availableDate": null
}