REIWA Scraper - WA Property, Agents & Market Data
Pricing
from $1.00 / 1,000 results
REIWA Scraper - WA Property, Agents & Market Data
Scrape REIWA.com.au across sale, rental, sold, commercial, business and rural properties. Search with filters or URLs and extract structured listings, agents, agencies and market insights across Western Australia.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
2
Monthly active users
11 days ago
Last modified
Categories
Features
Share
REIWA Scraper: WA Property Listings, Agents and Market Insights
REIWA Scraper turns REIWA.com.au (Real Estate Institute of Western Australia) into structured data. Collect for sale, for rent, sold, commercial, business and rural listings, agent and agency profiles, and market insight articles across Western Australia. Search by section, suburb, price and bedroom filters, or paste REIWA URLs directly. Turn on detail enrichment for full descriptions and extra photos, then export to JSON, CSV or Excel, pull the dataset through the API, or pipe results into apps you already use.
Why This Scraper?
- Nine REIWA sections, one actor. For sale, for rent, sold, find agents, commercial for sale, commercial for lease, business, rural and insights, all through the same input.
- Two ways in. Build a search from a section, suburbs or regions, price and bedroom filters, or paste REIWA result pages, single listings, agent or agency profiles, and insight articles.
- Agent and agency contact detail. Agent names, profile links, agency names, phone numbers where visible, and profile performance figures such as listings sold and median days on market.
- Optional detail enrichment. Turn on Fetch details to add full descriptions, extra photos, page metadata and richer visible contact fields, billed only for the rows it successfully enriches.
- Full-catalogue pagination. Leave Max pages empty and the run keeps walking result pages until the site's own last-page signal, relying on Max items as the cap.
- Filters that work on both modes. Keywords, property type, price and bedroom filters run as a post-fetch step on search-mode and URL-mode rows alike, though a row with no numeric price or bedroom count is always kept.
- Resume and recurring updates. Point a new run at a previous run's ID (or dataset ID) to skip rows already collected, or turn on Incremental mode so each scheduled run returns only new and changed rows, stamped with
changeType,changedFields,firstSeenAtandlastSeenAt.
Use Cases
- Buyers and renters: track new listings in chosen suburbs, filtered by price range and bedroom count.
- Lead generation: build contact lists of agents and agencies active in a region, with phone numbers and profile links.
- Market research: pair sold listings with insight articles to study price trends across WA.
- Portfolio tracking: monitor commercial, business and rural listings for acquisition or leasing opportunities.
- CRM and workflow automation: pipe new rows into Notion, Linear or Airtable through MCP connectors as they're collected.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
id | "5551234" |
type | "for-sale" (also "for-rent", "sold", "commercial", "business", "rural", "agent", "agency", "insight") |
title | "12 Example Street, Sampleford" |
address | "12 Example Street, Sampleford" |
suburb | "Sampleford" |
url | "https://reiwa.com.au/12-example-street-sampleford-5551234/" |
sourceUrl | "https://reiwa.com.au/for-sale/perth~region/" |
price | "$650,000" |
priceValue | 650000 |
bedrooms / bathrooms / parkingSpaces | 4 / 2 / 2 |
propertyType | "House" |
agencyName / agencyUrl | "Sample Realty Group" / "https://reiwa.com.au/real-estate-agency/sample-realty-group/" |
agentNames / agentUrls | ["Jordan Sample"] / ["https://reiwa.com.au/real-estate-agent/jordan-sample/"] |
phoneNumbers | ["0491570156"] |
dateText | "Added 4 days ago" |
imageUrls | ["https://imagecdn.reiwa.com.au/listing/34/5551234-01.jpg"] |
description | listing description text (Fetch details on, or a pasted single listing URL; usually a short summary, not the full listing text) |
pageTitle | the listing page's <title> text (Fetch details on, or a pasted single listing URL) |
latitude, longitude | listing coordinates (Fetch details on, or a pasted single listing URL) |
postcode, listingStatus, landAreaSqm, soldDate | postcode, status label such as Sold, land size in square metres, YYYY-MM-DD sold date (same condition, when the listing shows them) |
features | listing feature lines such as Garages: 2 (same condition) |
detailStatus | "ok" or "skipped" (when Fetch details is on) |
scrapedAt | "2026-01-01T00:00:00.000Z" |
Agent and agency profile rows (the find-agents section, or pasted agent and agency URLs) carry the same title, url, agencyName and phoneNumbers shape plus profileStats, an object of visible profile figures such as listings sold, median days on market and median sale price. Insight rows (the insights section) use the article URL as id and carry title, url, dateText and a short summary instead of price or agent fields.
Output views. The dataset has five views: Results (every kind), Overview (compact listing columns), Listings (detail) (coordinates, postcode, status, land area, sold date, features), Agents & agencies and Insights & articles. The type field tells you the kind of each row. A run summary is saved to the key-value store as OUTPUT (rows saved, rows per type, detail-enriched count, rows per search).
How to Use
- Pick a mode: Search by filters or Scrape from URLs.
- For search mode, choose a REIWA section and one or more suburbs or regions, then narrow with price, bedroom and property type filters.
- Turn on Fetch details if you want full descriptions, extra photos and richer contact fields (billed per row it succeeds on).
- Set Max items (and optionally Max pages), then click Start.
Sale listings in Perth with a price and bedroom filter:
{"mode": "search","channel": "for-sale","locations": ["perth~region"],"minPrice": 500000,"maxPrice": 750000,"minBedrooms": 3,"maxItems": 30}
Rental listings with details enabled:
{"mode": "search","channel": "for-rent","locations": ["baldivis"],"minPrice": 450,"maxPrice": 650,"fetchDetails": true,"maxItems": 20}
Find agents in a region:
{"mode": "search","channel": "agents","locations": ["south-west~region"],"maxItems": 25}
Paste REIWA search URLs (multiple pages of the same search):
{"mode": "url","urls": ["https://reiwa.com.au/for-sale/perth~region/","https://reiwa.com.au/for-sale/perth~region/?page=2"],"maxItems": 15}
Supported URL shapes (URL mode):
| Page | Example path |
|---|---|
| For sale search (region, suburb, property type, filtered or sorted, paginated) | /for-sale/perth~region/, /for-sale/baldivis/houses/, /for-sale/baldivis/?minPrice=400000&bedrooms=3&sortBy=price-asc, ?page=2 |
| Rentals | /rental-properties/perth/ (a /rent/<location>/ link is mapped to this) |
Sold (including ?page=2) | /sold/baldivis/ |
| Commercial for sale / for lease | /commercial/for-sale/perth/, /commercial/for-lease/perth/ |
| Business for sale | /business/for-sale/perth/ |
| Rural | /rural/for-sale/south-west~region/ |
| Agents directory | /real-estate-agents/baldivis/ |
| Agent profile | /real-estate-agent/<name>-<id>/ |
| Agency profile | /real-estate-agency/<name>-<id>/ |
| Listing detail | /<street>-<suburb>-<id>/ (typed from the page: sale, rent or sold) |
| Insights list / article | /the-wa-market/resources/?types=news&page=1, /news/<slug>/ |
Filters you put in the URL (price, bedrooms, sort) are applied by the site and are never overwritten by the run-level filters. www. and m. hosts are normalised to reiwa.com.au, tracking parameters are dropped, and a bare numeric id such as /5049038/ or a non-REIWA link is skipped with a warning in the log.
Default URLs (behaviour change): the URLs field now defaults to one example of every page type above (16 URLs, covering all 18 URL shapes in the table). A URL-mode run started with that field untouched scrapes all of them, up to Max items, and the dataset items it produces are billed as usual. Replace or clear the list to scrape only your own pages.
Plain place names in search mode: locations such as Perth, South West or Baldivis are checked against the site (region first, then suburb) and the run stops with a clear error if no match is found. Slugs like south-west~region are used as typed.
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/reiwa-com-au-scraper").call(run_input={"mode": "search","channel": "for-sale","locations": ["perth~region"],"maxItems": 20,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["title"], row.get("price"))
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/reiwa-com-au-scraper').call({mode: 'search',channel: 'for-sale',locations: ['perth~region'],maxItems: 20,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Result filters apply to both modes
Keywords, property types, min/max price and min bedrooms run as a filter on the rows a page returns, whether that page came from a built search or a pasted URL. Locations and sort order only affect how a search-mode URL is built, so they have no effect in URL mode. Property type filters have no effect on the rural section.
Full pages and Resume
Leave Max pages empty (or 0) to walk every result page for a search or URL; the run stops on the site's own short or empty last page, or once Max items is reached. Resume (resumeFromRunId) seeds the run's row-tracking set from a previous run or dataset before scraping starts: already-collected leading pages are walked through rather than ending the search early, and already-collected rows on them are skipped; once the walk reaches a page with no new rows at all, that search stops as usual.
Incremental mode for scheduled runs
Turn on Incremental mode (incrementalMode) and the run remembers what it delivered for the same search scope (mode, section, locations or URLs, filters, sort and Fetch details; caps such as Max items never change the scope). On the next run every row is classified: NEW (first time seen), UPDATED (a compared field changed, with changedFields naming it), UNCHANGED (not pushed unless you turn on emitUnchanged), REAPPEARED (was tombstoned, now back) or EXPIRED (the previous run delivered it and a complete scan no longer returns it). UPDATED compares every returned field except scrapedAt, the relative dateText, detailStatus, imageUrls, sourceUrl and anything you list under Ignore fields; list order is ignored. Set changeScope to priceAndStock to compare only price, price value, listing status and sold date. EXPIRED means the search no longer returned the row; it does not prove the property was sold or withdrawn. EXPIRED rows are only produced when the scan ran to the end: not capped by Max items or Max pages, not resumed, and not started at a later page. Rows that are not pushed (unchanged ones) are not billed, and a detail-enrichment charge applies only to full rows pushed with detailStatus: "ok"; compact UPDATED rows and EXPIRED tombstones carry no detail charge. Incremental mode off returns the full result set exactly as before.
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 row, not the full JSON. Each row becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify > Settings > Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto 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.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search builds REIWA pages from the filters below; url scrapes the REIWA links you paste. |
channel | string | for-sale | REIWA section for search mode: for sale, for rent, sold, find agents, commercial for sale, commercial for lease, business, rural or insights. URL mode detects the section from each URL. |
locations | array | ["perth~region"] | Suburbs or regions such as perth, perth |
sortBy | string | default | Ordering for result pages that support sorting. |
urls | array | 16 example URLs, one per supported page type (see the URL mode section) | Only used when mode is url. Paste search or list pages, single listings, agent or agency profiles, or insight articles. Multiple URLs are supported. |
keywords | string | "" (empty) | Optional text matched against returned titles, addresses, agencies, and article summaries, plus a pasted single listing page's own description; Fetch-details-enriched descriptions are not searched. Runs as a post-fetch filter on both search and URL modes. |
propertyTypes | array | [] (none) | Optional listing type filters (houses, apartments, units, villas, townhouses, land, rural). Applies to search and URL modes when supported by the source; has no effect on the rural section. |
minPrice | integer | none | Optional minimum price. For rentals this is weekly rent. |
maxPrice | integer | none | Optional maximum price. For rentals this is weekly rent. |
minBedrooms | integer | none | Optional minimum bedrooms. |
fetchDetails | boolean | false | Adds full descriptions, extra photos, page metadata and richer contact or profile fields per row. Billed as a detail-enrichment surcharge for each row it succeeds on. |
maxItems | integer | 20 | Hard cap on rows saved across the whole run. |
maxPages | integer | none (prefill: 0) | Optional bound on result pages walked per search or URL. 0 or empty walks every result page, relying on Max items as the cap. |
resumeFromRunId | string | none | Paste a previous run ID (or dataset ID) from this actor. Rows already collected there are skipped, so this run only returns new ones. |
incrementalMode | boolean | false | Remember the rows delivered for this search scope and push only NEW, UPDATED, REAPPEARED and EXPIRED rows on later runs. Off returns the full result set as before. |
stateKey | string | none | Optional name for the incremental baseline. Empty keys the baseline on a hash of the search scope automatically. |
emitUnchanged | boolean | false | With Incremental mode on, also push rows that did not change (changeType: "UNCHANGED"). |
emitExpired | boolean | true | With Incremental mode on, push an EXPIRED tombstone for rows the previous run delivered and this complete scan no longer returns. |
changeScope | string | all | all compares every returned field; priceAndStock compares only price, price value, listing status and sold date. |
compactUpdates | boolean | false | UPDATED rows carry only id, title, link, current price fields and priceChanges instead of the full record. |
expireAfterMissedScans | integer | 1 | Tombstone a row only after it was missing from this many consecutive complete scans. |
ignoreFieldsForChanges | array | [] | Fields that never count as a change (top-level names or dotted paths). Defaults already ignore scrapedAt, dateText, detailStatus, imageUrls and sourceUrl. |
proxy | object | Apify Proxy enabled | Connection settings. Keep Apify Proxy enabled for stable runs; use a country setting only if you need a specific geography. |
mcpConnectors | array | none | Optional: send a summary of each row into apps you already use, via MCP connectors authorized under Apify Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which item pages are created. Ignored by other connectors. |
maxNotifyListings | integer | 50 | Cap on rows written to each selected connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"id": "5551234","type": "for-sale","title": "12 Example Street, Sampleford","address": "12 Example Street, Sampleford","suburb": "Sampleford","url": "https://reiwa.com.au/12-example-street-sampleford-5551234/","sourceUrl": "https://reiwa.com.au/for-sale/perth~region/","price": "$650,000","priceValue": 650000,"bedrooms": 4,"bathrooms": 2,"parkingSpaces": 2,"propertyType": "House","agencyName": "Sample Realty Group","agencyUrl": "https://reiwa.com.au/real-estate-agency/sample-realty-group/","agentNames": ["Jordan Sample"],"agentUrls": ["https://reiwa.com.au/real-estate-agent/jordan-sample/"],"phoneNumbers": ["0491570156"],"dateText": "Added 4 days ago","imageUrls": ["https://imagecdn.reiwa.com.au/listing/34/5551234-01.jpg"],"description": "Sample listing description text goes here.","pageTitle": "12 Example Street, Sampleford - For Sale | REIWA","detailStatus": "ok","scrapedAt": "2026-01-01T00:00:00.000Z"}
Plan Requirement
The default proxy setting works out of the box on any plan that includes Apify Proxy: REIWA pages load through the standard datacenter connection, so no residential proxy is needed. Each page request has a 15 second attempt limit and up to 5 attempts, and each page has a 25 second overall limit. When the selected connection is unavailable the run switches to a backup connection and logs: "Served over the backup connection (the default connection was unavailable)." If it does, a warning explains that "Apify free plans do not include residential proxies" and that some pages may still be unavailable.
When nothing can be loaded the run fails with a plain message instead of returning an empty dataset:
- Proxy refused: "The proxy connection was refused for this account, so no page could be read." A paid plan is required, or supply valid proxy URLs of your own.
- Backup also failed: "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested REIWA pages."
- Connection problem: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search."
FAQ
How much does it cost?
You pay per row saved, plus a one-time run start fee. When you turn Fetch details on, the detail-enrichment event is billed once per row whose detail page was fetched and merged successfully (rows marked detailStatus: "skipped" are never billed). It is charged once, when the run finishes cleanly, for the total number of enriched rows. The Pricing tab shows the current rates. Use Max items to cap the cost of any run. Single pages you paste (a listing, an agency or agent profile, an insight article) are already their own detail page, so they are never fetched again and never billed detail-enrichment; the same goes for agent, agency and article rows found on list pages.
Is it legal to scrape REIWA?
This actor collects only publicly available real estate data. You are responsible for how you use it: follow REIWA's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution, particularly for agent or agency contact details.
Do keyword and price filters work in URL mode too?
Yes. Keywords, property types, price and bedroom filters run on the rows returned by a page regardless of how that page was reached, so they apply to a pasted URL the same way they apply to a built search.
Can I get only new listings on a recurring schedule?
Yes. Turn on Incremental mode: the first run returns everything as NEW, later runs on the same scope return only NEW, UPDATED, REAPPEARED and EXPIRED rows (see the incremental section above). Resume (resumeFromRunId) is different: it skips rows collected in one earlier run and is meant for continuing an interrupted run.
Why did my run fail instead of returning an empty dataset?
An empty dataset can mean the search or filters matched nothing on the find-agents or insights sections, or, for a listing search, that the section returned a single page-level row rather than any listings at all. A page that does not exist (a mistyped pasted URL included) is skipped with a "Page not found" warning, and a search whose page can't be loaded is skipped with a "Could not load" warning, so the other searches in the same run still finish. A search whose first page returns no results logs a warning, and a run that saves nothing says so in the log. The run fails only when no page could be loaded at all ("Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."). Rows already saved before a failure stay in the dataset and are billed for. Check the run log, then run it again in a few minutes.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
π Want more real estate data?
Pair this actor with these related scrapers from the same team:
| π Homely.com.au Scrape Homely.com.au properties for sale, rent, and sold, plus agent finder, suburb... | π Domain.com.au Extract enriched Domain.com.au property listings across buy, rent, and sold, with... |
| π View.com.au Scraper Scrape View.com.au properties for sale, rent and recently sold across Australia. Search... | π Real Estate AU Agents Scraper Scrape Australian real estate agent and agency profiles by suburb or profile URLs... |
| π Commercial Property AU Scraper Scrape Australian commercial property listings with detailed property data. Extract... | π 591.com.tw Scraper Extract property listings from 591ζΏε±δΊ€ζηΆ² 591.com.tw, Taiwanβs largest real estate... |
π Browse all abotapi scrapers
π¬ Support
- π Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- π οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
- β Enjoying it? A quick review on the actor page helps other users find it.