# Bayut Properties Search Scraper (UAE) (`scrapyx/bayut-properties-search-scraper`) Actor

Property listings from Bayut.com, the UAE's largest property portal: price in AED, rent frequency, beds, baths, area in m² and sqft, location chain with coordinates, agency and agent contacts, verification and listing tier. Rent or sale, any category and location.

- **URL**: https://apify.com/scrapyx/bayut-properties-search-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.26 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bayut Properties Search Scraper (UAE)

Property listings from **Bayut.com**, the UAE's largest property portal —
Dubai, Abu Dhabi, Sharjah and the other emirates, for rent or for sale:
price in AED, rent frequency, bedrooms, bathrooms, area in m² **and** sqft,
the full location chain (emirate → community → sub-community → building)
with coordinates, agency and agent contact details, verification status,
furnishing, completion status, paid listing tier, photo count, timestamps,
and the listing URL.

> **Need the full listing?** This Actor returns search results (the card data). For each listing's full description, amenities, every photo, floor plans, videos and the agent profile, pass this Actor's `url` column to **Bayut Properties Detail Listing Scraper**.

HTTP only. It reads the structured page state Bayut ships with every search
page — the same objects its own front end renders — so every field is the
site's own value. No login, no API key, no browser.

### What it is for

- **Rent and price monitoring** by community and property type, on a schedule.
- **Agent and agency lead lists** — every row carries the agency, agent name
  and phone / mobile / WhatsApp numbers published on the ad.
- **Market research** — 24 listings per request, with Bayut's own location
  and category ids for joining.

### Input

| field | what it does |
| --- | --- |
| `purpose` | `to-rent` or `for-sale`. |
| `category` | Bayut's URL slug: `apartments`, `villas`, `townhouses`, `penthouse`, `hotel-apartments`, `offices`, `shops`, … or `property` for everything. |
| `locations` | One search per entry — the location path from any Bayut URL: `dubai`, `dubai/dubai-marina`, `abu-dhabi`, `sharjah`, `dubai/jumeirah-village-circle-jvc`. |
| `maxItems` | Listings per location (default 100, `0` = no cap). |
| `maxPages`, `maxConcurrency`, `minRequestInterval`, `proxyConfiguration` | Limits and transport. |

Each location gets its own `SEARCH_SUMMARY` row, followed by its `LISTING` rows.

### Five things about this site worth knowing before you trust a run

#### 1. A category Bayut does not know returns every property type, silently

`/to-rent/notacategory/dubai/dubai-marina/` is HTTP 200 with **5,571** real
listings — every type in Dubai Marina — while the real apartments search has
5,441. Nothing errors, and the page even echoes the bogus slug back. This
Actor does not trust the echo: it checks that the rows on page 1 actually
carry the purpose, category and location you asked for. If they don't, the
search stops with **zero rows** and `filterApplied: false`, instead of handing
you thousands of listings under the wrong label.

#### 2. There are two totals, and they disagree

For rent / apartments / Dubai the search engine estimates **126,085** matches
(and says itself that the figure is not exhaustive), while the page prints
**94,869**. Neither is provably right, so the summary carries both, named for
what they are: `nbHitsEstimate` (with `nbHitsIsExhaustive`) and
`siteDisplayedCount`. On a narrower search they converge (Dubai Marina:
5,441 vs 5,448).

#### 3. Page one is an advert slot, not a sample

In the default order the first pages are all `superhot` — the most expensive
paid tier (30/30 in the verification run). Every row keeps its `product`
tier and the summary counts them in `listingTierCounts`, so a first page is
never mistaken for a representative one.

#### 4. `area` is square metres; the site shows square feet

`area: 90.95` is displayed on Bayut as "979 sqft". `area` is passed through
untouched and `areaSqft` is added, computed exactly the way the site computes
its label (checked 4/4 against live cards).

#### 5. "Rent" is spelled two ways

The URL says `to-rent`; every row says `purpose: "for-rent"`. Both are correct —
just don't filter your output on the URL spelling.

### Proxy — why UAE residential is the default, and required

Bayut serves an in-house "Security check" JavaScript challenge to every
datacenter and non-UAE address measured — 56 of 56 requests across seven TLS
fingerprints, from both Apify's datacenter proxy and its bare servers — and
the real page to a UAE residential address on every fingerprint tried. It is
decided by the IP, not the browser fingerprint. Switching the proxy off or to
datacenter will get you an error row explaining exactly that, not empty data.

A page costs about 270 KB of residential transfer (the page is 2.3 MB
uncompressed).

### Output

`LISTING` rows are Bayut's own listing objects, untouched (49 fields), plus
`areaSqft`, `url`, `searchPage`, `searchRank` and the envelope
(`_input`, `_source`, `_scrapedAt`, `recordType`). Timestamps
(`createdAt`, `updatedAt`) are Unix seconds, as Bayut sends them.

```json
{
  "recordType": "LISTING",
  "externalID": "15736690",
  "title": "Upgraded | Full Marina View | Luxury Furniture",
  "purpose": "for-rent",
  "price": 199900,
  "rentFrequency": "yearly",
  "rooms": 2,
  "baths": 3,
  "area": 127.46297088,
  "areaSqft": 1372,
  "furnishingStatus": "furnished",
  "product": "superhot",
  "url": "https://www.bayut.com/property/details-15736690.html"
}
```

### Limits — what this Actor does not claim

- **Listing detail pages** (full description, amenities, all photos) are not
  fetched; the search page already carries 49 fields per listing.
- **Price, bedroom and other query-string filters** are not offered: they were
  not verified against the rows they return, and on this site an
  unrecognised value is answered with results, not an error.
- The totals are Bayut's own estimates (see 2 above).

# Actor input Schema

## `purpose` (type: `string`):

Bayut's own path segment. Rows report it as `purpose: for-rent` / `for-sale`.

## `category` (type: `string`):

Bayut category slug as it appears in its URLs, e.g. 'apartments', 'villas', 'townhouses', 'penthouse', 'hotel-apartments', 'offices', 'shops', or 'property' for everything. A slug Bayut does not apply is detected from the rows themselves and reported as filterApplied=false with no rows, rather than returning mislabelled listings.

## `locations` (type: `array`):

One search per entry: Bayut's location path, e.g. 'dubai', 'dubai/dubai-marina', 'abu-dhabi', 'sharjah', 'dubai/jumeirah-village-circle-jvc'. Copy it from any Bayut search URL after the category. Several narrow locations beat one wide one: totals are estimates.

## `maxItems` (type: `integer`):

Stop each search after this many listings (24 per page). 0 = no cap.

## `maxPages` (type: `integer`):

Hard cap on pages per search. 0 = no cap beyond maxItems and the end of results.

## `maxConcurrency` (type: `integer`):

Requests in flight at once, across locations. Pages within one location are always read in order.

## `minRequestInterval` (type: `number`):

Global pacing of request starts.

## `proxyConfiguration` (type: `object`):

Residential in the UAE is REQUIRED, not a preference: Bayut serves its 'Security check' page to every datacenter and non-UAE exit measured (56/56 requests across 7 TLS fingerprints), and the real page to a UAE residential exit on every fingerprint tried.

## Actor input object example

```json
{
  "purpose": "to-rent",
  "category": "apartments",
  "locations": [
    "dubai/dubai-marina"
  ],
  "maxItems": 100,
  "maxPages": 0,
  "maxConcurrency": 3,
  "minRequestInterval": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AE"
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "category": "apartments",
    "locations": [
        "dubai/dubai-marina"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/bayut-properties-search-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 = {
    "category": "apartments",
    "locations": ["dubai/dubai-marina"],
}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/bayut-properties-search-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "category": "apartments",
  "locations": [
    "dubai/dubai-marina"
  ]
}' |
apify call scrapyx/bayut-properties-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/bayut-properties-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1P6HRK1PkjkpYobiX/builds/Lqgc8NTzMUkrYyIrU/openapi.json
