Property24 $1💰 Buy, Rent, Sell, Commercial Scraper avatar

Property24 $1💰 Buy, Rent, Sell, Commercial Scraper

Pricing

from $1.00 / 1,000 results

Go to Apify Store
Property24 $1💰 Buy, Rent, Sell, Commercial Scraper

Property24 $1💰 Buy, Rent, Sell, Commercial Scraper

From $1/1K. Extract structured property listings from Property24, South Africa’s largest property portal. Search by location or use Property24 URLs. Get 50+ fields including price, beds, baths, sizes, GPS coordinates, photos, property details, and agent/agency information.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

11

Total users

3

Monthly active users

4 hours ago

Last modified

Share

Property24 Scraper: South Africa Property Listings, Agents & GPS

Property24 Scraper turns Property24, South Africa's largest property portal, into structured data. Get price, bedrooms, bathrooms, floor and erf size, GPS coordinates, the full grouped property overview, every photo, agent and agency details, and 50+ fields per listing. Search by suburb, city or province name, or paste Property24 search and single-listing URLs directly, then export to JSON, CSV or Excel, or pull results through the API.

Why This Scraper?

  • More fields per listing. GPS latitude and longitude, numeric floor and erf size, postal code, the complete grouped property overview (rooms, external features, building, security), nearby suburbs, listing date and full multi-size photo URLs, alongside the standard price, beds, baths and description.
  • Two ways to find listings. Search by any suburb, city or province name, resolved automatically, or paste Property24 URLs directly: search pages paginate forward, single-listing URLs are fetched directly.
  • Filters that actually narrow the data. Price, bedroom and bathroom filters are sent in the search request and re-checked on the returned records; property type is matched on the results; sort and amenity filters are applied through the search request. Results match what you asked for even if the site ignores a parameter.
  • Cost under your control. Turn detail-page fetching off for a cheaper search-result-only run, or on for full listing depth, and cap any run with Max Listings.
  • Only new listings on repeat runs. Point a run at a previous run or dataset ID and already-collected listings are skipped, so you only pay for what's new.
  • Built for an unreliable site. The actor automatically tries a different connection when a request is refused, so runs keep making progress instead of stopping at the first blocked page.
  • Clean, flat output. One record per listing, ready for spreadsheets, BI tools, ETL pipelines and CRMs, with optional delivery into the apps you already use.

Use Cases

  • Property portals and listing aggregators: pull fresh Property24 listings into your own search index or comparison site.
  • Real estate agencies and agents: monitor competing listings and price positioning by suburb or city.
  • Investors and analysts: track price per square metre, erf size and inventory across South African suburbs over time.
  • PropTech and CRM integrations: feed listings and agent and agency details into your CRM or lead pipeline, including through MCP connectors.
  • Market researchers and journalists: build historical datasets of pricing and listing volume for reporting.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
listingNumber"100000001"
urlhttps://www.property24.com/for-sale/sample-suburb/sample-city/western-cape/0000/100000001
listingType"For Sale"
title"3 Bedroom House for sale in Sample Suburb"
price / displayPrice2600000 / "R 2 600 000"
currency"ZAR"
priceOnApplicationfalse
bedrooms / bathrooms3 / 2
garages / parkingSpaces2 / 4
floorSize / erfSize248.0 / 554.0
propertyType"House"
suburbName / cityName / provinceName"Sample Suburb" / "Sample City" / "Western Cape"
latitude / longitude-33.0000 / 18.0000
description"Full listing description text."
agencyName / agentName"Sample Agency" / "Agent Name"
contacts[{ "id": 0, "name": "Agent Name", "contactType": "Agent", "jobTitle": "Property Practitioner", "hasContactNumber": true }]
keyFeatures["Bedrooms 3", "Bathrooms 2", "Garden"]
propertyOverview{ "Type of Property": "House", "Erf Size": "554 m2" }
photos / photoCount[{ "imageIdentifier": "000000000", "imageUrl": "..." }] / 1 (equal to the length of photos)
floorPlans[{ "imageIdentifier": "000000000", "imageUrl": "..." }], floor-plan images when the listing has them (detail pages only)
nearbySuburbs["Sample Suburb A", "Sample Suburb B"]
auction / onShow / repossessedfalse / false / false
datePosted"2026-01-01"
scrapedAt"2026-01-01T00:00:00.000000+00:00"

GPS coordinates, the full description, agent and agency details, the property overview, photos and nearby suburbs only populate when Fetch Detail Pages is on. A search-result-only run still returns listing number, url, type, title, price, bedrooms, bathrooms, garages, floor and erf size, suburb name and a short excerpt.

How to Use

  1. Pick a mode: search (find listings by place name) or url (paste Property24 search or listing links).
  2. In search mode, choose a listing type (buy, rent, or commercial) and one or more locations, then set any price, bedroom or amenity filters.
  3. Turn Fetch Detail Pages on for the full record, or off for a faster, cheaper search-result-only run.
  4. Set Max Listings to control run size and cost, then click Start. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search by location (basic):

{
"mode": "search",
"listingType": "for-sale",
"locations": ["Cape Town"],
"maxListings": 50
}

Search with filters:

{
"mode": "search",
"listingType": "for-sale",
"locations": ["Sandton", "Umhlanga"],
"propertyType": "house",
"minPrice": 1000000,
"maxPrice": 3000000,
"minBedrooms": 3,
"sortBy": "price-asc",
"maxListings": 200,
"fetchDetails": true
}

Rentals:

{
"mode": "search",
"listingType": "to-rent",
"locations": ["Cape Town"],
"maxListings": 100
}

URL mode: supported URL shapes

Behaviour note: with mode set to url and the urls field left untouched, the actor now scrapes the built-in examples below (one per shape) instead of returning nothing. Clear the field and paste your own URLs to avoid this.

URL shapeExample pathHandling
City search/for-sale/cape-town/western-cape/432Scraped
Paginated search.../432/p2Scraped, walks forward from the given page
Filtered / sorted search.../432?sp=pf%3D1000000%26pt%3D3000000%26so%3DPriceLowScraped, pasted filters and sort are kept
Rent search/to-rent/sandton/gauteng/109Scraped
Commercial for sale / to rent/commercial-property-for-sale/..., /commercial-property-to-rent/...Scraped
Suburb search/for-sale/gardens/cape-town/western-cape/9145Scraped
Province search/for-sale/western-cape/9Scraped
Listing detail/for-sale/<suburb>/<city>/<province>/<id>/<listing>Scraped in full
Mobile hostm.property24.com/...Converted to www.property24.com, then scraped
New developments (search and detail)/new-developments-for-sale/...Skipped with a warning in the log
Estate agent profile/estate-agents/...Skipped with a warning in the log
Estate agency directory/estate-agencies/...Skipped with a warning in the log

Direct URLs (search pages and single listings, mixed):

{
"mode": "url",
"urls": [
"https://www.property24.com/for-sale/cape-town/western-cape/432",
"https://www.property24.com/for-sale/belhar/cape-town/western-cape/8132/117073882"
],
"maxPages": 3
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/property24-scraper").call(run_input={"mode": "search", "locations": ["Cape Town"], "maxListings": 50})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["title"], listing["displayPrice"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/property24-scraper').call({ mode: 'search', locations: ['Cape Town'], maxListings: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Incremental mode

Set incrementalMode to track one search over time. The baseline is stored per state key (derived from your search settings unless you set stateKey). Each returned row gains changeType (NEW, UPDATED, REAPPEARED, EXPIRED or UNCHANGED), changedFields, firstSeenAt and lastSeenAt; the Changes view shows them. Unchanged listings are skipped unless emitUnchanged is on. EXPIRED rows appear only with emitExpired and only after a complete scan: a run that hits Max Listings, a page limit, a failed page or a resume never marks anything EXPIRED. Billing: the result and detail-enrichment events are charged only for delivered NEW, UPDATED and REAPPEARED rows; UNCHANGED and EXPIRED rows are never charged, even when returned. The scrape time is always ignored when comparing; add other fields to ignoreFieldsForChanges.

Run size and resume

  • Max Listings is the run cap across every search or URL, divided evenly across them. Leave Max Pages Per Search empty to let Max Listings decide how far each search goes, or set it to cap result pages per search directly.
  • Resume from a previous run (delta) (resumeFromRunId): paste a previous run ID or dataset ID and this run skips every listing already collected there, returning only new listings. Combine both datasets for the full set. For scheduled monitoring that also reports price changes and removed listings, use Incremental mode above.
  • If a run is interrupted by a platform migration, an internal checkpoint restores the same run's progress automatically so nothing already collected is re-scraped or re-charged.

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 and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  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.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch builds URLs from the fields below; url scrapes the URLs you paste.
listingTypestringfor-salefor-sale (Buy), to-rent (Rent), commercial-for-sale, or commercial-to-rent (search mode). The commercial options search Property24's separate commercial vertical.
locationsarraynone (prefill: ["Cape Town"])Suburb, city or province names (search mode). Resolved automatically.
propertyTypestringanyNarrow to house, apartment, townhouse, vacant land, farm, commercial, or industrial (applied to results).
minPriceintegernoneMinimum price in Rand (search mode).
maxPriceintegernoneMaximum price in Rand (search mode).
minBedroomsintegernoneMinimum bedrooms (search mode). Only the minimum is sent in the search request; both min and max are applied to results.
maxBedroomsintegernoneMaximum bedrooms (search mode). Applied to results; not sent in the search request.
minBathroomsintegernoneMinimum bathrooms (search mode).
parkingSpacesintegernoneMinimum parking spaces or garages (search mode).
minErfSizeintegernoneMinimum erf (land) size in m² (search mode).
minFloorSizeintegernoneMinimum floor size in m² (search mode).
hasPoolbooleanfalseOnly listings with a swimming pool.
hasGardenbooleanfalseOnly listings with a garden.
hasFlatletbooleanfalseOnly listings with a flatlet / granny flat.
petFriendlybooleanfalseOnly pet-friendly listings.
securityEstatebooleanfalseOnly listings inside a security estate.
repossessedbooleanfalseOnly bank-repossessed properties.
retirementbooleanfalseOnly retirement listings.
sortBystringdefaultnewest, price-asc, price-desc, or size.
onShowOnlybooleanfalseOnly listings with a scheduled show day.
auctionsOnlybooleanfalseOnly properties going to auction.
urlsarrayone example per supported shape (14 URLs)Property24 URLs to scrape (url mode). Filter fields are ignored in this mode.
fetchDetailsbooleantrueOpen each listing for GPS, full description, photos, agent, agency, and the property overview.
startUrlsarraynoneAlias of urls (accepts the standard request-list format); use either.
maxItemsintegernoneAlias of maxListings; use either.
maxPagesintegernoneOptional bound on result pages walked per search (about 45 listings per page). Leave empty to walk every result page; the run size is controlled by maxListings, which this field defers to.
maxListingsinteger20THE run cap: max listings across all searches. 0 for unlimited.
incrementalModebooleanfalseRemember listings between runs and label each row NEW, UPDATED, REAPPEARED or EXPIRED.
stateKeystringderived from the searchName of the saved baseline.
emitUnchangedbooleanfalseAlso return UNCHANGED listings (never charged).
emitExpiredbooleanfalseReturn EXPIRED rows for listings gone from a complete scan (never charged).
ignoreFieldsForChangesarraynoneTop-level fields that must not count as a change.
resumeFromRunIdstringnoneID of a previous run of this actor (or a dataset ID). Listings already in that dataset are skipped, so this run returns only new listings (a delta).
proxyobjectnone (prefill: Apify Proxy with the Residential group)Connection settings.
mcpConnectorsarraynoneOptional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstringnoneNotion connector only: page under which records are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

The dataset has two views in the Console: Overview (core columns) and Detail (GPS, agent, agency and overview fields).

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"listingNumber": "100000001",
"url": "https://www.property24.com/for-sale/sample-suburb/sample-city/western-cape/0000/100000001",
"listingType": "For Sale",
"title": "3 Bedroom House for sale in Sample Suburb",
"price": 2600000,
"displayPrice": "R 2 600 000",
"currency": "ZAR",
"priceOnApplication": false,
"bedrooms": 3,
"bathrooms": 2,
"garages": 2,
"floorSize": 248,
"erfSize": 554,
"propertyType": "House",
"suburbName": "Sample Suburb",
"cityName": "Sample City",
"provinceName": "Western Cape",
"provinceId": "9",
"latitude": -33.0000,
"longitude": 18.0000,
"descriptionHeader": "Sample headline for the listing.",
"description": "Full listing description text appears here when Fetch Detail Pages is on.",
"agencyName": "Sample Agency",
"agentName": "Agent Name",
"contacts": [{ "id": 0, "name": "Agent Name", "contactType": "Agent", "jobTitle": "Property Practitioner", "hasContactNumber": true }],
"keyFeatures": ["Bedrooms 3", "Bathrooms 2", "Garden"],
"propertyOverview": { "Type of Property": "House", "Erf Size": "554 m2" },
"photos": [{ "imageIdentifier": "000000000", "imageUrl": "https://images.prop24.com/000000000/Ensure960x540" }],
"photoCount": 1,
"datePosted": "2026-01-01",
"scrapedAt": "2026-01-01T00:00:00.000000+00:00"
}

Plan Requirement

Residential proxy is recommended. In our measurement through Apify proxies, the Residential group (South Africa) loaded every search and listing page we tried (8 of 8), while the Apify datacenter group loaded only 2 of 5 search pages and 1 of 5 listing pages; the rest came back as a short rejection stub from Property24. The input form comes pre-filled with the Residential option, which needs an Apify plan that includes Residential proxy. If you choose a datacenter group, the actor uses it as selected and retries on a fresh exit when a request is rejected, so expect gaps. API calls that leave the proxy field out start on the default connection and the actor checks whether Residential is available to your account.

If Residential is not available (for example on an Apify free plan), the run logs this warning and continues on a backup connection:

The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable.

If no connection can be opened at all, the run stops with: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required." If the backup connection also cannot load the pages, the run ends with "No results: residential proxies are unavailable on this run ... Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again." Any other run where no page loads ends with "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?

This actor uses pay-per-event pricing with three events: an actor-start event charged once per run, a result event charged for each listing delivered to the dataset, and a detail-enrichment event charged for each listing detail page fetched, only when Fetch Detail Pages is on. This applies to pasted listing URLs too: with Fetch Detail Pages off, a pasted listing URL is charged the result event only. In Incremental mode, UNCHANGED and EXPIRED rows are never charged, even when returned. The Pricing tab shows the current rates. Use Max Listings and Fetch Detail Pages to control the cost of any run.

This actor collects only publicly available listing data. You are responsible for how you use it: follow Property24's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing prices and specifications are generally facts, but photos and agency branding may be subject to third-party rights.

Can I get only new listings on a schedule?

Yes. Switch on Incremental mode (incrementalMode) and schedule the actor with the same search: each row is labelled NEW, UPDATED (with changedFields), REAPPEARED or EXPIRED, and unchanged listings are skipped. resumeFromRunId remains available as a simple one-way delta against a past run.

Why are GPS coordinates, photos or the full description missing from my results?

Those fields only populate when Fetch Detail Pages is on. With it off, you get the faster, cheaper search-result fields only (price, beds, baths, floor and erf size, suburb, a short excerpt and a main image).

Why did my run return an empty dataset instead of failing?

An empty dataset usually means none of your Locations could be resolved to a Property24 area, or none of your Property24 URLs were valid or reachable; check the run log for "Could not resolve location" or similar warnings. The run fails outright only when resumeFromRunId points to a run or dataset it cannot read, since continuing would risk re-collecting and re-charging listings you already have.

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...
🏠 Fotocasa.es
Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths...
🏠 Trulia Scraper
Scrape Trulia.com property listings by location, filters, or URL. Extract prices, beds...
🏠 Commercial Property AU Scraper
Scrape Australian commercial property listings with full detail data. Extract...
🏠 Zonaprop Argentina
Scrape Zonaprop.com.ar property listings across Argentina. Extract 140+ fields including...
🏨 Hipflat Scraper Thailand Property & Projects
Scrape hipflat.co.th property listings and new-project data across Thailand: price, price...

👉 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.