DDProperty TH $1๐ฐ Powerful Filters + Deep Search
Pricing
from $1.00 / 1,000 results
DDProperty TH $1๐ฐ Powerful Filters + Deep Search
From $1/1K. Extract property listings from ddproperty.com Thailand at scale. Get comprehensive data including prices, features, images, agent contacts, coordinates, nearby transit (BTS/MRT), and more. Perfect for Thai real estate analytics, market research, and investment analysis.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
24
Total users
5
Monthly active users
1.2 hours
Issues response
2 days ago
Last modified
Categories
Share
DDProperty Thailand Scraper
Extract property listings from ddproperty.com (PropertyGuru Thailand) at scale. Get comprehensive data including prices, features, images, agent contacts, coordinates, nearby transit (BTS/MRT), and more. Perfect for Thai property market analytics, research, and investment analysis.
What does DDProperty Scraper do?
This Apify Actor scrapes property listings from ddproperty.com. It extracts full listing data from search result pages and automatically enriches every listing with exact coordinates via the PropertyGuru Map Cluster API, so no individual page visits are required.
Key Features
| Feature | Description |
|---|---|
| All Listing Types | For Sale and For Rent properties across Thailand |
| Property Type Filters | Condos, Houses, Villas, Townhouses, Land, Apartments, Commercial |
| Price & Bedroom Filters | Narrow results by price range (THB) and bedrooms |
| Location Filters | Filter by region (Bangkok, Phuket, Chiang Mai, Pattaya, etc.) |
| Exact Coordinates | Lat/lng for every listing via PropertyGuru Map Cluster API (no detail page visits) |
| MRT/BTS Fallback | Remaining listings enriched with nearest transit station coordinates (253 stations) |
| Multiple Dataset Views | Overview, Map View, Detailed, Agent Contacts |
| Pagination | Multi-page scraping with automatic retry on blocked pages |
What data can you extract?
The scraper extracts 30+ fields per listing:
|
Property Details
|
Pricing
|
|
Location & Transit
|
Agent & Developer
|
|
Media
|
Dates & Metadata
|
Quick Start
Search for condos for sale in Bangkok:
{"mode": "search","listing_type": "sale","property_type": "CONDO","region": "TH10","max_properties": 20,"max_pages": 3,"proxy": { "useApifyProxy": true }}
How to Use
Step 1: Basic search by region
{"mode": "search","listing_type": "sale","region": "TH83","max_properties": 50,"max_pages": 5,"proxy": { "useApifyProxy": true }}
Step 2: Filter by property type and price
{"mode": "search","listing_type": "rent","property_type": "CONDO","region": "TH10","min_price": 15000,"max_price": 50000,"bedrooms": 1,"max_properties": 100,"max_pages": 10,"proxy": { "useApifyProxy": true }}
Step 3: Scrape specific URLs
{"mode": "url","urls": ["https://www.ddproperty.com/en/condo-for-sale/in-bangkok-th10","https://www.ddproperty.com/en/property-for-rent/in-phuket-th83"],"max_properties": 50,"max_pages": 5,"proxy": { "useApifyProxy": true }}
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (build URL from filters) or url (use provided URLs) |
urls | array | [] | DDProperty search URLs (url mode only) |
listing_type | string | sale | sale or rent |
property_type | string | - | CONDO, BUNG, SEMI, VIL, TOWN, LAND, APT, RET, OFF, WAR, BIZ, SHOP |
region | string | - | Region code (see table below) |
min_price | integer | - | Minimum price in THB |
max_price | integer | - | Maximum price in THB |
bedrooms | integer | - | Number of bedrooms (0 = Studio) |
sort | string | date | Sort by: date, price, psf |
sort_order | string | desc | asc or desc |
max_properties | integer | 20 | Max listings to scrape (0 = unlimited) |
resumeFromRunId | string | - | Continue one interrupted run/dataset (skips already-collected properties) |
incrementalMode | boolean | false | Recurring monitoring: remembers the previous run of this search and returns only what changed |
stateKey | string | - | Optional manual key to control which runs share incremental state |
emitUnchanged | boolean | false | Incremental mode: also return properties with no detected change |
emitExpired | boolean | false | Incremental mode: also return properties no longer found (after a complete scan) |
proxy | object | - | Proxy configuration (Apify proxy recommended) |
Region Codes
| Code | Region | Code | Region |
|---|---|---|---|
TH10 | Bangkok | TH83 | Phuket |
TH11 | Samut Prakan | TH84 | Surat Thani (Koh Samui) |
TH12 | Nonthaburi | TH77 | Prachuap Khiri Khan (Hua Hin) |
TH13 | Pathum Thani | TH50 | Chiang Mai |
TH20 | Chon Buri (Pattaya) | TH90 | Songkhla |
Property Type Codes
| Code | Type | Code | Type |
|---|---|---|---|
CONDO | Condo | LAND | Land |
BUNG | Single Detached House | APT | Apartment |
SEMI | Semi-Detached House | RET | Retail Space |
VIL | Villa | OFF | Office Space |
TOWN | Townhouse | SHOP | Shophouse |
Resume an interrupted run
Paste a previous run ID or dataset ID into resumeFromRunId to continue that ONE crawl โ properties it already collected are skipped instead of re-scraped. This is a one-off continuation, unrelated to Incremental mode below.
Incremental mode (recurring monitoring)
Turn on incrementalMode to schedule this actor against the same search repeatedly and get only what changed. The actor remembers the previous run of this search itself (a saved state, keyed on your filters or on stateKey) and tags every property returned with a changeType:
changeType | Meaning |
|---|---|
NEW | First time this property has ever been tracked under this state key |
UPDATED | Tracked before; at least one comparable field changed (see changedFields) |
UNCHANGED | Tracked before, nothing changed โ suppressed (not returned) unless emitUnchanged is ON |
REAPPEARED | Was previously marked EXPIRED, now back |
EXPIRED | Was tracked and present before, no longer found โ only emitted when emitExpired is ON, and only after a run that scanned its search to a genuine natural end (no max_properties cap hit, no Resume) |
Additional fields in incremental mode: changedFields (which field names differ from the last tracked scrape), firstSeenAt, lastSeenAt (UTC timestamps).
stateKey is optional โ leave it blank to auto-derive the tracked scope from your search filters (mode, listing/property type, search text, region, price/bedroom filters, sort, URLs, and whether detail pages are enabled). Two different filter setups never share a baseline unless you set the same stateKey on both.
emitUnchanged and emitExpired default OFF. Turning either on returns โ and bills, at the standard per-result rate โ extra rows beyond what actually changed.
Volatile fields excluded from change detection: recency (e.g. "Listed on Jul 07, 2026 (3w ago)") carries a relative "time ago" phrase that advances on its own as time passes, even when nothing about the listing changed โ it is excluded from the NEW/UPDATED/UNCHANGED comparison (but still returned in every record) so it never causes a false UPDATED. images, images_full, facilities, amenities, floor_plans, and highlights are compared by membership, not order โ a pure reshuffle of these lists is not treated as a change (their emitted order is untouched).
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.
- Authorize a connector once under Apify โ Settings โ Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Output Schema
Each scraped listing is returned as a JSON object with the fields shown below. Field names and types are stable across all results; values shown are placeholder examples.
{"id": "<integer listing id>","title": "<localized listing title>","address": "<full property address>","listing_type": "sale | rent","property_type": "CONDO | BUNG | SEMI | VIL | TOWN | LAND | APT | RET | OFF | WAR | BIZ | SHOP","price": "<integer THB>","price_formatted": "<formatted THB string, e.g. เธฟX,XXX,XXX>","price_per_sqm": "<formatted THB / sqm>","bedrooms": "<integer; 0 = studio>","bathrooms": "<integer>","floor_area": "<sqm, number>","tenure": "Freehold | Leasehold","developer": "<developer name, when applicable>","is_developer_listing": "<boolean>","agent_name": "<agent display name>","agent_id": "<integer>","agency_id": "<integer>","region": "<region label>","region_code": "<TH region code>","district": "<district label>","district_code": "<TH district code>","area": "<area label>","area_code": "<TH area code>","latitude": "<float>","longitude": "<float>","location_source": "nearest_mrt_station | map_api","nearby_mrt": "<descriptive distance to nearest MRT/BTS>","nearby_station_id": "<station id, e.g. BL17>","badges": ["<string>", "..."],"posted_date": "<DD MMM YYYY>","posted_unix": "<unix timestamp>","images": ["<image url>", "..."],"image_count": "<integer>","url": "<full listing url on ddproperty.com>","status": "<listing status code, e.g. ACT>"}