iProperty MY Scraper - Properties, Prices, Agents & Photos
Pricing
from $1.00 / 1,000 listing results
iProperty MY Scraper - Properties, Prices, Agents & Photos
Scrape property listings from iProperty.com.my for sale or rent: price, PSF, bedrooms, bathrooms, floor area, tenure, property type, full address, agent (name, license, agency, contact numbers) and photo gallery. Search and URL modes, filters, 6 sort orders, and optional detail enrichment.
Pricing
from $1.00 / 1,000 listing results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
4
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
iProperty.com.my Scraper: Property Listings, Prices, Agents & Photos
iProperty.com.my Scraper turns iProperty.com.my search results into structured property data. Search for sale or rent listings by channel, location, property type, price range and minimum bedrooms, or paste iProperty.com.my search and listing URLs directly, and get a record per property with price, price type, price-per-square-foot, bedrooms, bathrooms, floor area, tenure, the full address with region / district / area, the photo gallery, and the listing agent's name, license, verified status and agency. Two modes (search and URL), 6 sort orders, and location, property-type, price and bedroom filters. An optional detail pass adds the full description, map coordinates, and the agent's phone / WhatsApp contact numbers. Export results to JSON, CSV or Excel, or pull them straight into your app through the API.
Why This Scraper?
- ~50 fields on a search-mode listing: price type (e.g. Negotiable), price-per-square-foot, tenure, the full photo gallery, the region / district / area breakdown, and the agent / agency profile.
- Two ways in: build a search from channel + location + filters, or paste iProperty.com.my search and listing URLs directly. Search filters are ignored in URL mode so pasted links are used as-is.
- 6 sort orders (price, date, built-up size) and location, property-type, price and bedroom filters; the location box accepts plain text ("Petaling Jaya") or the site's own location slug pasted from your address bar.
- Optional detail enrichment adds the full property description, map coordinates (latitude / longitude), and the listing agent's phone and WhatsApp numbers, billed only on the listings it actually runs for.
- Built for schedules: Incremental mode returns only new and changed listings on recurring runs, and unchanged rows are never billed unless you ask for them.
- Export results straight into Notion, Linear, Airtable or Apify via MCP connectors, without touching the dataset.
Use Cases
- Property portals and lead generation: build a searchable inventory of for-sale or for-rent listings with price, address and agent contact for outreach.
- Market research and pricing analysis: track price-per-square-foot and asking prices across regions and property types over time.
- Listing monitoring: watch a specific location or price band on a schedule and get only the new and changed listings, without re-collecting everything.
- Investment screening: filter by price range, bedrooms and property type to shortlist properties matching an investment thesis.
- App and CRM feeds: pipe structured listings into your own site, CRM or spreadsheet through the API or MCP connectors.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
listingId | 900000001 |
title | "Sample Listing, Sample Area" |
propertyType | "Condominium" |
typeText | "For Sale" |
price | { "value": 650000, "pretty": "RM 650,000", "currency": "MYR", "type": "Negotiable" } |
priceType | "Negotiable" |
psf | "RM 480.00 psf" |
bedrooms / bathrooms | 3 / 2 |
floorArea | 1100 |
tenure | "Freehold" |
location | { "area": "Sample Area", "district": "Sample District", "region": "Selangor" } |
fullAddress | "Jalan Contoh, Sample Area, Sample District, Selangor" |
agent.name / agent.license | "Sample Agent" / "REN 00001" |
agent.isVerified | true |
agency.name | "Sample Realty Sdn. Bhd." |
agentRating | { "reviewCount": 0, "ratingAverage": 0 } |
imageCount | 1 (matches the length of images) |
thumbnail | "https://cdn.example.com/listing/900000001/thumb.jpg" |
recency | "Listed on Jan 05, 2026 (2h ago)" |
url | "https://www.iproperty.com.my/property/sample-area/sample-project/sale-900000001/" |
source | "iproperty.com.my" |
Search-mode listings (and URL-mode listings pasted as a search URL) also carry propertyTypeGroup, statusCode, externalId, searchUrl, shortAddress, pricePerArea, areaText, badges, postedOn, developer, isOfficialListing, isDeveloperListing, newProject and projectId. iProperty.com.my does not publish per-comment agent reviews on its public pages, so reviews is always returned as null; agentRating (above, commonly 0/0) is the only review signal the site exposes. With Fetch full details on, a record adds description, latitude, longitude, agentContacts (a list of the agent's phone / WhatsApp numbers) and agentPhone whenever the listing page provides them (a failed detail fetch is skipped silently and ships without enrichment), and the images/imageCount gallery is replaced by the fuller detail-page gallery. Pasting a single listing URL (not a search URL) is a narrower shape: it never goes through a search results card, so price, bedrooms, bathrooms, tenure, fullAddress, location, agent and agency are present as keys but always null or empty (images: [], imageCount: 0), alongside the real listingId, id, url, source, listingUrl and scrapedAt, plus the detail-only fields above when Fetch full details is on. Use Search mode, or paste a search URL, to get the full record.
How to Use
- Pick a mode:
search(build from channel + location + filters) orurl(paste iProperty.com.my search or listing URLs). - In search mode, set the channel, an optional location and any filters. In URL mode, paste your links; search filters are ignored.
- Turn on Fetch full details if you need the description, coordinates or agent contact numbers, and set Max items to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search for sale in a location:
{"mode": "search","channel": "sale","location": "Petaling Jaya","sortBy": "price_asc","maxItems": 50}
Filter rentals by price and bedrooms:
{"mode": "search","channel": "rent","priceMin": 1500,"priceMax": 3500,"bedrooms": 3,"propertyType": "condo","maxItems": 100}
Paste a search URL, with full details on:
{"mode": "url","urls": ["https://www.iproperty.com.my/property-for-rent"],"fetchDetails": true,"maxItems": 80}
Daily monitoring with expiry tracking:
{"mode": "search","channel": "sale","location": "Mont Kiara","incrementalMode": true,"emitExpired": true,"maxItems": 0}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/iproperty-com-my-scraper").call(run_input={"mode": "search", "channel": "sale", "location": "Petaling Jaya", "maxItems": 50})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["pricePretty"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/iproperty-com-my-scraper').call({mode: 'search', channel: 'sale', location: 'Petaling Jaya', maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Resume and recurring updates
Two different features, both optional:
- Resume (
resumeFromRunId) continues one specific interrupted crawl: paste a previous run or dataset ID and this run skips every listing already collected there. No state is kept between unrelated runs. - Incremental mode (
incrementalMode) is for scheduling this same search daily or weekly and getting only what changed. The actor remembers its own baseline for the search (keyed bystateKey, or an automatic key derived from the search/URL and detail settings) and classifies every listingNEW,UPDATED,UNCHANGED,REAPPEAREDorEXPIRED. By default onlyNEW/UPDATED/REAPPEAREDlistings ship; turn onemitUnchanged/emitExpiredto also get those (both return, and bill, extra rows).EXPIREDrows are only produced once a run has scanned its full tracked search with no cap hit and no Resume.REAPPEAREDnever happens "by default": a listing can only be marked absent (the one precondition forREAPPEARED) by an earlier run that hademitExpiredon and completed that kind of full, uncapped, non-resumed scan. IfemitExpiredhas never been turned on for a state key,REAPPEAREDcannot occur for it yet.
Output then carries changeType, changedFields, firstSeenAt and lastSeenAt. Change detection ignores scrapedAt/scraped_at (per-run timestamps) and searchMetadata (search-relative), and it ignores fields that only exist once the optional detail fetch has run (description, latitude, longitude, agentContacts, agentPhone, and the detail-page images/imageCount gallery) whenever the two sides being compared were not fetched at the same depth, so a flaky or toggled detail fetch never manufactures a false UPDATED. recency (e.g. "Listed on Aug 05, 2026 (55s ago)") is normalised, not ignored: the trailing (... ago) relative-age clock is stripped before comparison so it never re-triggers UPDATED on its own, but a genuine change to the listed date still does. Price, bedrooms, bathrooms, floor area, address and every other core field do trigger UPDATED when they change.
Send results into your apps (MCP connectors)
Optionally pipe each run's results into the tools you already use through Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed, and a failed export never fails the run.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the
mcpConnectorsinput field. - For Notion, also set
notionParentPageUrl: Notion gets one rich page per listing (up tomaxNotifyListings, default 50). Linear, Airtable and Apify instead get a single combined note covering up to 25 of the collected listings, sent to whichever writable tool that connector exposes.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (build from channel + location + filters) or url (use pasted URLs; filters below are ignored). |
channel | string | sale | sale or rent. Search mode only. |
location | string | no default (prefill: Kuala Lumpur) | Optional state, city, district or neighbourhood name (Kuala Lumpur, Selangor, Petaling Jaya, Mont Kiara). Hyphens work too (petaling-jaya). An iProperty.com.my location slug copied from the address bar (in-kuala-lumpur-58jok) is also accepted verbatim. Empty = whole country. |
propertyType | string | `` (all types) | Optional property-type filter: bungalow, condo (includes apartments/service residences), semi_detached, terrace, land. |
priceMin | integer | no default | Minimum price (MYR). |
priceMax | integer | no default | Maximum price (MYR). |
bedrooms | integer | no default | Minimum number of bedrooms. |
sortBy | string | relevance | One of 6 sort orders (price, date, built-up size). The site has no bedroom-count sort. |
urls | array | no default (prefill: sample URL) | iProperty.com.my search or listing URLs. URL mode only. |
fetchDetails | boolean | false | Visit each listing page for the full description, map coordinates and agent contact numbers. Slower and adds a small per-item charge. |
maxItems | integer | 20 | The single cap on the run: stop after collecting this many listings across all searches/URLs. 0 = unlimited. |
maxPages | integer | no default (unlimited; defers to Max items) | Optional safety bound on result pages per search. Leave empty or 0 for unlimited; the run still stops at Max items. |
resumeFromRunId | string | no default | Paste a previous run or dataset ID to continue a large crawl without returning or charging for listings already collected there. For recurring monitoring of the same search, use Incremental mode instead. |
incrementalMode | boolean | false | Turn on for daily/recurring monitoring of the same search. The first run returns everything as NEW; later runs normally return only NEW/UPDATED/REAPPEARED. |
stateKey | string | no default | Optional. Name a monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Empty = an automatic key derived from the search/URL and detail settings. |
emitUnchanged | boolean | false | Also return (and bill) UNCHANGED listings in incremental mode. |
emitExpired | boolean | false | Also return (and bill) EXPIRED listings no longer found since the last run. Only produced after a complete, non-resumed, non-capped scan. |
proxy | object | Residential (MY) | Proxy configuration. Apify Residential recommended. |
maxResidentialMB | integer | 0 (unlimited) | Advisory residential traffic budget in MB, logged at startup. Does not currently stop or reroute traffic once a run is underway. |
mcpConnectors | array | no default | Optional MCP connectors to pipe results into (Notion, Linear, Airtable, Apify). |
notionParentPageUrl | string | no default | Notion parent page URL or id for the Notion connector. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live listing.
{"listingId": 900000001,"url": "https://www.iproperty.com.my/property/sample-area/sample-project/sale-900000001/","title": "Sample Listing, Sample Area","propertyType": "Condominium","typeText": "For Sale","price": { "value": 650000, "pretty": "RM 650,000", "currency": "MYR", "type": "Negotiable" },"priceValue": 650000,"pricePretty": "RM 650,000","priceType": "Negotiable","pricePerArea": "RM 480.00 psf","psf": "RM 480.00 psf","bedrooms": 3,"bathrooms": 2,"floorArea": 1100,"tenure": "Freehold","location": { "area": "Sample Area", "district": "Sample District", "region": "Selangor" },"fullAddress": "Jalan Contoh, Sample Area, Sample District, Selangor","agent": {"id": 1,"name": "Sample Agent","license": "REN 00001","isVerified": true,"profileUrl": "https://www.iproperty.com.my/property-agent/sample-agent-1/"},"agency": { "id": 1, "name": "Sample Realty Sdn. Bhd." },"agentRating": { "reviewCount": 0, "ratingAverage": 0 },"images": ["https://cdn.example.com/listing/900000001/photo-1.jpg"],"imageCount": 1,"thumbnail": "https://cdn.example.com/listing/900000001/thumb.jpg","recency": "Listed on Jan 05, 2026 (2h ago)","description": "Full property description (Fetch full details on).","latitude": 3.05,"longitude": 101.7,"agentContacts": [{ "type": "mobile", "value": "+60123456789" }],"agentPhone": "+60123456789","reviews": null,"source": "iproperty.com.my","scrapedAt": "2026-01-05T00:00:00+00:00"}
Plan Requirement
Runs on any Apify plan. This site serves best on residential connections, so set the proxy to Apify Residential for reliable results. Datacenter and other non-residential connections are commonly rejected and can return zero items; running on one logs a warning at startup. When the primary connection cannot read a page, the actor tries a backup connection for the rest of that run before giving up.
Reliability
- Built for resilient, unattended runs: transient errors are retried on a fresh connection automatically.
- A page that does not exist (HTTP 404) is not retried, and if the run ends with zero items it is reported as
PAGE_NOT_FOUNDin the status message; that status message only appears on a zero-item run. It means the Location value or a pasted URL points at a page iProperty.com.my does not serve. If a run has several searches or pasted URLs and one of them 404s or is fully blocked, the run stops there and keeps whatever it already collected rather than attempting the rest, with only the run log noting what was skipped. - Residential traffic budget:
maxResidentialMBis advisory only, logged at run startup. It does not currently stop or reroute traffic once the run is underway.0= unlimited.
FAQ
How much does it cost?
You pay per run start, per listing returned, and a smaller amount per listing whose detail page is fetched (only when Fetch full details is on). The Pricing tab shows the current rates for each of these. Use Max items to cap the cost of any run.
Is it legal to scrape iProperty.com.my?
This actor collects only publicly available property listing data. You are responsible for how you use it: follow iProperty.com.my's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts (price, size, address) are generally data, but photos and agent profile details may be subject to third-party rights.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and (once a prior complete scan has run with Emit expired on) reappeared listings; unchanged ones are not billed unless you turn on Emit unchanged.
Does this include individual agent review comments?
No. iProperty.com.my does not publish per-comment agent reviews on its public pages, so there is nothing to scrape there. The only review signal the site exposes is an aggregate agentRating (reviewCount / ratingAverage), which is commonly 0.
What does a pasted single listing URL return?
Less than a search-mode record. A pasted listing detail URL never goes through a search results card, so price, bedrooms, bathrooms, tenure, address, agent and agency come back null or empty; you still get the listing id, URL and (with Fetch full details on) the description, coordinates and agent contact numbers. To get the full ~50-field record, use Search mode or paste a search URL instead of an individual listing URL.
Why did my run return fewer listings than expected, or none at all?
A blocked connection does not fail the run; when it returns zero items, the run completes normally with a status message explaining why. When a block or 404 happens partway through a multi-search or multi-URL run after some items were already collected, that stop is visible only in the run log, not in a status message, and this site serves best on a residential proxy. An invalid resumeFromRunId, or turning on Resume for a search that already has saved Incremental mode state, does stop the run outright with a clear error, since continuing would double-count or silently discard that state. Separately, if a run covers several searches or pasted URLs and one of them returns HTTP 404 or is fully blocked, the run stops at that point and keeps whatever it already collected rather than continuing to the rest.
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:
| 🏠 PropertyGuru MY From $1/1K. Fast, reliable scraper for propertyguru.com.my. Extract sale and rent... | 🏠 PropertyGuru SG Scraper From $0.80/1K. Scrape PropertyGuru.com.sg sale and rental listings with 30+ structured... |
| 🏠 CommercialGuru SG Property Listings & Agent Contacts Scraper Scrape commercialguru.com.sg Singapore listings at scale. Extract prices, PSF, floor... | 🏷️ Mudah.my Cars, Property, Jobs & Marketplace Scraper Scrape Mudah.my listings across every category: cars, motorcycles, property, mobiles... |
| 🏠 OnTheMarket Scraper Scrape onthemarket.com for-sale, to-rent and new-homes listings with 85+ fields: price... | 🏠 Zonaprop Argentina Scrape Zonaprop.com.ar property listings across Argentina. Extract 140+ fields including... |
💬 Support & custom scrapers
- 🐞 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 abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.