# Private Property Scraper - South Africa Listings & API (`sian.agency/privateproperty-property-scraper`) Actor

Scrape privateproperty.co.za for sale and to rent across all 9 South African provinces: price, beds, baths, erf and floor size, levies, rates, suburb, agent, on-show and repossessed stock. JSON, CSV or Excel.

- **URL**: https://apify.com/sian.agency/privateproperty-property-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.89 / 1,000 area searches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

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

## Private Property Scraper — South Africa Listings & Real Estate API 🏘️

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Property24 Scraper](https://img.shields.io/badge/Store-Property24%20Scraper-1AE392)](https://apify.com/sian.agency/property24-property-scraper?fpr=sian) [![Rightmove Scraper](https://img.shields.io/badge/Store-Rightmove%20Scraper-00DEB6)](https://apify.com/sian.agency/rightmove-property-scraper?fpr=sian) [![Smart Idealista Scraper](https://img.shields.io/badge/Store-Smart%20Idealista%20Scraper-E60023)](https://apify.com/sian.agency/smart-idealista-scraper?fpr=sian)

#### 🎉 Every South African listing as a typed row — price, erf size, levies, rates and the agency, in one export

##### Built for property analysts, buy-to-let investors, estate agencies and anyone tired of copying asking prices out of a browser tab

***

### 🔎 What is the Private Property South Africa Scraper — and when should you use it?

The **Private Property South Africa Scraper** turns public privateproperty.co.za listings from anywhere in South Africa into clean, structured rows you can filter, export and feed straight into a spreadsheet, database or AI agent. No account, no portal API key, no browser automation to maintain.

**Use it when you need:** South African sale and rental listings as rows: asking price or monthly rent in rands, bedrooms, bathrooms, parking, erf and floor size in square metres, the suburb, city and province, a photo, and the agency holding the mandate. Every row is also flagged new, price-reduced, under offer, sold or on show, and says whether the owner listed it themselves rather than an agency. Switch on the full record and each row additionally carries the listing text, the complete photo set, the listing date, the property type and — on for-sale stock — the levies and the rates and taxes.

**Use something else when:** the property is not in South Africa, or you want the other South African portal. Use [Property24 Scraper](https://apify.com/sian.agency/property24-property-scraper?fpr=sian) for the other South African portal, plus Namibia, Botswana, Zambia, Zimbabwe, Mozambique and Kenya, with the same column names so the two exports merge. Use [Rightmove Scraper](https://apify.com/sian.agency/rightmove-property-scraper?fpr=sian) for the UK, including sold prices. Use [Smart Idealista Scraper](https://apify.com/sian.agency/smart-idealista-scraper?fpr=sian) for Spain, Italy and Portugal. This actor covers the surfaces privateproperty.co.za publishes to a visitor: residential for sale and to rent, houses, apartments, townhouses, land and garden cottages, plus farms, commercial premises and the on-show list. Agent phone numbers are not on those pages, so they are not returned, and the portal publishes asking prices only — what a property actually sold for comes from the deeds office, not from here.

### 🤖 Use with AI agents

Already connected to the [Apify MCP server](https://mcp.apify.com)? Just ask for this Actor by name: sian.agency/privateproperty-property-scraper

**Your agent can pay for its own runs.** This Actor is eligible for [agentic payments](https://docs.apify.com/platform/actors/publishing/monetize), so an agent can discover it, run it and settle the bill over [x402](https://www.x402.org/) (USDC on Base) or [Skyfire](https://www.skyfire.xyz/) — without an Apify account or API token of its own. Billing is the same either way: per successful row, never for errors.

Otherwise copy this prompt into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```text
I want property listings and asking prices from privateproperty.co.za using the Apify Actor `sian.agency/privateproperty-property-scraper`.

Use it when I need: South African sale and rental listings as rows: asking price or monthly rent in rands, bedrooms, bathrooms, parking, erf and floor size in square metres, the suburb, city and province, a photo, and the agency holding the mandate. Every row is also flagged new, price-reduced, under offer, sold or on show, and says whether the owner listed it themselves rather than an agency. Switch on the full record and each row additionally carries the listing text, the complete photo set, the listing date, the property type and — on for-sale stock — the levies and the rates and taxes.

Don't use it when: the property is not in South Africa, or you want the other South African portal — use property24-property-scraper or rightmove-property-scraper or smart-idealista-scraper instead.

How to call it: give `locations` a list of South African places written as the portal writes them — a suburb ("Sea Point", "Midstream Estate"), a city ("Cape Town", "Durban"), a region ("Atlantic Seaboard") or a province ("Western Cape"). Names are matched against the portal's own published area index while the run starts, so there is no area id to look up, and a name that cannot be matched comes back with the nearest ones that were actually seen. Set `listingType` to `for-sale` or `to-rent`, or to `on-show`, `farms-for-sale`, `farms-to-rent`, `commercial-sales` or `commercial-rentals` for those sections. `propertyType` narrows the two residential sides to houses, apartments, townhouses, land or garden cottages. Narrow further with `minPrice`, `maxPrice`, `minBedrooms`, `minBathrooms` and `minParkingSpaces` — each goes to the portal's own filter, so anything excluded is never saved and never billed, and on the rental side the price bounds are monthly rent. `includeDetails` opens every listing for its full text, photo set, listing date, levies and rates, at an extra charge per listing. To expand listings you already have, set `operation` to `listing` and pass `listingUrls`; to run a search you built in your browser, paste it into `searchUrls` and it runs exactly as given.

Start with this input:
{
  "operation": "search",
  "locations": [
    "Sea Point",
    "Sandton"
  ],
  "listingType": "for-sale",
  "minPrice": 2000000,
  "maxPrice": 6000000,
  "maxResults": 200
}

Ask me which South African areas to cover, whether I want listings for sale or to rent, and whether the full listing text, photo set, levies and rates are worth the extra per-listing charge, then run the Actor and summarise the results as a table.
```

**Things you can ask your agent for:**

- *Pull apartments for sale in Sea Point between R3 million and R8 million and rank the buildings by price per square metre.*
- *Find three-bedroom houses to rent in Sandton under R35,000 a month, with the agency on every row.*
- *Give me this week's on-show listings in Cape Town and Pretoria with the suburb, asking price and a photo.*

Machine-readable API, MCP config and OpenAPI definition for this Actor are published at [apify.com/sian.agency/privateproperty-property-scraper.md](https://apify.com/sian.agency/privateproperty-property-scraper.md).

### 📋 Overview

**Two portals carry most of South Africa's residential stock, and this one covers the second of them properly.** It reads privateproperty.co.za the way a visitor does and writes every listing out as a row, with the numbers typed as numbers.

**What you get:**

- ✅ **Place names, not area ids**: type "Sea Point" or "Western Cape". Names resolve against the portal's own published area index while the run starts, so nothing is hard-coded and nothing rots.
- ⚡ **All nine provinces, at four grains**: province, city, region or suburb — plus the whole country if you leave the area list empty.
- 🎯 **Numbers that are numbers**: R 3 950 000 becomes `3950000`, and "735 m²" becomes `735`. No parsing project at the other end.
- 💰 **Charged per listing returned**: a search that matched nothing, and any input that could not be read, cost you nothing.
- 💎 **Levies, rates and map coordinates**: published on the for-sale side and returned on the full record, which most exports of this portal simply do not carry.
- ✨ **Column-for-column parity with our Property24 Scraper**: run both, stack the exports, and you have the South African market in one table.

***

### ✨ Features

- 🔍 **Area search**: sweep a suburb, city, region, province or the whole country and page through every result.
- 🏠 **Full listing record**: description, every photo, listing date, property type, levies, rates and taxes, and map coordinates where the portal publishes them.
- 📍 **Name-based areas**: 7,600-plus areas resolved from the portal's own index. A name that misses comes back with the nearest ones actually seen, not a bare failure.
- 🎚️ **Five filters that genuinely filter**: minimum and maximum price, minimum bedrooms, bathrooms and parking. Each was checked against the portal's own result count and against the rows it returns.
- 🏷️ **Seven sections**: for sale, to rent, on show this weekend, farms for sale, farms to rent, commercial for sale and commercial to rent.
- 🏘️ **Five property types**: houses, apartments and flats, townhouses, land and plots, and garden cottages.
- 🚩 **Status flags on every row**: new, price-reduced, under offer, sold or let, on show, and listed by the owner rather than an agency.
- 🔗 **Paste your own search**: a results page URL you built in the browser runs exactly as given, filters and all.
- 📤 **Export anywhere**: JSON, CSV or Excel straight out of the dataset, plus an HTML run report.

***

### 🎬 Quick Start

Pick your areas, pick for sale or to rent, press Start. The run tells you how many listings the portal holds for that search before it reads a single extra page, and stops at the row budget you set.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~privateproperty-property-scraper/runs?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "locations": ["Sea Point"], "listingType": "for-sale"}'
```

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Name your areas

Type the places as Private Property writes them: "Sea Point", "Cape Town", "Western Cape". Leave the field empty to sweep the whole country.

#### Step 2: Pick the section and narrow it

Choose for sale, to rent, on show, farms or commercial. Add a price band, a bedroom minimum or a parking minimum if you want a shortlist rather than the market.

#### Step 3: Press Start

Rows land in the dataset as they are found. Open the run report for a summary and one-click copy of every listing link.

**That's it! In under a minute, you'll have:**

- Every matching listing as a typed row
- Asking prices, sizes and room counts ready to sort and chart
- An export in JSON, CSV or Excel

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|---|---|---|---|
| `operation` | string | No | `search` (default) or `listing` |
| `locations` | array | No | Place names — suburb, city, region or province. Empty means the whole country |
| `listingType` | string | No | `for-sale`, `to-rent`, `on-show`, `farms-for-sale`, `farms-to-rent`, `commercial-sales`, `commercial-rentals` |
| `propertyType` | string | No | `houses`, `apartments`, `townhouses`, `land`, `garden-cottages`, or empty for any |
| `maxResults` | integer | No | Row budget for the run. Default 100 |
| `includeDetails` | boolean | No | Open each listing for the full record. Charged per listing |
| `minPrice` / `maxPrice` | integer | No | In rands; monthly rent on the to-rent side. 0 means no bound |
| `minBedrooms` | integer | No | At least this many bedrooms |
| `minBathrooms` | integer | No | At least this many bathrooms |
| `minParkingSpaces` | integer | No | At least this many parking spaces or garages |
| `searchUrls` | array | No | Results pages to read exactly as given. Overrides the area and filter fields |
| `listingUrls` | array | No | Individual listing pages. Switches the run to Listing Detail |

**Example:**

```json
{
  "operation": "search",
  "locations": ["Sea Point"],
  "listingType": "for-sale",
  "minPrice": 3000000,
  "maxPrice": 8000000,
  "minBedrooms": 2,
  "maxResults": 200
}
```

**Full record for listings you already have:**

```json
{
  "operation": "listing",
  "listingUrls": [
    { "url": "https://www.privateproperty.co.za/for-sale/western-cape/cape-town/atlantic-seaboard/sea-point/T5613080" }
  ]
}
```

***

### 📤 Output

Results are saved to the Apify dataset with **33 fields**. Search rows carry the first group; the full record adds the second.

| Field | Type | Description |
|---|---|---|
| `reference` | string | The portal's listing reference: `T…` for sale, `RR…` for rentals |
| `url` | string | The listing page |
| `listingTitle` | string | e.g. "2 Bedroom Apartment" |
| `price` | integer | Asking price in rands, or the monthly rent on the to-rent side |
| `suburb` / `city` / `province` | string | Where it is |
| `bedrooms` / `bathrooms` | number | Halves are real; a studio is 0.5 |
| `parkingSpaces` | number | Parking spaces or garages |
| `floorSizeSqm` / `landSizeSqm` | number | Floor area and erf size in square metres |
| `agencyName` | string | The agency holding the mandate |
| `listedPrivately` | boolean | Listed by the owner rather than an agency |
| `isNew` / `isPriceReduced` / `isUnderOffer` / `isSold` / `isOnShow` | boolean | Status flags |
| `listingDescription` | string | The listing text (full record) |
| `imageUrls` | array | Every photo (full record) |
| `listingDate` / `propertyType` | string | When it was listed, and how the portal classifies it (full record) |
| `levies` / `ratesAndTaxes` | integer | Monthly levies and municipal rates, for-sale listings only (full record) |
| `latitude` / `longitude` | number | Map coordinates, where the portal publishes them (full record) |

**Example:**

```json
{
  "reference": "T5613080",
  "listingId": 12057791,
  "url": "https://www.privateproperty.co.za/for-sale/western-cape/cape-town/atlantic-seaboard/sea-point/T5613080",
  "listingType": "for-sale",
  "listingTitle": "2 Bedroom Apartment in Sea Point",
  "price": 8750000,
  "priceText": "R 8 750 000",
  "suburb": "Sea Point",
  "city": "Cape Town",
  "province": "Western Cape",
  "streetAddress": "243 Strand beach, 243 High level road",
  "bedrooms": 2,
  "bathrooms": 2,
  "parkingSpaces": 2,
  "floorSizeSqm": 74,
  "landSizeSqm": 1728,
  "propertyType": "Apartment",
  "listingDate": "7 Sep 2026",
  "levies": 5500,
  "ratesAndTaxes": 3000,
  "latitude": -33.9159991,
  "longitude": 18.3934994,
  "agencyName": "SAProperty.com",
  "isUnderOffer": false
}
```

***

### 💼 Use Cases & Examples

#### 1. Suburb price tracking

**A property analyst wants the movement in asking prices in one suburb, week over week.**

**Input:** the suburb name and a for-sale search
**Output:** every listing with price, erf size, floor size and room counts as numbers
**Use:** run it on a schedule and the change is a subtraction, not a parsing project

#### 2. Buy-to-let and rental yield screening

**An investor is comparing gross yield across three suburbs.**

**Input:** the same areas run twice, once for sale and once to rent, with the full record on
**Output:** for-sale rows with levies and rates, rental rows with the monthly asking rent
**Use:** gross and net yield fall out of the two exports side by side

#### 3. Estate agency market share

**An agency principal wants to know who is carrying stock in their patch.**

**Input:** a city or region, a price band
**Output:** every listing with the agency holding the mandate, plus the owner-listed ones
**Use:** count listings by agency to see share, and spot the private sellers worth approaching

#### 4. On-show and new-listing monitoring

**A buyer's agent wants only what changed this week.**

**Input:** the on-show section for two or three cities
**Output:** the smaller, fresher set of listings with a scheduled show day, each flagged new or price-reduced
**Use:** a weekly shortlist that arrives without anyone refreshing a results page

#### 5. Relocation shortlists

**Someone moving to Cape Town wants a filtered list, not a browser full of tabs.**

**Input:** a suburb or region, a price band, a bedroom count, a parking minimum
**Output:** a clean shortlist with a photo, the suburb and, on the full record, map coordinates
**Use:** hand it to a spreadsheet or a map tool and pick

#### 6. Farm and commercial sourcing

**A commercial broker wants land and premises rather than homes.**

**Input:** the farms or commercial section, a province, a price ceiling
**Output:** the same row shape, with erf size and asking price
**Use:** the two verticals most residential exports of this portal simply skip

#### 7. Building a national dataset

**A data team wants the South African market in one table.**

**Input:** no area at all, a generous row budget, run alongside our Property24 Scraper
**Output:** two exports with the same column names
**Use:** stack them and deduplicate on address rather than reconciling two schemas by hand

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/privateproperty-property-scraper').call({
  operation: 'search',
  locations: ['Sea Point'],
  listingType: 'for-sale',
  maxResults: 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/privateproperty-property-scraper').call(
    run_input={
        'operation': 'search',
        'locations': ['Sandton'],
        'listingType': 'to-rent',
        'maxPrice': 35000,
    }
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~privateproperty-property-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "locations": ["Durban"], "listingType": "for-sale"}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: a weekly schedule, or a webhook from your own system
2. **HTTP Request**: call the Actor's run-sync endpoint
3. **Process**: filter the rows on price, suburb or the status flags
4. **Action**: write to Sheets or Airtable, or post the new listings to Slack

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 listings** per run — every field, every section, same quality
- No credit card required
- Enough to see the row shape before you commit

#### PAID Tier (Production Ready)

- **Unlimited** listings per run
- Pay per listing actually returned — errors and empty searches cost nothing
- The full record is a separate, optional charge, so a search-only run never pays for it

💰 **Priced where the market clears**: the same rate per row as our Property24 Scraper, so taking both South African portals costs the same per listing either way.

🔗 [View current pricing](https://apify.com/sian.agency/privateproperty-property-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: Do I need to find the portal's area id?**
A: No. Type the place name and it is matched against the portal's own published area index while the run starts. A name that cannot be matched comes back with the nearest ones actually seen.

**Q: How many listings can I get?**
A: FREE tier: 25 per run. PAID tier: unlimited, capped by the row budget you set.

**Q: Does it return agent phone numbers?**
A: No. The pages this Actor reads carry the agency name and sometimes the agent's name, not a number. That column is not offered rather than shipped empty.

**Q: Why are levies and rates empty on my rental rows?**
A: The portal publishes them on for-sale listings only. The same applies to map coordinates, which appear on roughly half of for-sale listings and far fewer rentals. A null means the portal does not publish it, not that the read failed.

**Q: Can I paste a search I built in my browser?**
A: Yes. Put the results page URL in Search URLs and it runs exactly as given, with whatever filters you set on the site. That overrides the area and filter fields.

**Q: What output formats are available?**
A: JSON, CSV and Excel, exported straight from the Apify dataset.

**Q: Does it cover sold prices?**
A: No. The portal publishes asking prices. What a property actually sold for comes from the deeds office.

**Q: Is this legal?**
A: Yes — only publicly available listing data is extracted. See the legal section below.

***

### 🐛 Troubleshooting

**"None of those places are areas on Private Property"**

- Use the place name as the portal writes it: a suburb, city, region or province.
- If a name exists twice, add the parent: "Hibberdene, KZN South Coast".
- The run log prints the nearest names it did see.

**The run returned no listings**

- Widen the price band, or lower the bedroom, bathroom and parking minimums.
- Some combinations do not exist: garden cottages are a rental category only.
- Try a larger area; a small suburb genuinely may hold nothing this week.

**Fewer rows than I expected**

- Check the row budget in `maxResults`, and the FREE tier's 25-row cap.
- The number the run prints first is the portal's own total for that search; if the budget is lower, that is where it stopped.

**A pasted search URL was skipped**

- It must be a privateproperty.co.za results page, not a listing page. A listing page belongs in Listing URLs.

**Levies, rates or coordinates are empty**

- Turn on the full record — those fields only come from the listing page.
- Even then they are for-sale only, and coordinates are partial. That is what the portal publishes.

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union, by **POPIA** in South Africa, and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

Private Property is a trademark of Private Property South Africa (Pty) Ltd. This Actor is not affiliated with, endorsed by, or sponsored by Private Property.

***

### 🤝 Support

**Join our active support community**

- For issues or questions, open an issue on the Actor's page
- Check the [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `operation` (type: `string`):

Pick one operation per run. Search sweeps an area and returns about 19 listing rows per page it reads; Listing Detail opens one listing and returns the full record for it, including the description, every photo, the map coordinates, levies and rates.

## `locations` (type: `array`):

Place names as Private Property writes them — a suburb ("Sea Point", "Midstream Estate"), a city ("Cape Town", "Durban"), a region ("Atlantic Seaboard") or a province ("Western Cape"). Names are matched against the portal's own published area index, so you never have to find an area id. Leave it empty to sweep the whole of South Africa. Ignored when you paste your own Search URLs.

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

Which side of the portal to read. "On show this weekend" returns only the stock with a scheduled show day, which is a much smaller and fresher set than for sale.

## `propertyType` (type: `string`):

Narrow to one type. Leave on "Any type" to get everything the area holds. Garden cottages exist only to rent; land and townhouses exist on both sides.

## `maxResults` (type: `integer`):

Stop after this many listings across all areas. Each page read returns about 19, so 100 costs six page reads.

## `includeDetails` (type: `boolean`):

Off by default. Turn it on to open every listing found and add the description, every photo, the map coordinates, the listing date, levies and rates and taxes. This reads one extra page per listing and is charged as Listing Detail on top of the search row.

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

In rands. For rentals this is the monthly asking rent, not a purchase price. 0 means no minimum.

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

In rands, and the monthly rent on the to-rent side. 0 means no maximum.

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

Returns listings with at least this many bedrooms. 0 means any, and also keeps studios and land, which carry no bedroom count at all.

## `minBathrooms` (type: `integer`):

Returns listings with at least this many bathrooms. 0 means any.

## `minParkingSpaces` (type: `integer`):

Returns listings with at least this many parking spaces or garages. 0 means any.

## `searchUrls` (type: `array`):

Paste privateproperty.co.za results pages you already have and they are read exactly as given, filters and all. When this is filled the Areas and filter fields above are ignored, so the URL you see in your browser is the search that runs.

## `listingUrls` (type: `array`):

Paste individual privateproperty.co.za listing pages to get the full record for each. This switches the run to Listing Detail and ignores every search field.

## Actor input object example

```json
{
  "operation": "search",
  "locations": [
    "Sea Point",
    "Sandton"
  ],
  "listingType": "for-sale",
  "propertyType": "",
  "maxResults": 100,
  "includeDetails": false,
  "minPrice": 0,
  "maxPrice": 0,
  "minBedrooms": 0,
  "minBathrooms": 0,
  "minParkingSpaces": 0,
  "searchUrls": [],
  "listingUrls": []
}
```

# Actor output Schema

## `privatePropertyListings` (type: `string`):

Every listing this run returned.

## `scrapingSummary` (type: `string`):

HTML summary showing successful and failed results with key metrics

# 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 = {
    "operation": "search",
    "locations": [
        "Sea Point",
        "Sandton"
    ],
    "listingType": "for-sale",
    "propertyType": "",
    "maxResults": 100,
    "includeDetails": false,
    "minPrice": 0,
    "maxPrice": 0,
    "minBedrooms": 0,
    "minBathrooms": 0,
    "minParkingSpaces": 0,
    "searchUrls": [],
    "listingUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/privateproperty-property-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 = {
    "operation": "search",
    "locations": [
        "Sea Point",
        "Sandton",
    ],
    "listingType": "for-sale",
    "propertyType": "",
    "maxResults": 100,
    "includeDetails": False,
    "minPrice": 0,
    "maxPrice": 0,
    "minBedrooms": 0,
    "minBathrooms": 0,
    "minParkingSpaces": 0,
    "searchUrls": [],
    "listingUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/privateproperty-property-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 '{
  "operation": "search",
  "locations": [
    "Sea Point",
    "Sandton"
  ],
  "listingType": "for-sale",
  "propertyType": "",
  "maxResults": 100,
  "includeDetails": false,
  "minPrice": 0,
  "maxPrice": 0,
  "minBedrooms": 0,
  "minBathrooms": 0,
  "minParkingSpaces": 0,
  "searchUrls": [],
  "listingUrls": []
}' |
apify call sian.agency/privateproperty-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sian.agency/privateproperty-property-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/kLQ8WdkxhA2k8MFlM/builds/bDiXMNg9RpQl5hxdj/openapi.json
