# PropertyHub.in.th Scraper | Thailand Real Estate (`fatihtahta/propertyhub-in-th-scraper`) Actor

Extract PropertyHub.in.th property listings at scale with clean JSON, prices, photos, descriptions, agent contacts, amenities, and map-ready coordinates. Built for Thailand real estate intelligence, lead enrichment, inventory monitoring, CRM, BI, and AI workflows.

- **URL**: https://apify.com/fatihtahta/propertyhub-in-th-scraper.md
- **Developed by:** [Fatih Tahta](https://apify.com/fatihtahta) (community)
- **Categories:** Real estate, Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 property listings

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Propertyhub.in.th Scraper | Thailand Real Estate

**Slug:** `fatihtahta/propertyhub_in_th_scraper`

### Overview

Propertyhub.in.th Scraper | Thailand Real Estate collects structured public property listing records from [PropertyHub.in.th](https://propertyhub.in.th), including listing identity, sale or rental mode, prices, property attributes, locations, media, contact fields, related agents or projects, and source context when available. PropertyHub.in.th is a Thailand-focused real estate marketplace, and its public listing data is useful for understanding visible inventory, asking prices, property categories, locations, project activity, and listing-level attributes across Thai property segments. The actor helps property researchers, operators, brokers, investors, analysts, and proptech teams turn structured PropertyHub search criteria into repeatable datasets. It supports property discovery, market monitoring, listing enrichment, competitive analysis, portfolio research, and operational data acquisition without requiring users to manually review each listing page. Results are delivered as structured dataset records suitable for review, export, ETL pipelines, BI dashboards, AI-agent workflows, and downstream processing. The actor is designed for dependable recurring public data acquisition with a clear output contract, documented optional fields, and run artifacts for review, while avoiding unsupported claims about complete market coverage or official valuation.

### What Makes This Actor Different

- **Pipeline-ready property records:** Records are grouped into stable JSON objects such as `source_context`, `entity`, `listing`, `pricing`, `location`, `property`, `media`, `contact_details`, `relationships`, and `attributes`, which makes them easier to load into warehouses, search indexes, CRMs, dashboards, and review queues.
- **Thailand real estate scope:** The input schema is built around PropertyHub-recognized locations, sale or rental mode, property categories, THB price bounds, area filters, bedroom counts, furnishing status, and amenities.
- **Schema-aware enrichment option:** `enrich_data` lets users request richer listing-page details when available, such as descriptions, additional photos, amenities, facilities, payment terms, contact details, and enrichment provenance. Standard search-result rows remain available for faster validation and broader discovery.
- **Run summary artifacts:** Each completed run can provide `RUN-SUMMARY`, `RUN-SUMMARY.html`, and `results-map` artifacts that help operators review saved counts, input context, enrichment counts, pricing breakdowns, location coverage, map readiness, sample records, and warning context without opening every dataset row.
- **Map-ready review:** Listing records can include `location.latitude` and `location.longitude` when the source exposes usable coordinates. The `results-map` artifact gives teams a visual way to inspect mapped listing distribution when coordinates are available.
- **Field preservation for downstream use:** Meaningful schema-supported values are grouped into public fields instead of being flattened into one opaque text field. Source-specific values that do not fit a stronger canonical group can be preserved under `attributes`.
- **Agentic usability:** The actor exposes clear input recipes, stable output groups, a recommended idempotency strategy, JSON examples, and run artifacts that can be handed to AI agents or workflow automations without private context.
- **Optional MCP handoff:** When users authorize supported Apify MCP connectors and select them in the actor input, the actor can deliver a concise post-run listing summary with dataset, summary, and map links when available. The dataset and key-value store remain the source of truth.

### Who Should Use This Actor

- **Real estate investors and analysts:** Collect public listings for comparable research, price-band review, location analysis, and recurring inventory snapshots.
- **Brokerages, agencies, and property operations teams:** Build repeatable listing review workflows for selected neighborhoods, projects, property categories, or rental and sale segments.
- **Market research and analytics teams:** Normalize visible asking prices, property mix, amenities, project names, and location signals for dashboards and market intelligence.
- **Proptech, data engineering, and product teams:** Feed structured property listing records into databases, enrichment pipelines, search products, workflow tools, or company APIs.
- **AI agents and workflow automations:** Use scoped inputs, stable JSON records, and run artifacts as a public property-data acquisition step inside larger research or monitoring workflows.
- **Lead generation and enrichment teams:** Add public listing context, contact fields, project information, and property attributes to CRM or review queues when those fields are exposed.
- **Monitoring and operations teams:** Schedule repeated runs to compare public listing visibility, price signals, property attributes, and source timestamps over time.

### Common Use Cases

- **Market intelligence:** Monitor visible supply, asking prices, property mix, locations, amenities, listing status signals, and category movement for selected Thailand property segments.
- **Comparable listing research:** Collect public attributes for a specific geography, property type, price band, bedroom count, furnishing status, or amenity set.
- **Competitive monitoring:** Track public listing activity across agents, agencies, projects, neighborhoods, or property categories when those relationships are available.
- **Catalog and directory building:** Populate owned listing, property, project, agent, or agency datasets with structured public records.
- **Data enrichment:** Add current public listing attributes to existing CRM, BI, underwriting, review, or analytics datasets.
- **Recurring reporting:** Schedule periodic runs for dashboards, alerts, inventory snapshots, analyst review, or trend analysis.
- **Map-based review:** Use coordinate-capable records and the interactive map artifact to inspect geographic distribution for selected listing scopes.
- **Agentic research workflows:** Let a property workflow agent collect a scoped dataset, inspect the run summary, summarize changes, and route records to the next workflow step.

### Real-World Questions This Data Can Answer

- Which public PropertyHub listings match a specific location, property category, transaction mode, price band, bedroom count, furnishing status, or amenity set?
- Which listings have enough structured price, property, location, media, or contact attributes to support review or enrichment workflows?
- Which projects, neighborhoods, agents, agencies, or property types are most visible in a selected segment?
- Which records include coordinates that can support map review or geospatial analysis?
- Which listings appear new, removed, repriced, or updated when compared with a previous saved dataset?
- Which search scopes produce sparse records, missing optional fields, or incomplete coordinates that need analyst review?
- Which run segments are ready for dashboards, CRM enrichment, search indexing, vector retrieval, or human verification?

### Quick Start

1. Choose a focused PropertyHub location and a structured set of search filters such as deal type, property type, price, bedrooms, area, furnishing, and amenities.
2. Set a small `limit` for the first validation run so you can inspect the output shape before scaling.
3. Run the actor in Apify Console.
4. Inspect the first dataset records and the run artifacts to confirm the listing shape, key fields, and map readiness match your workflow.
5. Increase the limit, refine filters, enable enrichment, export results, or schedule the actor once the output is verified.

### Input Parameters

The actor accepts structured PropertyHub search fields, plus optional enrichment, output limit, and MCP connector delivery settings.

| Parameter | Type | Description | Default |
| --- | --- | --- | --- |
| `location` | string | PropertyHub-recognized market, district, neighborhood, province, city, or transit station such as Bangkok or an MRT/BTS area. Use one focused location per run for cleaner comparison. | - |
| `deal_type` | string | Transaction mode. Allowed values: `sale`, `rent`. | `sale` |
| `property_type` | string | Optional property category. Allowed values: empty, `Condominium`, `Shop house`, `House`, `Land`, `Office`, `Town house`, `Sale area`, `Apartment`. Empty means any property type. | empty |
| `min_price` | integer | Optional minimum displayed asking price or monthly rent in THB. | - |
| `max_price` | integer | Optional maximum displayed asking price or monthly rent in THB. | - |
| `bed_count` | string | Optional bedroom filter. Allowed values: empty, `Studio`, `1 bedroom`, `2 bedroom`, `3 bedroom`, `4 bedroom`. Empty means any bedroom count. | empty |
| `min_area` | integer | Optional minimum room, usable, or floor area in square meters. | - |
| `max_useable_area` | integer | Optional maximum room, usable, or floor area in square meters. | - |
| `min_land_area` | integer | Optional minimum land area in square wah for property categories where land size is relevant. | - |
| `max_land_area` | integer | Optional maximum land area in square wah for property categories where land size is relevant. | - |
| `furnishment` | string | Optional furnishing filter. Allowed values: empty, `Fully`, `Partly`, `Unfurnished`. Empty means any furnishing status. | empty |
| `amenities` | array of strings | Optional room amenities or building facilities that matching listings should include. Supported values include Furniture, Air conditioner, Room digital lock system, TV, Fridge, WIFI, heater, Bath, Cooking stove, Microwave, Hood, Washing machine, Lift, Parking, Motorcycle Parking, CCTV, Pool, Fitness, Sauna, Stream, EV Charger, Internet, Security, Library, Shop, Meeting Room, Park, Restaurant, Laundry shop, Playground, Shuttle, and Stadium (Tennis/Basketball). | `[]` |
| `enrich_data` | boolean | Requests richer listing-page details when available. This can add fields such as long descriptions, extra photos, amenities, facilities, payment terms, contact details, and enrichment provenance. | `true` |
| `limit` | integer | Maximum number of listing records to save. Start small for validation, then increase after confirming output quality. | - |
| `mcpConnectors` | array | Optional Apify MCP connectors selected by the user. When configured, the actor sends a concise post-run summary with dataset, summary, and map links when available. | `[]` |

### Choosing Inputs

Use structured search fields when you want repeatable market slices, such as Bangkok condominiums for rent under a selected monthly budget or house listings with a specific land-area range.

Narrower filters produce more targeted datasets and cleaner downstream comparisons. Broader filters improve discovery, but they can produce more heterogeneous records and may require higher limits or segmented runs. Price filters use THB, area filters use square meters for room or usable area, and land-area filters use square wah. `deal_type`, `property_type`, `bed_count`, `furnishment`, and `amenities` directly affect the selected listing scope. Use one location, property type, price band, or amenity group per run when you need clean dashboards, historical comparisons, or deduplication-friendly exports.

Use `limit` as a validation and cost-control tool. Start with a small value, inspect the records and artifacts, then increase the limit for scheduled monitoring or production exports. Enable `enrich_data` when richer listing-page fields matter more than the fastest lightweight search-result pass.

### Input Recipes

- **Validation run:** Choose one location such as Bangkok, keep the default sale or rental mode you need, set `limit` to a small value, and inspect the grouped listing records before expanding.
- **Targeted condo rental search:** Set `location`, choose `deal_type` as `rent`, set `property_type` to `Condominium`, add a THB price band, choose a bedroom count, and optionally enable `enrich_data`.
- **Broad market discovery:** Use a location and a conservative `limit` with only a few filters. Leave optional filters empty when discovery matters more than precision.
- **Enriched listing review:** Enable `enrich_data` for scoped searches when listing-page details, additional media, contact fields, or richer property attributes matter more than the fastest search-only run.
- **Segmented analysis:** Run separate inputs by city, neighborhood, property category, transaction mode, price band, or furnishing status to keep exports easier to compare.

### Example Inputs

#### Location-driven validation run

```json
{
  "location": "Bangkok",
  "deal_type": "rent",
  "property_type": "Condominium",
  "limit": 25,
  "enrich_data": false
}
````

#### Filtered property research run

```json
{
  "location": "MRT Rama 9",
  "deal_type": "rent",
  "property_type": "Condominium",
  "min_price": 10000,
  "max_price": 30000,
  "bed_count": "1 bedroom",
  "amenities": ["Parking", "Pool"],
  "limit": 100
}
```

#### Enriched property review run

```json
{
  "location": "Bangkok",
  "deal_type": "rent",
  "property_type": "Condominium",
  "bed_count": "2 bedroom",
  "enrich_data": true,
  "limit": 50,
  "mcpConnectors": []
}
```

### Output

#### Output destination

The actor writes results to an Apify dataset as JSON records. The dataset is designed for direct consumption by analytics tools, ETL pipelines, AI agents, and downstream APIs with minimal post-processing.

The current dataset contract contains one primary record shape: `property_listing`. Run-level summaries, HTML reports, and maps are saved separately as key-value-store artifacts and are not dataset rows.

#### Record envelope and stable identifiers

Each dataset item is a grouped property listing record with `record_type`, `record_id`, `source_context`, and `entity` as the core envelope. The recommended idempotency key is `record_id` when present, with `listing.listing_id` as the next equivalent listing identifier and `source_context.canonical_url` or `entity.url` as useful fallback audit keys.

For deduplication and upserts, store one row per stable listing key and update selected business fields such as price, status, timestamps, property attributes, media, and contact fields on repeated runs. Stable identifiers make records easier to merge, deduplicate, sync, and compare across scheduled runs, warehouses, CRMs, and monitoring systems. Provenance fields such as `source_context.source_domain`, `source_context.source_url`, `source_context.canonical_url`, `source_context.search`, `source_context.pagination`, and `source_context.scraped_at` help users trace a record back to its public source context.

#### Examples

##### Example: property listing record

```json
{
  "record_type": "property_listing",
  "record_id": "sample-1000001",
  "source_context": {
    "source_id": "propertyhub_in_th_property_scraper",
    "source": "PropertyHub.in.th",
    "source_domain": "propertyhub.in.th",
    "source_url": "https://propertyhub.in.th/en/condo-for-rent/bangkok",
    "canonical_url": "https://propertyhub.in.th/en/listings/sample-condo---1000001",
    "position": 1,
    "page_number": 1,
    "scraped_at": "2026-07-03T09:31:41+00:00",
    "enrichment_status": "enriched",
    "enrichment_url": "https://propertyhub.in.th/en/listings/sample-condo---1000001",
    "search": {
      "public_search_url": "https://propertyhub.in.th/en/condo-for-rent/bangkok",
      "post_type": "FOR_RENT",
      "property_type": "CONDO"
    },
    "pagination": {
      "page": 1,
      "per_page": 60,
      "total_listings": 1200,
      "total_pages": 20
    }
  },
  "entity": {
    "title": "Sample condo for rent near MRT Rama 9",
    "description": "Sample furnished one-bedroom condo with building facilities and transit access.",
    "url": "https://propertyhub.in.th/en/listings/sample-condo---1000001",
    "external_ids": {
      "listing_id": "sample-1000001",
      "project_id": "sample-project-01"
    }
  },
  "listing": {
    "listing_id": "sample-1000001",
    "deal_type": "rent",
    "transaction_type": "FOR_RENT",
    "listing_status": "ACTIVE",
    "summary": "Sample one-bedroom rental listing for documentation.",
    "posted_at": "2026-06-26T10:58:38.837Z",
    "updated_at": "2026-06-26T11:00:46.046Z"
  },
  "pricing": {
    "price": 18500,
    "price_text": "18,500 THB",
    "currency": "THB",
    "payment_terms": {
      "advance_payment": {
        "type": "MONTH",
        "months": 1
      },
      "deposit": {
        "type": "MONTH",
        "months": 2
      }
    }
  },
  "location": {
    "address": "Rama 9, Bangkok",
    "city": "Bangkok",
    "region": "Bangkok",
    "country": "Thailand",
    "latitude": 13.758,
    "longitude": 100.565,
    "neighborhood": "MRT Rama 9"
  },
  "property": {
    "property_id": "sample-1000001",
    "property_type": "CONDO",
    "project_name": "Sample Rama 9 Residence",
    "bedrooms": 1,
    "bathrooms": 1,
    "floor_area": 32,
    "area_unit": "sqm",
    "floor": "12",
    "room_type": "1 BEDROOM",
    "furnishing_status": "FULLY",
    "amenities": ["air", "furniture", "microwave"],
    "facilities": ["pool", "fitness", "security"]
  },
  "media": {
    "main_image_url": "https://bcdn.propertyhub.in.th/pictures/sample-main.jpg",
    "image_urls": ["https://bcdn.propertyhub.in.th/pictures/sample-main.jpg"],
    "photos": [
      {
        "url": "https://bcdn.propertyhub.in.th/pictures/sample-detail.jpg",
        "thumbnail_url": "https://bcdn.propertyhub.in.th/pictures/sample-thumb.jpg"
      }
    ]
  },
  "contact_details": {
    "phones": ["0000000000"],
    "emails": ["agent@example.com"],
    "line_ids": ["@sampleagent"],
    "contacts": [
      {
        "name": "Sample Agent",
        "company_name": "Sample Realty",
        "phones": ["0000000000"],
        "line_id": "@sampleagent"
      }
    ]
  },
  "relationships": {
    "agent": {
      "name": "Sample Agent",
      "user_id": "sample-user-01"
    },
    "agency": {
      "name": "Sample Realty"
    },
    "project": {
      "name": "Sample Rama 9 Residence",
      "slug": "sample-rama-9-residence"
    }
  },
  "attributes": {
    "flags": {
      "sponsor_package": "EXCLUSIVE",
      "user_verification_status": true
    },
    "distance": 0.5,
    "source_payload": {
      "room_information": {
        "numberOfBed": 1,
        "numberOfBath": 1,
        "roomArea": 32
      }
    },
    "raw_attributes": {}
  }
}
```

#### Run Summary, Map, And Artifacts

In addition to dataset records, the actor exposes stable run artifacts through Apify output and key-value-store links:

- **`RUN-SUMMARY`:** machine-readable JSON with generated time, run duration, input summary, saved-record totals, requested limit, enrichment counts, coverage breakdowns, pricing summaries, property attribute counts, relationship counts, media counts, artifact keys, map statistics, source summary, sample records, and warnings when present.
- **`RUN-SUMMARY.html`:** human-readable report for quick operator review. It is useful for checking totals, pricing range, enrichment status, map readiness, and sample listings before exporting or importing records.
- **`results-map`:** standalone HTML map for saved records with valid latitude and longitude values. If a run has no usable coordinates, the map artifact still reports that no listing locations could be plotted.
- **`RUN-SUMMARY-ERROR`:** diagnostic artifact written only when summary or map artifact generation fails after listing records have already been saved.

Property teams can use these artifacts as run receipts: verify completion, compare recurring runs, route alerts, decide whether a retry or narrower segment is needed, and attach a summary to a downstream report or ticket. AI agents can read the summary and map metadata before deciding whether to process, alert, or request a follow-up run.

### Field Reference

#### Record envelope

- **record\_type** *(string, required)*: Dataset record family. Current value is `property_listing`.
- **record\_id** *(string or null, optional)*: Stable PropertyHub listing identifier when available. Preferred dedupe and upsert key.

#### Source context

- **source\_context.source\_id** *(string or null, optional)*: Source identifier for this listing family.
- **source\_context.source** *(string or null, optional)*: Human-readable source name.
- **source\_context.source\_domain** *(string or null, required within source context)*: Domain that supplied the public listing data.
- **source\_context.source\_url** *(string or null, optional)*: Search or result URL associated with the record.
- **source\_context.canonical\_url** *(string or null, optional)*: Best available public URL for the individual listing.
- **source\_context.position** *(number, integer, or null, optional)*: Listing position within a page or result chunk.
- **source\_context.page\_number** *(number, integer, or null, optional)*: Source page number when available.
- **source\_context.scraped\_at** *(string or null, optional)*: UTC timestamp when the record was produced.
- **source\_context.enrichment\_status** *(string or null, optional)*: Indicates whether richer listing-page data was added.
- **source\_context.enrichment\_url** *(string or null, optional)*: Listing URL used for richer details when enrichment succeeds.
- **source\_context.search** *(object or null, optional)*: Public search mode, filters, and URL context.
- **source\_context.pagination** *(object or null, optional)*: Page, total, and continuation metadata when available.

#### Listing identity

- **entity.title** *(string or null, optional)*: Public listing title or best display name.
- **entity.description** *(string or null, optional)*: Listing-page description when enrichment is enabled and the source exposes it.
- **entity.url** *(string or null, optional)*: Primary public PropertyHub listing URL.
- **entity.external\_ids** *(object or null, optional)*: Source identifiers such as listing, user, or project IDs.

#### Listing details

- **listing.listing\_id** *(string or null, optional)*: PropertyHub listing identifier.
- **listing.deal\_type** *(string or null, optional)*: Normalized transaction mode, such as rent or sale.
- **listing.transaction\_type** *(string or null, optional)*: Source-provided transaction value.
- **listing.listing\_status** *(string or null, optional)*: Source status signal when available.
- **listing.summary** *(string or null, optional)*: Short source-provided summary or SEO text.
- **listing.posted\_at** *(string or null, optional)*: Source-provided creation or publication timestamp.
- **listing.updated\_at** *(string or null, optional)*: Source-provided update or refresh timestamp.

#### Pricing

- **pricing.price** *(number, integer, or null, optional)*: Displayed asking price or monthly rent. This is not an appraisal or valuation.
- **pricing.price\_text** *(string or null, optional)*: Human-readable price string.
- **pricing.currency** *(string or null, optional)*: Currency code, commonly `THB` when present.
- **pricing.payment\_terms** *(object or null, optional)*: Deposit, advance payment, or similar terms when exposed.

#### Location

- **location.address** *(string or null, optional)*: Public address or project address text.
- **location.city** *(string or null, optional)*: City value when available.
- **location.region** *(string or null, optional)*: Province, region, or administrative area.
- **location.country** *(string or null, optional)*: Country associated with the listing.
- **location.latitude** *(number or null, optional)*: Latitude used for map artifacts when present.
- **location.longitude** *(number or null, optional)*: Longitude used for map artifacts when present.
- **location.neighborhood** *(string or null, optional)*: Neighborhood, station, or local area label.

#### Property attributes

- **property.property\_id** *(string or null, optional)*: Source property or listing identifier when available.
- **property.property\_type** *(string or null, optional)*: Property category.
- **property.project\_name** *(string or null, optional)*: Condominium, development, or project name.
- **property.bedrooms** *(number, integer, or null, optional)*: Bedroom count or studio signal when available.
- **property.bathrooms** *(number, integer, or null, optional)*: Bathroom count.
- **property.floor\_area** *(number, integer, or null, optional)*: Room, usable, or floor area.
- **property.area\_unit** *(string or null, optional)*: Unit for floor area, such as `sqm`.
- **property.land\_area** *(number, integer, or null, optional)*: Land size for house, land, town house, shop house, or sale area listings.
- **property.floor** *(string or null, optional)*: Floor label, preserved as text because listings may use labels or ranges.
- **property.room\_type** *(string or null, optional)*: Source room type label.
- **property.furnishing\_status** *(string or null, optional)*: Furnishing status when available.
- **property.amenities** *(array of strings or null, optional)*: Listing amenity flags.
- **property.facilities** *(array of strings or null, optional)*: Building or project facility flags, often available on richer records.

#### Media

- **media.main\_image\_url** *(string or null, optional)*: Primary public image URL.
- **media.image\_urls** *(array of strings or null, optional)*: Public image URLs associated with the listing.
- **media.photos** *(array of objects or null, optional)*: Structured photo records with full-size and thumbnail URLs when available.

#### Contact details

- **contact\_details.phones** *(array of strings or null, optional)*: Public phone numbers associated with the listing contact.
- **contact\_details.emails** *(array of strings or null, optional)*: Public email addresses when exposed.
- **contact\_details.line\_ids** *(array of strings or null, optional)*: Public LINE contact IDs when available.
- **contact\_details.contacts** *(array of objects or null, optional)*: Structured contact objects with names, company names, phones, emails, and profile image URLs when available.

#### Relationships

- **relationships.agent** *(object or null, optional)*: Agent or listing contact identity.
- **relationships.agency** *(object or null, optional)*: Agency or company identity.
- **relationships.project** *(object or null, optional)*: Condominium or development identity, project URL values, or listing-count context when available.

#### Attributes

- **attributes.flags** *(object or null, optional)*: Readable source signals such as sponsor package or verification status when exposed.
- **attributes.distance** *(number, integer, string, or null, optional)*: Source-provided distance value for location-scoped searches.
- **attributes.source\_payload** *(object or null, optional)*: Selected source objects preserved for audit, reprocessing, or enrichment.
- **attributes.raw\_attributes** *(object or null, optional)*: Additional meaningful source-specific values not promoted into a stronger grouped field.

### Data Model Notes

- **Identity fields:** Use `record_id` or `listing.listing_id` as the primary matching key when present. Use `source_context.canonical_url` or `entity.url` as fallback audit keys.
- **Source and provenance fields:** `source_context` explains where the listing came from, when it was produced, what source URL or search context was associated with it, and whether enrichment was applied.
- **Property and listing attributes:** `listing`, `pricing`, `location`, `property`, `media`, `contact_details`, and `relationships` carry the main user-facing value.
- **Pricing and status fields:** Prices, listing statuses, publication dates, and update timestamps are point-in-time public signals and should be verified before operational decisions.
- **Nested objects:** Related fields are intentionally grouped so JSON-first pipelines can preserve context without excessive flattening.
- **Optional fields:** Null-check fields that depend on listing type, region, property category, page visibility, enrichment mode, or source availability.
- **Repeated runs:** Compare records across runs using stable identifiers plus Apify run metadata, exported timestamps, and selected business fields such as price, status, updated date, property attributes, and contact fields.

### Data Quality, Guarantees, And Handling

- **Structured records:** Results are normalized into predictable JSON objects for downstream use.
- **Field preservation:** Meaningful schema-supported listing and property values should be kept in stable public fields or grouped objects instead of being silently discarded; optional source values may still be absent when the target does not expose them for a specific record.
- **Best-effort extraction:** Fields may vary by region, availability, account visibility, listing type, UI experiments, or source-side changes.
- **Optional fields:** Null-check in downstream code and dashboards.
- **Deduplication:** Use `record_id` or `listing.listing_id` when present, with `source_context.canonical_url` or `entity.url` as fallback keys.
- **Freshness:** Results reflect the publicly available data at run time.
- **Repeated runs:** Use the recommended idempotency key when syncing data into warehouses, CRMs, search indexes, vector stores, or monitoring systems.
- **Schema awareness:** Downstream systems should rely on documented fields and handle newly missing optional fields gracefully.
- **Run receipts:** Use run summary and map artifacts to audit listing counts, skipped or warning outcomes, enrichment status, map readiness, and export readiness without treating them as replacement dataset records.

### Tips For Best Results

- Start with a small `limit` to validate the output shape before scaling up.
- Use one city, neighborhood, property type, price band, or amenity segment per run when you need cleaner comparison.
- Leave optional filters empty when the goal is broad discovery.
- Add filters gradually to understand how each field changes the collected scope.
- Enable `enrich_data` when descriptions, richer media, amenities, facilities, payment terms, or contact details matter.
- Schedule recurring runs for monitoring workflows instead of relying on manual one-off exports.
- Use stable identifiers for deduplication when storing results over time.
- Review run summary and map artifacts before importing listings into production pipelines, dashboards, CRMs, or property research workflows.

### How to Run on Apify

1. Open the actor in Apify Console.
2. Configure the available input fields for the target PropertyHub location, property type, transaction mode, price range, area range, bedroom count, furnishing status, amenities, and enrichment setting.
3. Set the maximum number of outputs to collect with `limit`.
4. Click **Start** and wait for the run to finish.
5. Open the dataset and inspect the first records.
6. Download results in JSON, CSV, Excel, or another supported Apify dataset format.

### Agentic And API-First Usage

This actor can be used as a structured public property-data acquisition step inside larger automated workflows. It is suitable for systems that need scoped inputs, stable JSON records, run receipts, and predictable field groups before triggering enrichment, indexing, analysis, alerts, or human review.

Agent workflow pattern:

1. Generate or select a scoped input from the supported schema.
2. Run the actor manually, on a schedule, or through Apify platform automation.
3. Wait for completion and read the dataset records.
4. Validate records against the field reference.
5. Read `RUN-SUMMARY`, `RUN-SUMMARY.html`, or `results-map` when present to verify counts, limit behavior, warnings, enrichment status, coordinates, and export readiness.
6. Upsert records into the downstream system using `record_id`, `listing.listing_id`, or a URL fallback.
7. Trigger market analysis, enrichment, alerts, BI refreshes, vector or search indexing, lead review, or human verification.

Practical notes for agentic use:

- Keep prompts and automations grounded in the documented input parameters.
- Start with small validation runs before allowing broad automated collection.
- Feed the Field Reference and a small output sample to downstream AI steps.
- Feed run summary or map artifacts to downstream agents when present so they can reason about completion, record counts, location distribution, and follow-up actions.
- Treat optional property and listing fields as nullable instead of asking agents to infer missing values.
- Store run ID, input configuration, and dataset export metadata outside the record when building audit trails.
- For tools such as Claude, Codex, company copilots, or property workflow agents, pass the input schema, Field Reference, idempotency key, and one representative output example rather than the full README when context is limited.

### Scheduling & Automation

#### Scheduling

**Automated Data Collection**

Users can schedule recurring runs to keep a selected PropertyHub listing dataset current for monitoring, dashboards, lead review, or enrichment workflows. Use separate schedules for different locations, property categories, price bands, or business workflows when clean comparison matters.

- Navigate to **Schedules** in Apify Console
- Create a new schedule, such as daily, weekly, or custom cron
- Configure input parameters
- Enable notifications for run completion
- Add webhooks for automated processing

#### Integration Options

- **CRM enrichment:** Sync public listing, contact, agency, agent, project, price, and location fields into account or lead records.
- **BI dashboards:** Monitor asking prices, visible inventory, property mix, geographic distribution, enrichment counts, and record counts over time.
- **Warehouses and ETL pipelines:** Load grouped JSON records into analytics tables, normalize nested objects, and preserve raw exports for audit.
- **Google Sheets or Airtable:** Review smaller validation runs, analyst queues, sample listings, or manually curated target segments.
- **Webhooks:** Trigger validation, notification, ingestion, or quality-check workflows after each completed run.
- **MCP connectors:** Authorize a supported connector in Apify, select it in the actor input, and use the delivered listing summary, dataset link, run-summary link, or map link in the destination tool.
- **Search and vector indexes:** Index listing titles, descriptions, property attributes, locations, and source context for discovery, retrieval, or agent context.

### Export Formats And Downstream Use

- **JSON:** Best for APIs, applications, AI agents, JSON-first warehouses, and data pipelines that preserve nested objects.
- **CSV or Excel:** Useful for spreadsheet workflows, stakeholder review, lightweight analysis, and manual QA.
- **API access:** Supports automated ingestion into company systems through Apify dataset access.
- **BI and warehouses:** Suitable for reporting, dashboards, historical analysis, and monitoring once records are normalized into your preferred model.
- **Search or vector indexes:** Useful for property discovery, semantic search, retrieval workflows, or agent context when text and structured fields are indexed together.

### Downstream Pipeline Guide

- **Idempotency:** Use `record_id` or `listing.listing_id` for upserts when present, with `source_context.canonical_url` or `entity.url` as fallback keys.
- **Null handling:** Treat optional fields as nullable because availability varies by listing, property type, region, and enrichment mode.
- **Type handling:** Preserve numbers, booleans, arrays, and nested objects when exporting to JSON-first systems.
- **Flattening:** If exporting to CSV or Excel, flatten nested objects deliberately and keep the original JSON export for full fidelity.
- **Partitioning:** Store run date, input segment, geography, property type, transaction mode, price band, or workflow name outside or alongside records for easier analysis.
- **Change detection:** Compare repeated runs by stable key and selected business fields such as `pricing.price`, `listing.listing_status`, `listing.updated_at`, `property.property_type`, `property.bedrooms`, and `property.floor_area` when present.
- **Quality checks:** Monitor record count, stable identifier availability, coordinate coverage, price availability, status availability, contact-field fill rates, and important optional field fill rates.
- **Human review:** Route records with missing critical fields, unusual prices, changed status, high-value segments, or important contact/project signals into a review queue when needed.
- **Retention:** Decide how long to keep raw exports, run artifacts, and normalized warehouse tables based on your compliance and business requirements.

### Performance And Coverage Expectations

No recent measured production benchmark is available for this public page, so the following ranges are planning estimates rather than guarantees:

| Run type | Example scope | Listings | Duration | Coverage notes |
| --- | --- | --- | --- | --- |
| Small validation run | One focused location with a low limit | Fewer than 1,000 outputs | About 3-5 minutes | Best for checking output shape and field availability |
| Medium monitoring run | Focused location, property type, or price segment | 1,000-5,000 outputs | About 5-15 minutes | Suitable for recurring reporting or segmented exports |
| Large discovery run | Broad location or lightly filtered collection | 5,000+ outputs | About 15-30 minutes | May require segmentation and careful downstream QA |

Execution time varies based on filters, result volume, target availability, target response size, enrichment depth, coordinate and map artifact creation, and how much information is returned per listing. Highly filtered runs can finish faster, while broad discovery, enrichment, or detail-rich listing records may take longer. The actor does not claim complete market coverage, fastest execution, official valuation, or lossless collection; use the dataset and run artifacts to evaluate each run against your own workflow requirements.

### Limitations

- Availability depends on what PropertyHub.in.th publicly exposes at run time.
- Some optional fields may be missing on sparse records or listing types that do not expose them.
- Very broad searches may take longer or require higher limits and segmented runs.
- Target-side changes can affect field availability, naming, or visible result counts.
- Regional, account, visibility, listing status, or availability differences may change visible results.
- Listing prices, availability, status, timestamps, and descriptions are point-in-time public signals and should be verified before operational decisions.
- The actor provides structured public real estate data, not legal, financial, investment, valuation, appraisal, MLS, ownership, or brokerage advice.

### Troubleshooting

- **No results returned:** Check location spelling, filters, property category, transaction mode, and whether PropertyHub has matching public records.
- **Fewer results than expected:** Broaden filters, raise the limit, split the run differently, or verify that the target contains enough matching public records.
- **Some fields are empty:** Optional fields depend on what each listing, property, contact, or source page publicly provides.
- **Duplicate-looking records:** Compare `record_id`, `listing.listing_id`, `source_context.canonical_url`, and `entity.url` to decide whether records represent variants, updates, or duplicate listings.
- **Run takes longer than expected:** Reduce scope, lower `limit` for validation, disable enrichment when richer detail is not needed, or split broad collection into smaller segments.
- **Output changed:** Compare the current output with the Field Reference and include a small sample when reporting the issue.
- **Downstream import failed:** Check JSON validity, nullable fields, nested objects, arrays, and whether your destination expects flattened columns.

### FAQ

#### What data does this actor collect?

It collects public PropertyHub.in.th property listing records, including listing identity, sale or rental mode, price, property attributes, location, media, contact fields, related entities, source context, and selected source-specific attributes when available.

#### Can I filter by location, property type, price, bedrooms, furnishing, or amenities?

Yes. The input schema supports `location`, `deal_type`, `property_type`, `min_price`, `max_price`, `bed_count`, `min_area`, `max_useable_area`, `min_land_area`, `max_land_area`, `furnishment`, and `amenities`.

#### Can I provide PropertyHub URLs directly?

No. This actor is configured through structured PropertyHub search fields such as `location`, `deal_type`, `property_type`, price, area, bedrooms, furnishing, and amenities.

#### Why did I receive fewer results than my limit?

The limit is a maximum, not a guarantee. Fewer results can happen when the selected filters expose fewer matching public records, when optional fields are sparse, or when the source result set is smaller than the requested maximum.

#### Where can I find the run summary or interactive map?

Apify output links expose `RUN-SUMMARY`, `RUN-SUMMARY.html`, and `results-map` when those artifacts are created. The dataset remains the primary output for listing records.

#### How should I choose a limit for my first run?

Start with a small validation limit such as 25 or 50 records, inspect the dataset and artifacts, then increase the limit for monitoring, exports, or scheduled runs.

#### Can I schedule recurring runs?

Yes. Use Apify schedules to run the same input daily, weekly, or on a custom cadence for monitoring and reporting.

#### How do I avoid duplicates across runs?

Use `record_id` or `listing.listing_id` as the primary unique key when present. Use `source_context.canonical_url` or `entity.url` as fallback audit keys.

#### Can I use the output with AI agents or automated workflows?

Yes. The actor produces structured JSON records and run artifacts that can be used by AI agents, ETL jobs, dashboards, search indexes, vector stores, CRMs, and downstream APIs.

#### Can I export the data to CSV, Excel, or JSON?

Yes. Apify datasets can be exported in JSON, CSV, Excel, and other supported formats. JSON is recommended when you need to preserve nested objects.

#### Does this actor collect private data or provide official MLS/appraisal data?

No. It collects publicly available PropertyHub.in.th listing information. It does not provide MLS access, ownership verification, appraisal-grade valuation, legal advice, financial advice, or investment advice.

### Compliance & Ethics

#### Responsible Data Collection

This actor collects publicly available **Thailand real estate listing** information from **PropertyHub.in.th** for legitimate business purposes, including:

- **Real estate** research and market analysis
- Property listing monitoring, enrichment, and operational reporting
- Proptech, analytics, CRM, and AI-agent workflows using public listing records

This section is informational and not legal advice. Users are responsible for ensuring that their use of collected data complies with applicable laws, regulations, contractual obligations, and platform terms.

#### Best Practices

- Use collected data in accordance with applicable laws, regulations, and the target site’s terms.
- Respect individual privacy and personal information.
- Use data responsibly and avoid disruptive or excessive collection.
- Do not use this actor for spamming, harassment, discrimination, unlawful housing practices, or other harmful purposes.
- Follow relevant data protection, fair housing, consumer protection, and sector-specific requirements where applicable.
- Review your own retention, access control, and data-sharing policies before operationalizing the dataset.

### Support

For help, use the actor page or Issues section. Include the redacted input used, Apify run ID, expected versus actual behavior, a small output sample when useful, and the downstream destination or export format if the issue is pipeline-related.

# Actor input Schema

## `location` (type: `string`):

Enter a PropertyHub-recognized market such as Bangkok, a district, a neighborhood, or a BTS/MRT station name. Use one focused location per run when you want cleaner exports for monitoring, CRM enrichment, dashboards, or downstream analysis.

## `deal_type` (type: `string`):

Select whether this run should collect sale listings or rental listings. Pair this with location and property type when you need comparable market slices for price tracking, reporting, or CRM enrichment.

## `property_type` (type: `string`):

Optionally narrow the search to one PropertyHub property category. Leave this as Any property type for broader market discovery, or choose a category when you need cleaner downstream segments.

## `min_price` (type: `integer`):

Optional lower bound in THB. Use this with the maximum price when you need a comparable price band for dashboards, alerts, or scheduled monitoring.

## `max_price` (type: `integer`):

Optional upper bound in THB. Keep this empty for broad discovery, or set it to control run size and focus on listings that match your target budget range.

## `bed_count` (type: `string`):

Optional bedroom filter for listing searches that support bedroom-style room selection. Leave empty to include all bedroom counts.

## `min_area` (type: `integer`):

Optional minimum area in square meters. Use this to avoid very small units when preparing market comparisons, CRM lists, or property review queues.

## `max_useable_area` (type: `integer`):

Optional maximum usable or room area in square meters. Pair it with the minimum area to create a bounded size range for repeatable exports.

## `min_land_area` (type: `integer`):

Optional minimum land area in square wah. This is most useful for house, land, town house, shop house, or sale area searches.

## `max_land_area` (type: `integer`):

Optional maximum land area in square wah. Use it with the minimum land area when you need a bounded land-size segment for analysis or monitoring.

## `furnishment` (type: `string`):

Optionally limit results by furnishing status. Leave empty when furnishing is not important for this run.

## `amenities` (type: `array`):

Optionally choose room amenities or building facilities that matching listings should include. Use this for focused lead lists, tenant-ready rentals, amenity-based dashboards, or automated review workflows.

## `enrich_data` (type: `boolean`):

Turn this on for CRM enrichment, property review queues, richer BI records, or agentic workflows that need listing-page context. Leave it off for faster validation runs, lightweight monitoring, or broad exploratory searches.

## `limit` (type: `integer`):

Optional cap on saved property records. Leave empty to let the run collect the available matching records for the selected scope, or set a number to keep validation runs and recurring jobs bounded.

## `mcpConnectors` (type: `array`):

Choose user-authorized MCP connectors for optional delivery after the dataset, run summary, and interactive map are saved. The handoff includes run counts, scope, enrichment status, and links when available. Leave empty to only save listings to the Apify dataset and key-value store.

## Actor input object example

```json
{
  "deal_type": "sale",
  "property_type": "",
  "bed_count": "",
  "furnishment": "",
  "amenities": [],
  "enrich_data": true,
  "limit": 100,
  "mcpConnectors": []
}
```

# Actor output Schema

## `results` (type: `string`):

Grouped PropertyHub.in.th property listing records saved by this run.

## `runSummaryJson` (type: `string`):

Machine-readable end-of-run summary with totals, filter context, enrichment counts, map coverage, and artifact keys.

## `runSummaryHtml` (type: `string`):

Human-readable end-of-run report with listing totals, coverage, enrichment, pricing, map, and sample-record context.

## `resultsMap` (type: `string`):

Standalone HTML map for saved listing records that include valid latitude and longitude values. Runs with no valid coordinates still save a map report explaining that no locations could be plotted.

# 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 = {
    "limit": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("fatihtahta/propertyhub-in-th-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 = { "limit": 100 }

# Run the Actor and wait for it to finish
run = client.actor("fatihtahta/propertyhub-in-th-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "limit": 100
}' |
apify call fatihtahta/propertyhub-in-th-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=fatihtahta/propertyhub-in-th-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "PropertyHub.in.th Scraper | Thailand Real Estate",
        "description": "Extract PropertyHub.in.th property listings at scale with clean JSON, prices, photos, descriptions, agent contacts, amenities, and map-ready coordinates. Built for Thailand real estate intelligence, lead enrichment, inventory monitoring, CRM, BI, and AI workflows.",
        "version": "0.1",
        "x-build-id": "oOe9o2QackUo8UwRw"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/fatihtahta~propertyhub-in-th-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-fatihtahta-propertyhub-in-th-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/fatihtahta~propertyhub-in-th-scraper/runs": {
            "post": {
                "operationId": "runs-sync-fatihtahta-propertyhub-in-th-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/fatihtahta~propertyhub-in-th-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-fatihtahta-propertyhub-in-th-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "location": {
                        "title": "Set a Location, Transit Station, District, or Market",
                        "type": "string",
                        "description": "Enter a PropertyHub-recognized market such as Bangkok, a district, a neighborhood, or a BTS/MRT station name. Use one focused location per run when you want cleaner exports for monitoring, CRM enrichment, dashboards, or downstream analysis."
                    },
                    "deal_type": {
                        "title": "Choose Sale or Rental Listings",
                        "enum": [
                            "sale",
                            "rent"
                        ],
                        "type": "string",
                        "description": "Select whether this run should collect sale listings or rental listings. Pair this with location and property type when you need comparable market slices for price tracking, reporting, or CRM enrichment.",
                        "default": "sale"
                    },
                    "property_type": {
                        "title": "Choose a Property Category",
                        "enum": [
                            "",
                            "Condominium",
                            "Shop house",
                            "House",
                            "Land",
                            "Office",
                            "Town house",
                            "Sale area",
                            "Apartment"
                        ],
                        "type": "string",
                        "description": "Optionally narrow the search to one PropertyHub property category. Leave this as Any property type for broader market discovery, or choose a category when you need cleaner downstream segments.",
                        "default": ""
                    },
                    "min_price": {
                        "title": "Set a Minimum Asking Price or Monthly Rent",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional lower bound in THB. Use this with the maximum price when you need a comparable price band for dashboards, alerts, or scheduled monitoring."
                    },
                    "max_price": {
                        "title": "Set a Maximum Asking Price or Monthly Rent",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional upper bound in THB. Keep this empty for broad discovery, or set it to control run size and focus on listings that match your target budget range."
                    },
                    "bed_count": {
                        "title": "Filter by Bedroom Count",
                        "enum": [
                            "",
                            "Studio",
                            "1 bedroom",
                            "2 bedroom",
                            "3 bedroom",
                            "4 bedroom"
                        ],
                        "type": "string",
                        "description": "Optional bedroom filter for listing searches that support bedroom-style room selection. Leave empty to include all bedroom counts.",
                        "default": ""
                    },
                    "min_area": {
                        "title": "Set a Minimum Room or Usable Area",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional minimum area in square meters. Use this to avoid very small units when preparing market comparisons, CRM lists, or property review queues."
                    },
                    "max_useable_area": {
                        "title": "Set a Maximum Room or Usable Area",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional maximum usable or room area in square meters. Pair it with the minimum area to create a bounded size range for repeatable exports."
                    },
                    "min_land_area": {
                        "title": "Set a Minimum Land Area",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional minimum land area in square wah. This is most useful for house, land, town house, shop house, or sale area searches."
                    },
                    "max_land_area": {
                        "title": "Set a Maximum Land Area",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional maximum land area in square wah. Use it with the minimum land area when you need a bounded land-size segment for analysis or monitoring."
                    },
                    "furnishment": {
                        "title": "Filter by Furnishing Status",
                        "enum": [
                            "",
                            "Fully",
                            "Partly",
                            "Unfurnished"
                        ],
                        "type": "string",
                        "description": "Optionally limit results by furnishing status. Leave empty when furnishing is not important for this run.",
                        "default": ""
                    },
                    "amenities": {
                        "title": "Require Specific Amenities or Building Facilities",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Optionally choose room amenities or building facilities that matching listings should include. Use this for focused lead lists, tenant-ready rentals, amenity-based dashboards, or automated review workflows.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "Furniture",
                                "Air conditioner",
                                "Room digital lock system",
                                "TV",
                                "Fridge",
                                "Wireless internet (WIFI) in the room",
                                "Hot/warm water heater",
                                "Bath",
                                "Cooking stove",
                                "Microwave",
                                "Hood",
                                "Washing machine",
                                "Lift",
                                "Parking",
                                "Motorcycle Parking",
                                "Closed Circuit Television (CCTV)",
                                "Pool",
                                "Fitness",
                                "Sauna",
                                "Stream",
                                "EV Charger",
                                "Internet",
                                "Security",
                                "Library",
                                "Shop",
                                "Meeting Room",
                                "Park",
                                "Restaurant",
                                "Laundry shop",
                                "Playground",
                                "Shuttle",
                                "Stadium (Tennis/Basketball)"
                            ]
                        },
                        "default": []
                    },
                    "enrich_data": {
                        "title": "Collect Richer Property Listing Details",
                        "type": "boolean",
                        "description": "Turn this on for CRM enrichment, property review queues, richer BI records, or agentic workflows that need listing-page context. Leave it off for faster validation runs, lightweight monitoring, or broad exploratory searches.",
                        "default": true
                    },
                    "limit": {
                        "title": "Set the Maximum Number of Listings to Save",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Optional cap on saved property records. Leave empty to let the run collect the available matching records for the selected scope, or set a number to keep validation runs and recurring jobs bounded."
                    },
                    "mcpConnectors": {
                        "title": "Select Optional MCP Connectors for Listing Handoff",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose user-authorized MCP connectors for optional delivery after the dataset, run summary, and interactive map are saved. The handoff includes run counts, scope, enrichment status, and links when available. Leave empty to only save listings to the Apify dataset and key-value store.",
                        "default": []
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
