# PropertyGuru Property Scraper (`sian.agency/propertyguru-property-scraper`) Actor

Scrape PropertyGuru listings across Singapore, Malaysia and Thailand: asking price, PSF, beds, baths, floor area, tenure, district, nearest MRT, agent name, licence and phone. Sale and rent. Export JSON, CSV or Excel.

- **URL**: https://apify.com/sian.agency/propertyguru-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 $2.64 / 1,000 property 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

## PropertyGuru Scraper - Singapore, Malaysia & Thailand Property 🚀

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian)[![99.co Property Scraper](https://img.shields.io/badge/Store-99.co%20Property%20Scraper-1AE392)](https://apify.com/sian.agency/99co-property-scraper?fpr=sian)[![Rightmove Property Scraper](https://img.shields.io/badge/Store-Rightmove%20Property%20Scraper-00DEB6)](https://apify.com/sian.agency/rightmove-property-scraper?fpr=sian)[![Redfin Property Scraper](https://img.shields.io/badge/Store-Redfin%20Property%20Scraper-A02021)](https://apify.com/sian.agency/redfin-property-scraper?fpr=sian)

#### 🎉 Three countries, one Market dropdown — 56,381 Singapore listings for sale, 224,072 Malaysian, 110,965 Thai

##### Asking price, PSF, beds, baths, floor area, tenure, district and nearest MRT on every row, plus the agent's name, CEA licence and phone number

***

### 🔎 What is the PropertyGuru Property Scraper — and when should you use it?

The **PropertyGuru Property Scraper** turns any PropertyGuru search across Singapore, Malaysia and Thailand 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:** asking prices in the local currency with price per square foot already computed, floor area, bedrooms and bathrooms, tenure, district code and name, build year and the walking time to the nearest MRT or BTS station, for property to buy or to rent. Every row names the listing agent, their licence number and their agency. Turning on detail enrichment adds the full description as plain text, GPS coordinates, the postcode and street, the developer, furnishing, floor level, completion date, the building's facility list, every photo, and the agent's mobile number. One Market field switches between propertyguru.com.sg, propertyguru.com.my and ddproperty.com, and the output shape does not change between them.

**Use something else when:** the property is outside Singapore, Malaysia or Thailand. Use [99.co Property Scraper](https://apify.com/sian.agency/99co-property-scraper?fpr=sian) for the other major Singapore portal, for cross-checking the same market. Use [Rightmove Property Scraper](https://apify.com/sian.agency/rightmove-property-scraper?fpr=sian) for the United Kingdom. Use [Smart Idealista Scraper](https://apify.com/sian.agency/smart-idealista-scraper?fpr=sian) for Spain, Italy and Portugal. Batdongsan.com.vn belongs to the same corporate group but runs on a different platform, so it is not covered here and this actor cannot be pointed at it. This reads live advertisements only: there are no sold prices and no transaction history, because PropertyGuru does not publish them — Singapore's transaction record comes from URA and HDB instead. HDB is Singapore public housing and returns nothing on the Malaysian or Thai sites. Prices stay in SGD, MYR or THB and are never converted.

### 🤖 Use with AI agents

Already connected to the [Apify MCP server](https://mcp.apify.com)? Just ask for this Actor by name: sian.agency/propertyguru-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 to research Southeast Asian property markets, or to build a list of the agents active in one using the Apify Actor `sian.agency/propertyguru-property-scraper`.

Use it when I need: asking prices in the local currency with price per square foot already computed, floor area, bedrooms and bathrooms, tenure, district code and name, build year and the walking time to the nearest MRT or BTS station, for property to buy or to rent. Every row names the listing agent, their licence number and their agency. Turning on detail enrichment adds the full description as plain text, GPS coordinates, the postcode and street, the developer, furnishing, floor level, completion date, the building's facility list, every photo, and the agent's mobile number. One Market field switches between propertyguru.com.sg, propertyguru.com.my and ddproperty.com, and the output shape does not change between them.

Don't use it when: the property is outside Singapore, Malaysia or Thailand — use 99co-property-scraper or rightmove-property-scraper or smart-idealista-scraper instead.

How to call it: set `market` to `sg`, `my` or `th` and `listingType` to `sale` or `rent`. Narrow with `propertyGroup` — `N` for condo, apartment and executive condo, `H` for HDB flats, `L` for landed houses, or leave it empty for every type — and with `bedrooms` (`studio` or `1` to `5`, an exact count rather than a minimum), `minPrice`, `maxPrice`, `minSizeSqft` and `maxResults`. Prices are whole units of the local currency, so `800000` means S$800,000 on a sale search and S$800 a month on a rental one. `includeDetails` opens each property's own page for the description, coordinates, postcode, developer, facilities, every photo and the agent's phone number, at an extra charge per property. To expand properties you already have, set `operation` to `detail` and pass `listingUrls`; to reuse a search you built on the site with filters this form does not expose, paste the browser address into `searchUrls` and it is used verbatim.

Start with this input:
{
  "operation": "search",
  "market": "sg",
  "listingType": "sale",
  "propertyGroup": "N",
  "bedrooms": "3",
  "minPrice": 800000,
  "maxPrice": 1500000,
  "maxResults": 120
}

Ask me which of the three markets they mean, whether they are buying or renting, and whether they want the agent's phone number, then run the Actor and summarise the results as a table.
```

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

- *Pull every 3-bedroom condo for sale in Singapore between S$800k and S$1.5m and rank the districts by median price per square foot.*
- *Build me a contact list of the agents listing HDB resale flats in Singapore right now, with their licence numbers and phone numbers.*
- *Compare asking rents for 2-bedroom condos in Singapore against Kuala Lumpur and tell me the gap in local currency.*

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

### 📋 Overview

**Pick a market, set your filters, press Start.** Live PropertyGuru and DDproperty advertisements come back as flat rows you can sort, filter and export. Built for property investors, valuers, estate agencies and proptech teams working Southeast Asian housing.

**What you get:**

- ✅ **Three markets on one output shape**: propertyguru.com.sg, propertyguru.com.my and ddproperty.com all run the same application build, so the Market dropdown is the only thing that changes between them.
- 📞 **The agent, not only the property**: name, agency, CEA licence number and profile link on every search row; the mobile number and review score on every detail row.
- 🎯 **Filters that were actually applied**: PropertyGuru accepts several filters and then quietly ignores them. This actor sends each one the way the site honours it and checks the response before a row is billed.
- 💰 **$3.00 per 1,000 properties** at the Bronze rate, charged per row returned and never for a failed one.
- 📊 **PSF already computed**: price per square foot arrives with the row, so a district-level asking-price index is a group-by rather than a modelling job.
- 🧾 **Honest row counts**: 20 organic properties per page, deduplicated across pages, with sponsored ads that fall outside your price or size range dropped instead of billed.
- 🚇 **Nearest MRT with walking distance**: district code, district name, region and the station itself, in the form "11 min (940 m) from CR8 Hougang MRT Station".
- 🌏 **Local currency, no conversion**: SGD, MYR and THB come back as published, with the currency in its own column.

***

### ✨ Features

- 🔍 **Property Search**: sweep a market by sale or rent, property type, bedrooms, price band and minimum floor area.
- 📄 **Property Detail**: open a single listing for its description, GPS coordinates, postcode, developer, facilities, every photo and the agent's phone.
- 🔗 **Paste-a-URL search**: any PropertyGuru or DDproperty search URL is used exactly as given, so filters this form does not expose still work.
- 🏬 **HDB, condo and landed**: the three Singapore property groups as separate options, alongside "any type".
- 📞 **One switch for enrichment**: turn on details and every search row gains the description, coordinates, facilities, photo set and agent mobile.
- 🧭 **Coordinates on detail rows**: latitude and longitude, so results drop straight onto a map or into a GIS layer.
- 📸 **Complete photo galleries**: the full image set per property, not the thumbnail alone.
- 📊 **Run report**: an HTML summary in the key-value store with the counts, any failures and what the run cost.
- 📤 **Export anywhere**: JSON, CSV, Excel or the Apify API, straight into a sheet, a database or a CRM.

***

### 🎬 Quick Start

Choose Singapore, Malaysia or Thailand. Set sale or rent and a price band. Run the Actor and collect the dataset.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~propertyguru-property-scraper/runs?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"operation":"search","market":"sg","listingType":"sale","propertyGroup":"N","maxResults":60}'
```

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Pick the market and the slice

Singapore, Malaysia or Thailand. Sale or rent. Condo and apartment, HDB flat, landed, or any type. Add a bedroom count, a price band or a minimum floor area if you want a narrower sweep.

#### Step 2: Say how many properties you want

Set the maximum. Each page returns 20 properties, so the run stops at the first page that crosses your limit. Turn on the enrichment switch if you need descriptions, coordinates and agent phone numbers.

#### Step 3: Run and export

Press Start. Rows land in the dataset as they arrive, and you can download them as JSON, CSV or Excel the moment the run finishes.

**That's it! In a couple of minutes, you'll have:**

- A clean table of live listings with price, PSF, floor area, beds, district and nearest MRT on every row
- The listing agent's name, agency and CEA licence, with the mobile number where you asked for details
- A run report showing what came back, what failed and what it cost

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| operation | string | No | search (walk a search page) or detail (full record for property URLs). Default: search |
| market | string | No | sg (propertyguru.com.sg), my (propertyguru.com.my) or th (ddproperty.com). Default: sg |
| listingType | string | No | sale or rent. Default: sale |
| propertyGroup | string | No | Empty for any type, N for condo/apartment/EC, H for HDB flat, L for landed. Default: empty |
| bedrooms | string | No | Empty for any, or studio, 1, 2, 3, 4, 5. An exact count, not a minimum |
| minPrice | integer | No | Lowest asking price, in the market's own currency and whole units. 0 for no floor |
| maxPrice | integer | No | Highest asking price, same units. 0 for no ceiling |
| minSizeSqft | integer | No | Smallest floor area in square feet. 0 for no floor |
| maxResults | integer | No | How many properties to return, 1 to 10000. Default: 60 |
| searchUrls | array | No | PropertyGuru or DDproperty search URLs, used exactly as given. Overrides the filters above |
| listingUrls | array | No | Property URLs for the detail operation. Filling this switches the run to detail |
| includeDetails | boolean | No | Add description, coordinates, postcode, developer, facilities, photos and agent phone to every search row. Default: false |

**Example: 3-bedroom Singapore condos above S$800,000**

```json
{
  "operation": "search",
  "market": "sg",
  "listingType": "sale",
  "propertyGroup": "N",
  "bedrooms": "3",
  "minPrice": 800000,
  "maxResults": 200
}
```

**Example: Malaysian rentals with agent phone numbers**

```json
{
  "operation": "search",
  "market": "my",
  "listingType": "rent",
  "minPrice": 1000,
  "maxPrice": 5000,
  "maxResults": 100,
  "includeDetails": true
}
```

**Example: a search you built on the site yourself**

```json
{
  "operation": "search",
  "searchUrls": [
    { "url": "https://www.propertyguru.com.sg/property-for-sale/with-3-bedrooms?minPrice=800000" },
    { "url": "https://www.ddproperty.com/en/property-for-sale" }
  ],
  "maxResults": 120
}
```

**Example: full records for properties you already have**

```json
{
  "operation": "detail",
  "listingUrls": [
    { "url": "https://www.propertyguru.com.sg/listing/for-sale-the-florence-residences-500176941" }
  ]
}
```

***

### 📤 Output

Every row is flat JSON, exportable as CSV, JSON, Excel or through the API. Search rows carry the listing, the location and the agent; detail rows add the description, coordinates, facilities, photos and the agent's phone number.

| Field | Type | Description |
|-------|------|-------------|
| listingId | integer | PropertyGuru listing number |
| propertyTitle | string | Listing headline as published |
| listingUrl | string | Direct link to the property |
| market | string | sg, my or th |
| listingType | string | sale or rent |
| propertyType / propertyTypeGroup | string | Condo, HDB, landed and the group it belongs to |
| price / priceText / currency | number / string / string | Asking price, the string as shown, and SGD, MYR or THB |
| priceType | string | Price basis, including "Price on ask" where the seller publishes no figure |
| pricePerArea | string | Price per square foot as the site computes it |
| floorArea / floorAreaText | number / string | Floor area in square feet and the text beside it |
| bedrooms / bathrooms | integer | Room counts |
| fullAddress / shortAddress | string | Address as published and the area name |
| districtCode / districtText / regionText | string | District code such as D19, its name, and the region |
| tenure / builtYear | string / integer | Freehold or leasehold, and the completion year |
| nearestTransit | string | Nearest station with walking time and distance |
| agentName / agentId / agentLicense | string / integer / string | Listing agent, their id and CEA licence number |
| agentProfileUrl / agencyName / listerType | string | Agent profile link, agency and whether an agent or owner listed it |
| photoCount / thumbnailUrl | integer / string | Photo count and the cover image |
| postedOn / isVerified / isSponsored | string / boolean / boolean | Listing date, verified flag and promoted flag |
| description | string | Full listing description, plain text (detail) |
| latitude / longitude / postcode / streetName | number / string | Map coordinates and street address (detail) |
| developer / furnishing / floorLevel / completionText | string | Developer, furnishing, floor band and TOP date (detail) |
| agentMobile / agentRating / agentReviewCount | string / number / integer | Agent phone, rating and review count (detail) |
| facilities / photoUrls | array | Building facilities and the full image set (detail) |
| source / scrapedAt | string | Whether the row came from a search or a detail page, and when |

**Example row (trimmed):**

```json
{
  "listingId": 500176941,
  "propertyTitle": "The Florence Residences",
  "listingUrl": "https://www.propertyguru.com.sg/listing/for-sale-the-florence-residences-500176941",
  "market": "sg",
  "listingType": "sale",
  "propertyType": "Condominium",
  "propertyTypeGroup": "N",
  "price": 1580000,
  "priceText": "S$ 1,580,000",
  "currency": "SGD",
  "priceType": "Asking price",
  "pricePerArea": "S$ 1,834 psf",
  "floorArea": 861,
  "floorAreaText": "861 sqft",
  "bedrooms": 2,
  "bathrooms": 2,
  "fullAddress": "21 Hougang Avenue 2",
  "districtCode": "D19",
  "districtText": "Hougang / Punggol / Sengkang",
  "regionText": "North East",
  "tenure": "99-year leasehold",
  "builtYear": 2023,
  "nearestTransit": "11 min (940 m) from CR8 Hougang MRT Station",
  "agentName": "Jane Tan",
  "agentLicense": "R012345A",
  "agencyName": "PropNex Realty",
  "agentMobile": "+65 9123 4567",
  "latitude": 1.372,
  "longitude": 103.888,
  "postcode": "538768",
  "developer": "Logan Property",
  "completionText": "TOP in Sep 2023",
  "facilities": ["Swimming pool", "Gym", "Tennis court"],
  "photoCount": 18,
  "source": "detail",
  "scrapedAt": "2026-09-06T09:14:22.310Z"
}
```

***

### 💼 Use Cases & Examples

#### 1. Singapore property market tracking

**A research team wants an asking-price series for a district without buying a subscription.**

**Input:** A Singapore sale or rent search for one district, or the whole island, on a weekly schedule.
**Output:** Asking price, floor area and price per square foot on every live advertisement.
**Use:** Group by district and week and you have an asking-price and time-on-market index you own.

#### 2. Agent and agency lead lists

**An agency recruiter wants the agents already listing in the price band they compete in.**

**Input:** A market and property type, price band set, enrichment switched on.
**Output:** Agent name, CEA licence number, agency, profile link, mobile number and review score.
**Use:** A contactable list of the agents active this week, rather than a directory compiled two years ago.

#### 3. Cross-border portfolio screening

**An investor is comparing Kuala Lumpur yields against Singapore ones.**

**Input:** The same search run three times, once per market.
**Output:** Identical columns for all three countries, with a currency field on each row.
**Use:** One table instead of three schemas, so the comparison is a filter rather than an integration project.

#### 4. Rental yield and comparables

**A valuer needs gross yield per building, not a headline city average.**

**Input:** A sale search and a rent search over the same project or district, collected the same day.
**Output:** Price, floor area, tenure, build year and nearest MRT on both sides.
**Use:** Divide one by the other for a per-building yield, with a comparables table attached.

#### 5. New launch and developer monitoring

**A developer's analyst tracks competing launches as they release stacks.**

**Input:** A watchlist of listing URLs through the detail operation, on a schedule.
**Output:** Developer name, TOP or completion date, tenure and the full project description.
**Use:** Diff between runs to catch price changes and newly released units the day they appear.

#### 6. Proptech and valuation data pipelines

**A proptech founder needs live Southeast Asian inventory behind their own search product.**

**Input:** Scheduled runs per market, results pulled through the Apify API.
**Output:** Flat JSON with stable keys, the same shape for all three countries.
**Use:** Land it in a warehouse without a transform step and rebuild the index nightly.

***

### 🔗 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/propertyguru-property-scraper').call({
  operation: 'search',
  market: 'sg',
  listingType: 'sale',
  propertyGroup: 'N',
  bedrooms: '3',
  minPrice: 800000,
  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/propertyguru-property-scraper').call(run_input={
    'operation': 'search',
    'market': 'my',
    'listingType': 'rent',
    'minPrice': 1000,
    'maxPrice': 5000,
    'maxResults': 100,
    'includeDetails': True,
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['listingId'], item['price'], item.get('agentMobile'))
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~propertyguru-property-scraper/runs?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "operation": "detail",
    "listingUrls": [{ "url": "https://www.propertyguru.com.sg/listing/for-sale-the-florence-residences-500176941" }]
  }'
```

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

1. **Trigger**: a daily schedule, or a webhook from your own system
2. **HTTP Request**: start the Actor with your market and filters
3. **Process**: read the dataset and drop rows already seen, matching on listing ID
4. **Action**: write new properties to a sheet, a CRM or a Slack alert

***

### 💰 Performance & Pricing

#### FREE tier (try it now)

- **25 rows per run**, full feature access and the same data quality
- No credit card required
- Enough to check the fields and the format before you commit

#### PAID tier (production)

- **Unlimited rows per run**, up to what the site serves for a single search
- 20 properties arrive per page, deduplicated across pages
- Pay per row returned: a failed item is never charged

| Event | Price | Per 1,000 |
|---|---:|---:|
| Actor Start | $0.005 per run | — |
| Property returned from a search | $0.00300 | $3.00 |
| Full property detail record | $0.04000 | $40.00 |

💰 **The agent's phone number is inside the detail charge, not beside it.** One detail record buys the description, coordinates, postcode, developer, furnishing, floor level, the full photo set, the facilities and the agent's mobile, rating and review count. Rates above are the Bronze tier, and higher Apify plans pay less per event.

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

***

### ❓ FAQ — Frequently Asked Questions

**Q: Do I need a PropertyGuru account or an API key?**
A: No. Pick a market and press Start.

**Q: Does this cover Malaysia and Thailand as well as Singapore?**
A: Yes. propertyguru.com.sg, propertyguru.com.my and ddproperty.com run the same application build, so one Market dropdown switches between them and every output column stays the same. Prices come back in the local currency and are never converted.

**Q: What about Batdongsan in Vietnam?**
A: Not covered. It belongs to the same group but runs on a different platform, so it needs its own parser rather than a flag on this one. Better an honest gap than a column that arrives empty.

**Q: Can I get the agent's phone number?**
A: Yes, on detail rows. Turn on the enrichment switch, or pass property URLs directly. Search rows carry the agent's name, CEA licence and agency but not the mobile number, because the site only publishes it on the property's own page.

**Q: Can I get sold prices?**
A: No. PropertyGuru publishes live advertisements. Singapore's transaction record is published by URA and HDB, and an asking price is not a substitute for it.

**Q: Why are there fewer rows than the site's result count suggests?**
A: Two reasons, both deliberate. The same property is returned once even when it appears on several pages, and sponsored advertisements that fall outside the price or size you asked for are dropped instead of billed.

**Q: How do I search exactly what I see on the site?**
A: Build the search on PropertyGuru, copy the address out of the browser bar and paste it into Search URLs. It is used exactly as given, so anything the site can show is reachable, including filters this form does not expose.

**Q: How many properties can one run return?**
A: As many as the search holds. Singapore alone lists about 56,000 properties for sale and 22,000 for rent; Malaysia about 224,000 for sale. The Max properties field decides where a run stops.

**Q: What output formats are available?**
A: JSON, CSV and Excel from the dataset, or straight through the Apify API into your own system.

***

### 🐛 Troubleshooting

**The run returned zero rows**

- Open the same search in your browser. If the site shows no results for those filters, there is nothing to return.
- HDB exists only in Singapore, so an HDB search against the Malaysian or Thai site comes back empty. Switch the property type to any type or to condo.
- Check a pasted URL is a search page rather than a single property page. Property links belong in the Property URLs field.

**Fewer properties than I asked for**

- Pages arrive 20 at a time and duplicates across pages are removed once, so the total lands below a round number.
- On the FREE tier a run stops at 25 rows. Add a payment method in Apify Console to lift it.
- A narrow price band or floor-area minimum may simply hold fewer live advertisements than your maximum.

**No phone number on a row**

- Enrichment must be on, or use the Property Detail operation. Search rows alone carry the name, licence and agency but no mobile.
- Some agents publish no number, and those rows come back without one.

**A price field is empty**

- Listings marked "Price on ask" publish no figure. The price field stays empty rather than reporting zero, and the price basis field says why.

**A bedroom or price filter looked ignored**

- Bedrooms is an exact count rather than a minimum, so a 3-bedroom search excludes 4-bedroom units by design.
- Promoted advertisements that sit outside your price or size range are removed before billing, which is why a manual count on the site can differ.

***

### ⚖️ 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. Property listings include the agent's name, licence number and published contact details. Personal data is protected by the **GDPR** in the European Union, by Singapore's **PDPA**, 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/).

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- Questions, issues or feature requests → [Telegram support group](https://t.me/+vyh1sRE08sAxMGRi)
- Browse more tools → [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian)
- ✉️ <apify@sian-agency.online>

***

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

**⭐ Getting value from this actor? [Leave a 5-star review](https://apify.com/sian.agency/propertyguru-property-scraper/reviews) — it helps other property professionals find it.**

***

### ⚖️ Disclaimer

PropertyGuru and DDproperty are trademarks of PropertyGuru Group Limited. This actor is not affiliated with, endorsed by, or sponsored by PropertyGuru Group. All trademarks mentioned are the property of their respective owners.

# Actor input Schema

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

Pick one operation per run. Search returns twenty properties per page and is where the value is; Detail opens a single listing for its description, coordinates, facilities and the agent's phone number, and is priced as an add-on.

## `market` (type: `string`):

Which PropertyGuru site to search. All three run on one codebase, so every filter and every output column behaves the same way in each. Prices stay in the local currency: SGD in Singapore, MYR in Malaysia, THB in Thailand. Ignored when you paste your own search URLs, since the URL already names the site.

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

Sale is the larger side in Singapore (56,000 live ads against 22,000 rentals). Rental prices come back per month.

## `propertyGroup` (type: `string`):

Narrow to one slice of the market. Measured on Singapore for sale: any type 56,381 ads, condo and apartment 33,226, HDB 14,123, landed 9,046. HDB only exists in Singapore, so it returns nothing on the Malaysian or Thai sites.

## `bedrooms` (type: `string`):

An exact bedroom count, not a minimum. PropertyGuru only honours this as a path filter, so the actor writes it into the search path rather than the query string, where the site would drop it silently.

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

Lowest asking price to include, in the market's own currency and in whole units - 800000 means S$800,000 on a sale search and S$800 per month on a rental one. Leave at 0 for no floor.

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

Highest asking price to include, same units as the minimum. Leave at 0 for no ceiling. PropertyGuru injects a handful of sponsored ads that sit outside the price you asked for; those are dropped rather than returned and billed.

## `minSizeSqft` (type: `integer`):

Smallest floor area to include, in square feet, which is the unit all three sites quote. Leave at 0 for no floor.

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

Stop after this many properties. Each page returns twenty, so the run stops at the first page that crosses your limit.

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

Paste search URLs straight from PropertyGuru and they are used exactly as given, overriding every filter above. Anything the site can show, this can read: https://www.propertyguru.com.sg/property-for-sale/with-3-bedrooms?minPrice=800000, https://www.propertyguru.com.my/property-for-rent, https://www.ddproperty.com/en/property-for-sale. Build the search you want on the site, copy the address bar, paste it here.

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

Used by the Property Detail operation: PropertyGuru listing URLs to open, e.g. https://www.propertyguru.com.sg/listing/for-sale-the-florence-residences-500176941. Filling this switches the run to Detail.

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

Open every property's own page to add the full description, GPS coordinates, postcode, developer, tenure, furnishing, floor level, the complete photo set, the building's facilities and the agent's phone number. Costs one extra request per property and bills the Property Detail event on top of the search row, so a 100-property run bills 100 search rows plus 100 detail rows.

## Actor input object example

```json
{
  "operation": "search",
  "market": "sg",
  "listingType": "sale",
  "propertyGroup": "",
  "bedrooms": "",
  "minPrice": 0,
  "maxPrice": 0,
  "minSizeSqft": 0,
  "maxResults": 60,
  "searchUrls": [],
  "listingUrls": [],
  "includeDetails": false
}
```

# Actor output Schema

## `propertyguruProperties` (type: `string`):

Every property 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",
    "market": "sg",
    "listingType": "sale",
    "propertyGroup": "",
    "bedrooms": "",
    "minPrice": 0,
    "maxPrice": 0,
    "minSizeSqft": 0,
    "maxResults": 60,
    "searchUrls": [],
    "listingUrls": [],
    "includeDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/propertyguru-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",
    "market": "sg",
    "listingType": "sale",
    "propertyGroup": "",
    "bedrooms": "",
    "minPrice": 0,
    "maxPrice": 0,
    "minSizeSqft": 0,
    "maxResults": 60,
    "searchUrls": [],
    "listingUrls": [],
    "includeDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/propertyguru-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",
  "market": "sg",
  "listingType": "sale",
  "propertyGroup": "",
  "bedrooms": "",
  "minPrice": 0,
  "maxPrice": 0,
  "minSizeSqft": 0,
  "maxResults": 60,
  "searchUrls": [],
  "listingUrls": [],
  "includeDetails": false
}' |
apify call sian.agency/propertyguru-property-scraper --silent --output-dataset

```

## MCP server setup

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