# Bayut Saudi Arabia Scraper with Contacts & Features (`fatihtahta/bayut-saudi-arabia-property-scraper`) Actor

Extract Bayut Saudi Arabia property listings with prices, locations, specs, descriptions, amenities, media, coordinates, and available agent or agency contacts. Get pipeline-ready records for market research, comps, inventory monitoring, CRM enrichment, and AI workflows.

- **URL**: https://apify.com/fatihtahta/bayut-saudi-arabia-property-scraper.md
- **Developed by:** [Fatih Tahta](https://apify.com/fatihtahta) (community)
- **Categories:** Real estate, Agents, Lead generation
- **Stats:** 2 total users, 1 monthly users, 42.9% 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/docs.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## Bayut KSA Property Scraper

**Slug:** `fatihtahta/bayut-ksa-property-scraper`

### Overview

Bayut KSA Property Scraper collects structured public property listings from [Bayut Saudi Arabia](https://www.bayut.sa/), including listing identity, asking price, transaction type, location, property characteristics, media, and available agent or agency context. Bayut Saudi Arabia is a public property marketplace whose listing inventory is useful for understanding visible residential and commercial supply across Saudi cities and neighborhoods. The actor supports direct property-listing URLs as well as repeatable countrywide or location-focused searches with property, price, area, room, media, furnishing, keyword, agency, status, and ordering filters. URL seeds take precedence, so supplying them never starts an additional structured search. Optional enrichment can add fuller descriptions, amenities, media URLs, regulatory values, project context, and publicly available contact channels when present. Every result is written as a structured property-listing record suitable for review, export, ETL pipelines, BI dashboards, AI-agent workflows, and downstream applications. Stable identifiers and grouped objects make recurring datasets easier to compare, deduplicate, and synchronize. The actor is designed for consistent recurring acquisition of publicly visible listing data while acknowledging that availability and field completeness depend on what Bayut exposes at run time.

### What Makes This Actor Different

- **Pipeline-ready property records:** each dataset row uses a stable `property_listing` envelope with documented identity, source, listing, pricing, location, property, media, relationship, contact, and attribute groups.
- **Stable listing identity:** `record_id` is the recommended idempotency key for warehouse upserts, CRM synchronization, repeated-run comparison, search indexes, and deduplication workflows.
- **Saudi property search controls:** searches can be scoped by location, sale or rent mode, residential or commercial property type, price and area ranges, bedroom and bathroom counts, furnishing, media, keyword, agency or agent name, and supported status filters.
- **Independent detail and contact enrichment:** `enrich_data` requests richer listing context, while `enrich_contact` requests available public phone and WhatsApp details. Rows report each outcome independently in `source_context`.
- **Field-preserving grouped output:** meaningful schema-supported source values are retained in logical nested objects instead of being compressed into a small flat summary. Optional fields remain nullable when a listing does not expose them.
- **Operational run receipts:** machine-readable and human-readable run summaries report saved listings, duplicate and invalid records skipped, search scope, enrichment outcomes, asking-price statistics, field coverage, warnings, and artifact availability.
- **Map-ready review:** coordinate-capable records include `location.latitude` and `location.longitude`; the interactive map artifact clusters valid listing locations and reports how many rows could be mapped.
- **Agentic workflow support:** documented inputs, a stable field reference, structured output, run artifacts, and optional MCP summary delivery let automated systems evaluate a run without private implementation context.

### Who Should Use This Actor

- **Real estate investors and analysts:** assemble scoped comparable-listing datasets by geography, property type, asking-price band, size, and transaction mode for independent research.
- **Brokerages and agencies:** monitor publicly visible inventory, listing presentation, media coverage, agent or agency relationships, and selected market segments.
- **Market research teams:** create repeatable snapshots of visible supply, asking prices, property mix, neighborhoods, and listing status for reporting.
- **Proptech and data engineering teams:** ingest normalized property records into warehouses, search products, internal catalogs, CRMs, and enrichment pipelines.
- **AI agents and workflow automations:** generate a constrained search, inspect run receipts, reason over structured listings, and route follow-up work using stable identifiers.
- **Lead and operations teams:** review public listing contact channels and agent or agency context when those values are available and appropriate for the workflow.
- **BI and monitoring teams:** schedule segmented runs and compare price, status, location, enrichment, and record-count changes over time.

### Common Use Cases

- **Market intelligence:** monitor visible residential or commercial supply, asking-price ranges, locations, property categories, and listing status.
- **Comparable-listing research:** collect public listings for a specific neighborhood, transaction type, property type, size range, or price segment.
- **Competitive monitoring:** track the public listings associated with a named agent or agency and compare recurring inventory snapshots.
- **Property catalog building:** populate an internal listing directory with structured identity, location, pricing, property, media, and relationship fields.
- **Dataset enrichment:** add current public descriptions, amenities, media, regulatory attributes, and contact channels to an existing property workflow when available.
- **Recurring reporting:** schedule consistent queries for dashboards, alerts, inventory snapshots, geographic review, and analyst reports.
- **Media-quality review:** identify listings that expose photos, videos, or 360-degree content and analyze media coverage using structured fields.
- **Agentic research:** let an internal agent run a scoped collection, read the summary and map, compare records by `record_id`, and prepare the next review step.

### Real-World Questions This Data Can Answer

- Which public Bayut listings match a Saudi location, transaction type, property category, price band, area range, or keyword?
- What asking-price and property-type mix is visible in a selected city or neighborhood at run time?
- Which listings have changed price, status, description, or key property attributes compared with a previous internal snapshot?
- Which agents or agencies are associated with the visible listings in a selected segment?
- Which records include coordinates, media, amenities, regulatory attributes, or public contact channels for further review?
- Which residential listings match selected bedroom, bathroom, residence-type, or furnishing criteria?
- How many saved listings were enriched, skipped as duplicates, or available for map review in a completed run?

### Quick Start

1. Add one or more Bayut property listing URLs for direct collection, or leave `url` empty to build a structured search.
2. For structured search mode, leave `location` empty for countrywide Saudi Arabia results or enter a city, district, neighborhood, or market, then choose `deal_type` and any filters you need.
3. Set a small `limit`, such as 5 or 10, for the first validation run and choose whether `enrich_data` should be enabled.
4. Start the actor in Apify Console and inspect the first dataset records.
5. Review the run summary and map, then increase the limit or schedule the same input after confirming that the record shape fits your workflow.

### Input Parameters

The actor supports two input modes. When `url` contains one or more property listing URLs, it fetches only those listings and ignores every structured search field. When `url` is empty, it builds one countrywide or location-focused search and applies the supported filters below.

| Parameter | Type | Description | Default |
| --- | --- | --- | --- |
| `url` | array of strings | Bayut property listing URLs to collect directly. When supplied, these URLs take precedence and all structured search fields are ignored. | `[]` |
| `location` | string | Optional Saudi city, district, neighborhood, or market recognized by Bayut. Leave empty to search across Saudi Arabia. | All Saudi Arabia |
| `deal_type` | string | Transaction mode: `buy` or `rent`. The `property_status` filter applies only to `buy`. | `buy` |
| `property_type` | string | Property category. Values: `all_residential`, `all_commercial`, `residential_apartment`, `residential_villa`, `residential_floor`, `residential_building`, `residential_land`, `residential_rest_house`, `residential_chalet`, `residential_room`, `residential_townhouse`, `residential_duplex`, `commercial_building`, `commercial_warehouse`, `commercial_land`, `commercial_industrial_land`, `commercial_farm`, `commercial_agriculture_plot`, `commercial_complex`, `commercial_hotel`, `commercial_workshop`, `commercial_factory`, `commercial_school`, `commercial_health_center`, `commercial_gas_station`, or `commercial_showroom`. | `all_residential` |
| `residential_residence_type` | string | Optional residential accommodation type: `family` or `singles`. Omitted automatically for commercial property types. | – |
| `bedroom_count` | array of strings | One or more residential bedroom counts: `studio`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, or `8+`. Omitted automatically for commercial property types. | `[]` |
| `bathroom_count` | array of strings | One or more residential bathroom counts: `1`, `2`, `3`, `4`, `5`, or `6+`. Omitted automatically for commercial property types. | `[]` |
| `min_price` | integer | Minimum displayed asking price or rent in Saudi riyals. Must not exceed `max_price`. | – |
| `max_price` | integer | Maximum displayed asking price or rent in Saudi riyals. Must be at least `min_price`. | – |
| `min_area` | integer | Minimum source-reported property area in square metres. Must not exceed `max_area`. | – |
| `max_area` | integer | Maximum source-reported property area in square metres. Must be at least `min_area`. | – |
| `keyword` | string | Keyword or phrase used to narrow listing text, such as `sea view`, `furnished`, or `corner villa`. | – |
| `agent_agency_name` | string | Public Bayut agent or agency name used to narrow the result set. An unmatched name can produce no results. | – |
| `multimedia` | array of strings | Required media types: `photos`, `video`, or `360_tour`. When several values are selected, listings must satisfy every selected media requirement. | `[]` |
| `furnishment` | string | Furnishing filter: `furnished` or `unfurnished`. | – |
| `sort_by` | string | Result order: `default`, `newest`, `price_low_to_high`, `price_high_to_low`, or `verified`. | `default` |
| `property_status` | string | Buy-only property status: `ready` or `off_plan`. Omitted automatically for rent searches. | – |
| `enrich_data` | boolean | When enabled, requests fuller public details such as descriptions, amenities, expanded media, regulatory values, and project context. | `true` |
| `enrich_contact` | boolean | When enabled, requests available public phone, WhatsApp, and proxy contact details for each property. | `true` |
| `limit` | integer | Maximum number of property records to save. Minimum value: `1`. Leave empty for no user-defined record cap. | – |
| `mcpConnectors` | array of connector resources | Optional Apify-authorized connectors for concise post-run summary delivery through a compatible output-style tool. The full listing dataset is not sent through MCP. | `[]` |

### Choosing Inputs

Use `url` when you already know the exact Bayut property listings to collect. URL mode accepts property listing URLs only, fetches those listings directly, and ignores `location`, `deal_type`, property filters, keyword, agency, and sorting inputs. This prevents a direct-listing run from starting an additional search.

Leave `url` empty when you want discovery through structured query mode. Use `location` for a focused scope; one city or neighborhood per run usually creates cleaner recurring comparisons, while leaving it empty enables countrywide discovery. `deal_type` separates purchase and rental markets, and `property_type` separates residential and commercial inventory or selects a specific category.

Add price and area ranges when the workflow needs a comparable segment. Bedroom, bathroom, and residence-type filters apply only to residential searches; they are omitted for commercial property types. `property_status` applies only to purchase searches, while keywords, named agents or agencies, media requirements, furnishing, and sorting can further focus the result set.

Narrow filters produce a more targeted dataset but can reduce the number of matching records. Leave location and optional filters empty for broad Saudi Arabia discovery within the selected transaction mode. Start with a small `limit`, inspect the output and run summary, then increase the cap once the field coverage meets your needs. Use `enrich_data: false` for lightweight validation or monitoring and `enrich_data: true` when richer listing-level context is important.

### Input Recipes

- **Direct listing collection:** add one or more Bayut property listing URLs. Any structured search values left in the input are ignored while URLs are present.
- **Validation run:** use one focused location, select `deal_type`, disable enrichment, and set `limit` to 5 or 10. Review the first records before expanding scope.
- **Targeted residential search:** combine a neighborhood with `property_type`, bedroom and bathroom selections, a price band, and optional furnishing or keyword criteria.
- **Commercial discovery:** choose `all_commercial` or a specific commercial property type with a location, price or area range, and a sensible limit. Residential room and residence-type fields are automatically omitted.
- **Recent inventory monitoring:** reuse the same location and filters with `sort_by: newest` on a schedule, then compare records by `record_id` and selected point-in-time fields.
- **Agency portfolio review:** set `agent_agency_name` with a location and transaction mode, then use enrichment when available public relationship and contact context is important.
- **Segmented analysis:** run separate configurations for each city, neighborhood, property type, transaction mode, or price band so downstream comparisons retain a clear segment boundary.

### Example Inputs

#### Example: lightweight Riyadh rental validation

```json
{
  "location": "Riyadh",
  "deal_type": "rent",
  "property_type": "residential_apartment",
  "sort_by": "newest",
  "enrich_data": false,
  "enrich_contact": false,
  "limit": 10
}
````

#### Example: targeted Al Khobar purchase search

```json
{
  "location": "Al Khobar",
  "deal_type": "buy",
  "property_type": "residential_villa",
  "bedroom_count": ["4", "5"],
  "min_price": 1000000,
  "max_price": 3000000,
  "limit": 50
}
```

#### Example: commercial warehouse discovery

```json
{
  "location": "Riyadh",
  "deal_type": "rent",
  "property_type": "commercial_warehouse",
  "min_area": 500,
  "sort_by": "price_low_to_high",
  "enrich_data": true,
  "enrich_contact": true,
  "limit": 25
}
```

### 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 output contract contains one record shape: a normalized property listing identified by `record_type = "property_listing"`. Agent, agency, and project information appears as optional relationships on a listing rather than as separate dataset rows. Run summaries, reports, maps, and diagnostics are key-value-store artifacts, not dataset records.

#### Record envelope and stable identifiers

Every valid row includes `record_type`, `record_id`, `url`, `source_context`, `entity`, and `listing`. The recommended idempotency key is `record_id`, a stable Bayut listing identity stored as text. Use `record_id` for deduplication and upserts; retain `url` and `source_context.source_url` for public-source review and provenance. Stable identifiers make records easier to merge, synchronize, deduplicate, and compare across repeated runs.

#### Example: property listing record

```json
{
  "record_type": "property_listing",
  "record_id": "88039736",
  "url": "https://www.bayut.sa/en/property/details-88039736.html",
  "source_context": {
    "source_id": "bayut_ksa_property_scraper",
    "source_domain": "bayut.sa",
    "source_url": "https://www.bayut.sa/en/property/details-88039736.html",
    "seed_value": "Al Khobar",
    "position": 1,
    "scraped_at": "2026-07-18T06:29:22+00:00",
    "enrichment_status": "enriched"
  },
  "entity": {
    "title": "Sample 3-bedroom apartment for sale in Al Khobar",
    "description": "Sample public listing description for a three-bedroom apartment.",
    "external_ids": {
      "bayut_listing_id": "88039736"
    }
  },
  "listing": {
    "listing_id": "88039736",
    "deal_type": "sale",
    "transaction_type": "for-sale",
    "listing_status": "active",
    "is_verified": true,
    "posted_at": "2026-07-16T09:28:11+00:00",
    "updated_at": "2026-07-16T10:18:02+00:00"
  },
  "pricing": {
    "price": 950000,
    "currency": "SAR"
  },
  "location": {
    "address": "Sample District, Al Khobar, Saudi Arabia",
    "city": "Al Khobar",
    "neighborhood": "Sample District",
    "country": "Saudi Arabia",
    "latitude": 26.22868,
    "longitude": 50.204129
  },
  "property": {
    "property_type": "Apartment",
    "bedrooms": 3,
    "bathrooms": 3,
    "floor_area": 137,
    "area_unit": "sqm",
    "furnishing_status": "unfurnished",
    "amenity_groups": [
      {
        "name": "Main Features",
        "amenities": [{"name": "Air Conditioning"}]
      }
    ]
  },
  "media": {
    "main_image_url": "https://images.example/property-sample.jpg",
    "image_urls": ["https://images.example/property-sample.jpg"],
    "photo_count": 8
  },
  "relationships": {
    "agency": {"id": "sample-agency-1", "name": "Sample Property Agency"},
    "agent": {"id": "sample-agent-1", "name": "Sample Listing Agent"}
  },
  "contact_details": {
    "contact_name": "Sample Listing Agent",
    "phones": ["+966500000000"],
    "whatsapp": "966500000000"
  },
  "attributes": {
    "translations": {"ar": {"title": "شقة نموذجية للبيع في الخبر"}},
    "regulatory": {"brokerage_and_marketing_license_number": "1200000000"}
  }
}
```

Optional groups and fields appear only when Bayut exposes them for that listing and the selected run collects them. The example demonstrates the supported public structure; it is not a claim that every row contains every optional value.

#### Run Summary, Map, And Artifacts

Completed runs expose stable output links in Apify for the dataset and these key-value-store artifacts:

| Artifact | Purpose |
| --- | --- |
| `RUN-SUMMARY` | Machine-readable run receipt with timestamps, duration, status, input and search scope, saved-listing totals, duplicate and invalid records skipped, enrichment outcomes, field coverage, asking-price statistics, breakdowns, map status, warnings, and artifact keys. |
| `RUN-SUMMARY.html` | Human-readable report with listing KPIs and breakdown tables for operational review. |
| `results-map` | Interactive clustered map for saved records with valid coordinates. It also reports inspected, mapped, skipped-coordinate, deduplicated-marker, and marker totals. |
| `RUN-SUMMARY-ERROR` | Best-effort diagnostic created only if summary creation or storage does not complete after listing records have already been saved. |

Property teams can use the report and map to review location distribution and record coverage without opening every row. Data teams and AI agents can treat `RUN-SUMMARY` as a run receipt for validating saved counts, enrichment outcomes, skipped records, coordinate coverage, warning state, and artifact readiness before importing or routing the dataset. These artifacts complement the dataset and do not replace listing records.

When `mcpConnectors` is selected, the actor attempts to send a concise version of the completed run summary and available dataset, report, and map links through a compatible authorized connector. Users authorize the connector in Apify and select it in the actor input; the actor receives only connector identifiers while Apify supplies the third-party credentials server-side. The full property dataset is not sent through MCP, and connector delivery remains optional.

### Field Reference

Required status below refers to the dataset record contract. Fields inside optional groups should be treated as nullable unless stated otherwise.

#### Record envelope

- **record\_type** *(string, required)*: stable record-family value, currently `property_listing`.
- **record\_id** *(string, required)*: stable Bayut listing identity and recommended upsert key.
- **url** *(string, required)*: public Bayut listing URL for review and attribution.

#### Source context

- **source\_context** *(object, required)*: source and collection provenance.
- **source\_context.source\_id** *(string, optional)*: stable source label.
- **source\_context.source\_domain** *(string, optional)*: public source domain, normally `bayut.sa`.
- **source\_context.source\_url** *(string, optional)*: public source URL associated with the normalized row.
- **source\_context.seed\_type** *(string, optional)*: public search-seed classification when present.
- **source\_context.seed\_value** *(string, optional)*: requested location associated with the row.
- **source\_context.position** *(number, optional)*: listing position in the returned search slice.
- **source\_context.scraped\_at** *(string, optional)*: ISO-8601 collection timestamp.
- **source\_context.language / source\_context.country** *(string, optional)*: source locale and country code when present.
- **source\_context.enrichment\_status** *(string, optional)*: indicates whether useful detail fields were added or the row remained a standard lightweight listing.
- **source\_context.contact\_enrichment\_status** *(string, optional)*: set to `enriched` only when the separate contact request returned usable public contact details.

#### Entity

- **entity** *(object, required)*: human-readable listing identity.
- **entity.title** *(string, optional)*: source-provided display title.
- **entity.description** *(string, optional)*: cleaned public listing description when available.
- **entity.external\_ids** *(object, optional)*: Bayut and related source identifiers retained as strings.

#### Listing

- **listing** *(object, required)*: transaction, status, and listing signals.
- **listing.listing\_id** *(string, optional)*: source listing identifier, usually aligned with `record_id`.
- **listing.deal\_type** *(string, optional)*: normalized sale or rent classification.
- **listing.transaction\_type** *(string, optional)*: source transaction label such as `for-sale`.
- **listing.listing\_status** *(string, optional)*: source-provided listing state at collection time.
- **listing.completion\_status** *(string, optional)*: source-provided completion state when available.
- **listing.is\_verified** *(boolean, optional)*: source verification signal; it is not independent legal or ownership verification.
- **listing.posted\_at / listing.updated\_at** *(string, optional)*: normalized source timestamps when available.

#### Availability and pricing

- **availability** *(object, optional)*: source availability state and active flag when supplied; absence does not imply availability.
- **pricing** *(object, optional)*: displayed asking-price and payment details.
- **pricing.price** *(number, optional)*: numeric asking price or rent displayed by the source.
- **pricing.currency** *(string, optional)*: currency code, typically `SAR`.
- **pricing.billing\_period** *(string, optional)*: rental frequency, such as yearly, when supplied.
- **pricing.original\_price** *(number, optional)*: source-displayed price before a discount when available.
- **pricing.discount\_percentage** *(number, optional)*: source-displayed discount percentage when available.

#### Location

- **location** *(object, optional)*: address hierarchy and map coordinates.
- **location.address** *(string, optional)*: readable source location text.
- **location.city** *(string, optional)*: source-provided city.
- **location.neighborhood** *(string, optional)*: neighborhood or district when available.
- **location.country** *(string, optional)*: normalized country display name.
- **location.latitude / location.longitude** *(number, optional)*: source coordinates used for map review; they are not legal boundary data.
- **location.hierarchy** *(array of objects, optional)*: ordered broad-to-specific source location levels.

#### Property

- **property** *(object, optional)*: property classification, room counts, size, furnishing, and amenities.
- **property.property\_id** *(string, optional)*: source property identity when separately supplied.
- **property.property\_type** *(string, optional)*: normalized property category.
- **property.bedrooms / property.bathrooms** *(number, optional)*: source-provided room counts; studios can use zero bedrooms.
- **property.floor\_area / property.land\_area** *(number, optional)*: source-reported floor or plot area.
- **property.area\_unit** *(string, optional)*: unit for area values, commonly `sqm`.
- **property.furnishing\_status** *(string, optional)*: source-provided furnished or unfurnished classification.
- **property.amenity\_groups** *(array of objects, optional)*: grouped public amenities; each group can include a name and an amenity array.

#### Media and metrics

- **media** *(object, optional)*: listing images, video, panoramas, floor plans, or document metadata when available.
- **media.main\_image\_url** *(string, optional)*: primary public image URL.
- **media.image\_urls** *(array of strings, optional)*: ordered public listing image URLs.
- **media.photo\_count / media.video\_count / media.panorama\_count** *(number, optional)*: source-provided media counts.
- **metrics** *(object, optional)*: source-provided rating, review, ranking, or related listing metrics when available.

#### Relationships and contact details

- **relationships** *(object, optional)*: public identities associated with the listing.
- **relationships.agent** *(object, optional)*: public agent identity and available attributes such as ID or name.
- **relationships.agency** *(object, optional)*: public agency identity and available attributes such as ID or name.
- **relationships.project** *(object, optional)*: public project context when associated with the listing.
- **contact\_details** *(object, optional)*: publicly supplied contact channels.
- **contact\_details.contact\_name** *(string, optional)*: public contact display name.
- **contact\_details.phones** *(array of strings, optional)*: deduplicated public phone values.
- **contact\_details.whatsapp** *(string, optional)*: public WhatsApp contact value when supplied.

#### Additional attributes

- **attributes** *(object, optional)*: meaningful public values that do not fit a stronger canonical group.
- **attributes.translations** *(object, optional)*: available bilingual or localized listing text.
- **attributes.regulatory** *(object, optional)*: non-empty public regulatory values, such as a brokerage and marketing license number.

### Data Model Notes

- **Identity:** use `record_id` as the primary match, deduplication, and upsert key; keep it as text even when it contains only digits.
- **Provenance:** retain `url`, `source_context.source_url`, `source_context.source_domain`, and `source_context.scraped_at` when auditability and repeated-run comparison matter.
- **Property value:** `entity`, `listing`, `pricing`, `location`, and `property` carry the main research attributes; `media`, `relationships`, `contact_details`, and `attributes` add optional context.
- **Point-in-time values:** asking prices, availability, status, descriptions, media, and public contact details reflect what was visible at collection time and can change later.
- **Nested objects:** related values stay grouped to preserve meaning in JSON-first pipelines. Flatten them deliberately when a destination requires columns.
- **Optionality:** null-check optional groups and fields because availability varies by listing, property category, geography, visibility, and enrichment outcome.
- **Repeated runs:** compare rows by `record_id`, then evaluate selected business fields and retain Apify run metadata outside the record for a complete audit trail.

### 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 are 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, source presentation experiments, or source-side changes.
- **Optional fields:** null-check optional fields in downstream code, dashboards, and automations.
- **Deduplication:** use `record_id` as the strongest stable key and fall back to `url` only when necessary.
- **Freshness:** results reflect publicly available data at run time.
- **Repeated runs:** use `record_id` 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 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 increasing volume.
- Use one city, neighborhood, property type, transaction mode, or price band per run when cleaner comparisons matter.
- Leave optional filters empty when the goal is broad discovery within a selected location.
- Add filters gradually so you can see how each selection changes the matching dataset.
- Use `enrich_data: false` for lightweight validation and enable it when richer public listing context is required.
- Schedule recurring runs with the same saved input for consistent monitoring workflows.
- Use `record_id` for deduplication and retain the input configuration associated with each run.
- Review the run summary, warning state, field coverage, and map before importing a large result set into a production workflow.

### How to Run on Apify

1. Open the Actor in Apify Console.
2. Enter a location and configure the transaction type and any property filters.
3. Set the maximum number of listings to collect and choose whether enrichment should be enabled.
4. Click **Start** and wait for the run to finish.
5. Open the dataset, inspect the first records, and review the run summary and map.
6. Download results in JSON, CSV, Excel, or another format supported by Apify datasets.

### Agentic And API-First Usage

The actor can serve as a structured public property-data acquisition step inside a larger automated workflow. Its documented inputs, stable listing identity, grouped output, and run receipts allow developers, workflow builders, and AI agents to scope a search, validate the result, and pass records to subsequent systems without inferring undocumented fields.

#### Agent workflow pattern

1. Generate or select a scoped input using the supported fields, with `location` as the primary search scope.
2. Run the actor manually, on a schedule, or through Apify platform automation.
3. Wait for completion and read the property-listing dataset records.
4. Validate records against the Field Reference and required envelope.
5. Read `RUN-SUMMARY` and `results-map` to verify saved counts, skipped outcomes, enrichment, coordinates, map readiness, warnings, and artifact availability.
6. Upsert records into the downstream system using `record_id`.
7. Trigger market analysis, enrichment, alerts, BI refreshes, search or vector indexing, lead review, or human verification.

Practical guidance for agentic systems:

- Keep prompts and automations grounded in the documented input parameters.
- Start with small validation runs before allowing broader automated collection.
- Provide downstream AI steps with the Field Reference and a small representative output sample.
- Provide run summary or map artifacts when an agent needs to reason about completion, record counts, field coverage, location distribution, or follow-up actions.
- Treat optional property and listing fields as nullable rather than asking an agent to infer missing values.
- Store the run ID, input configuration, and export metadata outside the listing record when building audit trails.
- For Claude, Codex, internal copilots, or property workflow agents, pass the input schema, idempotency key, Field Reference, and one representative record when context is limited.

### Scheduling & Automation

#### Scheduling

**Automated Data Collection**

Schedule recurring runs in Apify to create fresh public listing snapshots for monitoring, reporting, and downstream synchronization.

1. Navigate to **Schedules** in Apify Console.
2. Create a daily, weekly, or custom cron schedule.
3. Configure and save the location, filters, enrichment choice, and limit.
4. Enable notifications for run completion.
5. Add webhooks when another system should process the completed run.

#### Integration Options

- **BI dashboards:** monitor visible asking prices, property mix, listing status, enrichment, and geographic distribution over time.
- **Data warehouses and ETL:** upsert structured listing records by `record_id` and retain run metadata for historical analysis.
- **CRM enrichment:** add public listing, agent, agency, location, media, and available contact attributes to property or lead workflows.
- **Webhooks:** trigger validation, ingestion, notification, or review workflows after a completed run.
- **Google Sheets or Airtable:** review smaller exports, create analyst queues, and share scoped property snapshots with operations teams.
- **Search and vector systems:** index titles, descriptions, locations, amenities, and property attributes for structured or semantic discovery.
- **MCP connectors:** authorize a compatible connector in Apify, select it in the actor input, and receive a concise run summary with available dataset, report, and map links. Full listing rows are not delivered through MCP.

### Export Formats And Downstream Use

Apify datasets can be exported for manual review or consumed by downstream systems:

- **JSON:** preserves nested groups for applications, AI agents, and data pipelines.
- **CSV or Excel:** supports spreadsheet workflows, stakeholder review, and lightweight analysis; nested groups may require deliberate flattening.
- **API access:** enables automated ingestion into internal systems and recurring synchronization workflows.
- **BI and warehouses:** supports dashboards, historical analysis, segmentation, and monitoring.
- **Search or vector indexes:** supports property discovery, semantic search, retrieval workflows, and grounded agent context.

### Downstream Pipeline Guide

- **Idempotency:** use `record_id` for upserts and retain it as a string.
- **Null handling:** treat every non-required field and optional object as nullable.
- **Type handling:** preserve numbers, booleans, arrays, and nested objects in JSON-first systems.
- **Flattening:** flatten nested groups deliberately for CSV or Excel and retain the original JSON export for full fidelity.
- **Partitioning:** store run date, input segment, location, property type, transaction mode, and workflow name alongside the records.
- **Change detection:** compare repeated runs by `record_id`, then evaluate fields such as `pricing.price`, `listing.listing_status`, `availability`, `entity.description`, and key property attributes.
- **Quality checks:** monitor record count, skipped duplicates, required identifiers, price and status availability, coordinate coverage, and important optional-field fill rates.
- **Human review:** route records with missing critical values, unusual prices, changed status, material attribute changes, or high-priority segments into a review queue.
- **Retention:** define separate retention periods for raw exports, run receipts, and normalized warehouse tables according to the workflow.

### Performance And Coverage Expectations

No completed benchmark artifact is currently available for a public measured-runtime table. The following ranges are planning estimates, not guarantees:

- **Small runs with fewer than 1,000 outputs:** approximately 3–5 minutes.
- **Medium runs with 1,000–5,000 outputs:** approximately 5–15 minutes.
- **Large runs with more than 5,000 outputs:** approximately 15–30 minutes.

Execution time varies with filter specificity, result volume, Bayut availability, response size, enrichment depth, coordinate and map artifact creation, and how much public information is available per listing. Highly filtered lightweight runs can finish sooner, while broad discovery and detail-rich enrichment can take longer. The requested `limit` caps saved records but does not represent a freshness, completeness, or execution-time guarantee. Use the run summary's measured `duration_seconds`, saved totals, enrichment results, warning state, and map counts as the authoritative receipt for each completed run.

### Limitations

- Results depend on what Bayut Saudi Arabia publicly exposes at run time and do not represent guaranteed full-market coverage.
- Some optional fields can be absent on sparse listings or when enrichment does not add useful detail.
- Very broad searches can take longer and may require a higher `limit` to retain more matching records.
- Direct URL mode supports Bayut property listing URLs only; search-result, agency, project, and other page URLs are rejected rather than converted into a structured search.
- Source presentation changes, regional visibility, listing status, and availability can affect which records and fields are visible.
- Asking prices, availability, status, descriptions, media, and contacts are point-in-time public signals and should be independently verified before operational decisions.
- The actor provides structured public real estate data, not legal, financial, investment, valuation, appraisal, ownership-verification, or brokerage advice.

### Troubleshooting

- **No results returned:** check location spelling, transaction mode, property category, price and area ranges, named agent or agency, and whether Bayut currently shows matching public records.
- **Fewer results than expected:** remove overly narrow filters, raise `limit`, and verify that enough matching records are publicly visible.
- **Some fields are empty:** optional values depend on what each listing publicly provides and whether useful enrichment detail is available.
- **Duplicate-looking records:** compare `record_id`; similar properties can have separate listing identities, while repeated identities should be handled as upserts.
- **Run takes longer than expected:** lower the limit for validation or split a broad market into smaller location, property-type, or price segments.
- **Output changed:** compare the current record with the Field Reference and retain a small sample for support.
- **Downstream import failed:** validate JSON, nullable fields, nested objects, arrays, and whether the destination requires flattened columns.

### FAQ

#### What data does this actor collect?

It collects public Bayut Saudi Arabia property listings with stable identity, listing status, asking price, location, property attributes, media, and available relationship, contact, amenity, translation, and regulatory context.

#### Which filters are available?

You can filter by location, purchase or rent mode, residential or commercial property type, room counts, price, area, keyword, agent or agency name, required media, furnishing, sort order, and buy-only ready or off-plan status.

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

`limit` is a maximum, not a promised count. The selected filters, publicly visible inventory, listing availability, and source conditions can produce fewer matching records.

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

Start with 5 or 10 records, confirm the field shape and optional-field coverage, then raise the limit for the validated workflow.

#### Where are the run summary and interactive map?

Open the run's Outputs or key-value-store links in Apify. `RUN-SUMMARY` is the machine-readable receipt, `RUN-SUMMARY.html` is the report, and `results-map` is the interactive location review.

#### Can I schedule recurring runs?

Yes. Save a consistent input and use Apify Schedules for daily, weekly, or custom recurring collection.

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

Use `record_id` as the upsert key. Compare selected point-in-time fields when you need to detect changes rather than create a new row for every run.

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

Yes. The JSON records, Field Reference, stable identity, and run artifacts are suitable for grounded property workflows, provided agents treat optional values as nullable.

#### Can I export results to CSV, Excel, or JSON?

Yes. Apify datasets support these formats and other platform-supported export options. JSON preserves the nested record structure most faithfully.

#### Does this actor provide private data, MLS records, valuations, or investment advice?

No. It structures publicly visible Bayut listing information and does not provide private access, official MLS completeness, appraisal-grade valuation, ownership verification, or professional advice.

#### What should I include when reporting an issue?

Include the redacted input, Apify run ID, expected and actual behavior, an optional small output sample, and the downstream destination or export format when relevant.

### Compliance & Ethics

#### Responsible Data Collection

This actor collects publicly available property-listing information from Bayut Saudi Arabia for legitimate business purposes, including:

- **Real estate** research and market analysis
- Property inventory monitoring and operational reporting
- Structured data acquisition for authorized analytics and workflow automation

Users are responsible for ensuring that their collection and use comply with applicable requirements. This section is informational and not legal advice.

#### 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 retention, access-control, and data-sharing policies before operationalizing the dataset.

### Support

Use the Issues or support option on the Apify Actor page when help is needed. Include the input used with sensitive values redacted, the run ID, expected versus actual behavior, and an optional small output sample. If the issue involves a pipeline or export, also identify the downstream destination and format so the problem can be reproduced accurately.

# Actor input Schema

## `url` (type: `array`):

Add one public Bayut property listing URL per line, such as https://www.bayut.sa/en/property/details-88016665.html. Only property listing URLs are supported. Leave this empty to use the structured search fields below.

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

Leave empty to search across Saudi Arabia, or enter a location recognized by Bayut such as Riyadh, Al Khobar, Al Hamra, or Al Malqa. Focused locations are useful for repeatable market monitoring and comparisons.

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

Choose Buy for properties offered for sale or Rent for rental listings. Buy is the default and also enables the ready versus off-plan property-status filter below.

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

Select the property category to include in the location search. The default includes all residential listings; choose a specific residential type for a narrower market slice or a commercial type for business-property research.

## `residential_residence_type` (type: `string`):

Optionally narrow residential results to family or singles accommodation. This filter does not apply to commercial property types and is omitted automatically for commercial searches.

## `bedroom_count` (type: `array`):

Choose every bedroom count that should be included, such as Studio, 2, 3, or 8 or more. Multiple selections broaden the residential search across those counts; this filter is omitted automatically for commercial property types.

## `bathroom_count` (type: `array`):

Choose every bathroom count that should be included. Multiple selections broaden the residential search across those counts; this filter is omitted automatically for commercial property types.

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

Only include listings priced at or above this amount in Saudi riyals. Pair it with a maximum price to create a comparable market band for monitoring, reporting, or downstream analysis.

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

Only include listings priced at or below this amount in Saudi riyals. It must be greater than or equal to the minimum price when both values are provided.

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

Only include listings with a reported area at or above this number of square metres. Use an area range to compare properties of a similar size within the selected market.

## `max_area` (type: `integer`):

Only include listings with a reported area at or below this number of square metres. It must be greater than or equal to the minimum area when both values are provided.

## `keyword` (type: `string`):

Enter a focused phrase such as sea view, furnished, corner villa, or near metro. Keywords narrow the same location search and are useful for thematic monitoring, lead qualification, and AI-assisted listing review.

## `agent_agency_name` (type: `string`):

Enter the public Bayut name of an agent or agency to collect listings associated with that identity. Use the clearest available name for repeatable portfolio monitoring or CRM enrichment; an unmatched name produces an empty result rather than broadening the search.

## `multimedia` (type: `array`):

Select one or more media requirements. A listing must contain every selected type, so combining Photos, Video, and 360 Tour creates a narrower dataset suited to visual review or media-quality monitoring.

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

Optionally include only furnished or unfurnished properties. Leave empty when furnishing status should not narrow the location search.

## `sort_by` (type: `string`):

Select the order in which matching listings are collected. Use Newest for monitoring recent inventory, a price order for bounded comparisons, or Verified First when verification status is the primary review signal.

## `property_status` (type: `string`):

Optionally narrow Buy results to completed, ready properties or off-plan properties under development. This setting only applies to Buy and is omitted automatically when Rent is selected.

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

Keep enabled for CRM enrichment, property review, regulatory reporting, search indexing, or ETL workflows that benefit from listing-detail context. Turn it off for faster validation, lightweight monitoring, or pipelines that only need standard search-result fields. A record is marked enriched only when useful additional detail was actually collected.

## `enrich_contact` (type: `boolean`):

Keep enabled to request available public phone, WhatsApp, and proxy contact details for each property. Turn it off when you only need listing data. A record is marked and charged as contact-enriched only when the contact request returns usable details.

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

Choose the maximum number of property records to save for this run. Start with a small value such as 5 or 10 when validating filters and output, then increase it for production collection. Leave empty to continue through the available matching listings without a user-defined record cap.

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

Choose user-authorized connectors for optional post-run delivery after the listing dataset, run summary, report, and map are saved. The full property dataset is not sent through MCP. Leave empty to keep output only in Apify storage.

## Actor input object example

```json
{
  "deal_type": "buy",
  "property_type": "all_residential",
  "bedroom_count": [],
  "bathroom_count": [],
  "multimedia": [],
  "sort_by": "default",
  "enrich_data": true,
  "enrich_contact": true,
  "limit": 100,
  "mcpConnectors": []
}
```

# Actor output Schema

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

Structured Bayut Saudi Arabia property listing records saved by this run.

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

Machine-readable end-of-run totals, search scope, enrichment, coverage, asking-price, and artifact breakdowns.

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

Human-readable real-estate run report with listing KPIs and breakdown tables.

## `interactiveMap` (type: `string`):

Map of saved listings with valid coordinates, marker clustering, property context, and source links. Zero-coordinate runs receive a map report showing no mapped locations.

# 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/bayut-saudi-arabia-property-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "limit": 100 }

# Run the Actor and wait for it to finish
run = client.actor("fatihtahta/bayut-saudi-arabia-property-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/bayut-saudi-arabia-property-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bayut Saudi Arabia Scraper with Contacts & Features",
        "description": "Extract Bayut Saudi Arabia property listings with prices, locations, specs, descriptions, amenities, media, coordinates, and available agent or agency contacts. Get pipeline-ready records for market research, comps, inventory monitoring, CRM enrichment, and AI workflows.",
        "version": "0.1",
        "x-build-id": "ruTlfks04H5PFaSDE"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/fatihtahta~bayut-saudi-arabia-property-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-fatihtahta-bayut-saudi-arabia-property-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~bayut-saudi-arabia-property-scraper/runs": {
            "post": {
                "operationId": "runs-sync-fatihtahta-bayut-saudi-arabia-property-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~bayut-saudi-arabia-property-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-fatihtahta-bayut-saudi-arabia-property-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": {
                    "url": {
                        "title": "Add Bayut Property Listing URLs",
                        "type": "array",
                        "description": "Add one public Bayut property listing URL per line, such as https://www.bayut.sa/en/property/details-88016665.html. Only property listing URLs are supported. Leave this empty to use the structured search fields below.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "location": {
                        "title": "Optionally Focus on a Saudi Location",
                        "type": "string",
                        "description": "Leave empty to search across Saudi Arabia, or enter a location recognized by Bayut such as Riyadh, Al Khobar, Al Hamra, or Al Malqa. Focused locations are useful for repeatable market monitoring and comparisons."
                    },
                    "deal_type": {
                        "title": "Choose Listings for Purchase or Rent",
                        "enum": [
                            "buy",
                            "rent"
                        ],
                        "type": "string",
                        "description": "Choose Buy for properties offered for sale or Rent for rental listings. Buy is the default and also enables the ready versus off-plan property-status filter below.",
                        "default": "buy"
                    },
                    "property_type": {
                        "title": "Choose a Residential or Commercial Property Type",
                        "enum": [
                            "all_residential",
                            "all_commercial",
                            "residential_apartment",
                            "residential_villa",
                            "residential_floor",
                            "residential_building",
                            "residential_land",
                            "residential_rest_house",
                            "residential_chalet",
                            "residential_room",
                            "residential_townhouse",
                            "residential_duplex",
                            "commercial_building",
                            "commercial_warehouse",
                            "commercial_land",
                            "commercial_industrial_land",
                            "commercial_farm",
                            "commercial_agriculture_plot",
                            "commercial_complex",
                            "commercial_hotel",
                            "commercial_workshop",
                            "commercial_factory",
                            "commercial_school",
                            "commercial_health_center",
                            "commercial_gas_station",
                            "commercial_showroom"
                        ],
                        "type": "string",
                        "description": "Select the property category to include in the location search. The default includes all residential listings; choose a specific residential type for a narrower market slice or a commercial type for business-property research.",
                        "default": "all_residential"
                    },
                    "residential_residence_type": {
                        "title": "Choose Family or Singles Accommodation",
                        "enum": [
                            "family",
                            "singles"
                        ],
                        "type": "string",
                        "description": "Optionally narrow residential results to family or singles accommodation. This filter does not apply to commercial property types and is omitted automatically for commercial searches."
                    },
                    "bedroom_count": {
                        "title": "Select One or More Bedroom Counts",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose every bedroom count that should be included, such as Studio, 2, 3, or 8 or more. Multiple selections broaden the residential search across those counts; this filter is omitted automatically for commercial property types.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "studio",
                                "1",
                                "2",
                                "3",
                                "4",
                                "5",
                                "6",
                                "7",
                                "8+"
                            ],
                            "enumTitles": [
                                "Studio",
                                "1 bedroom",
                                "2 bedrooms",
                                "3 bedrooms",
                                "4 bedrooms",
                                "5 bedrooms",
                                "6 bedrooms",
                                "7 bedrooms",
                                "8 or more bedrooms"
                            ]
                        },
                        "default": []
                    },
                    "bathroom_count": {
                        "title": "Select One or More Bathroom Counts",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose every bathroom count that should be included. Multiple selections broaden the residential search across those counts; this filter is omitted automatically for commercial property types.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "1",
                                "2",
                                "3",
                                "4",
                                "5",
                                "6+"
                            ],
                            "enumTitles": [
                                "1 bathroom",
                                "2 bathrooms",
                                "3 bathrooms",
                                "4 bathrooms",
                                "5 bathrooms",
                                "6 or more bathrooms"
                            ]
                        },
                        "default": []
                    },
                    "min_price": {
                        "title": "Set the Minimum Asking Price or Rent (SAR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only include listings priced at or above this amount in Saudi riyals. Pair it with a maximum price to create a comparable market band for monitoring, reporting, or downstream analysis."
                    },
                    "max_price": {
                        "title": "Set the Maximum Asking Price or Rent (SAR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only include listings priced at or below this amount in Saudi riyals. It must be greater than or equal to the minimum price when both values are provided."
                    },
                    "min_area": {
                        "title": "Set the Minimum Property Area (Square Metres)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only include listings with a reported area at or above this number of square metres. Use an area range to compare properties of a similar size within the selected market."
                    },
                    "max_area": {
                        "title": "Set the Maximum Property Area (Square Metres)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only include listings with a reported area at or below this number of square metres. It must be greater than or equal to the minimum area when both values are provided."
                    },
                    "keyword": {
                        "title": "Search Listing Text for a Keyword or Phrase",
                        "type": "string",
                        "description": "Enter a focused phrase such as sea view, furnished, corner villa, or near metro. Keywords narrow the same location search and are useful for thematic monitoring, lead qualification, and AI-assisted listing review."
                    },
                    "agent_agency_name": {
                        "title": "Limit Results to a Bayut Agent or Agency",
                        "type": "string",
                        "description": "Enter the public Bayut name of an agent or agency to collect listings associated with that identity. Use the clearest available name for repeatable portfolio monitoring or CRM enrichment; an unmatched name produces an empty result rather than broadening the search."
                    },
                    "multimedia": {
                        "title": "Require Specific Listing Media",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Select one or more media requirements. A listing must contain every selected type, so combining Photos, Video, and 360 Tour creates a narrower dataset suited to visual review or media-quality monitoring.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "photos",
                                "video",
                                "360_tour"
                            ],
                            "enumTitles": [
                                "Photos available",
                                "Video available",
                                "360 tour available"
                            ]
                        },
                        "default": []
                    },
                    "furnishment": {
                        "title": "Choose the Furnishing Status",
                        "enum": [
                            "furnished",
                            "unfurnished"
                        ],
                        "type": "string",
                        "description": "Optionally include only furnished or unfurnished properties. Leave empty when furnishing status should not narrow the location search."
                    },
                    "sort_by": {
                        "title": "Choose How Matching Listings Are Ordered",
                        "enum": [
                            "default",
                            "newest",
                            "price_low_to_high",
                            "price_high_to_low",
                            "verified"
                        ],
                        "type": "string",
                        "description": "Select the order in which matching listings are collected. Use Newest for monitoring recent inventory, a price order for bounded comparisons, or Verified First when verification status is the primary review signal.",
                        "default": "default"
                    },
                    "property_status": {
                        "title": "Choose Ready or Off-Plan Properties",
                        "enum": [
                            "ready",
                            "off_plan"
                        ],
                        "type": "string",
                        "description": "Optionally narrow Buy results to completed, ready properties or off-plan properties under development. This setting only applies to Buy and is omitted automatically when Rent is selected."
                    },
                    "enrich_data": {
                        "title": "Add Richer Public Details to Every Saved Listing",
                        "type": "boolean",
                        "description": "Keep enabled for CRM enrichment, property review, regulatory reporting, search indexing, or ETL workflows that benefit from listing-detail context. Turn it off for faster validation, lightweight monitoring, or pipelines that only need standard search-result fields. A record is marked enriched only when useful additional detail was actually collected.",
                        "default": true
                    },
                    "enrich_contact": {
                        "title": "Add Public Contact Details to Every Saved Listing",
                        "type": "boolean",
                        "description": "Keep enabled to request available public phone, WhatsApp, and proxy contact details for each property. Turn it off when you only need listing data. A record is marked and charged as contact-enriched only when the contact request returns usable details.",
                        "default": true
                    },
                    "limit": {
                        "title": "Set the Maximum Number of Listings to Save",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Choose the maximum number of property records to save for this run. Start with a small value such as 5 or 10 when validating filters and output, then increase it for production collection. Leave empty to continue through the available matching listings without a user-defined record cap."
                    },
                    "mcpConnectors": {
                        "title": "MCP Connectors for Run-Summary Delivery",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose user-authorized connectors for optional post-run delivery after the listing dataset, run summary, report, and map are saved. The full property dataset is not sent through MCP. Leave empty to keep output only in Apify storage.",
                        "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
