# Gulf Real Estate Listings (`asgardlabs/gulf-property-api`) Actor

Property Finder listings across UAE, Qatar, Saudi Arabia, Bahrain and Egypt: price, size, location with coordinates, and the broker's phone, WhatsApp and email. New-listing and price-drop alerts. Half a cent per search, a fifth of a cent per listing.

- **URL**: https://apify.com/asgardlabs/gulf-property-api.md
- **Developed by:** [Asgard Labs](https://apify.com/asgardlabs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 listing delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Gulf Real Estate Listings – Property Finder UAE, Qatar, Saudi, Bahrain, Egypt

Paste Property Finder search links, or describe a search (country, rent or buy, property type, price range, keyword). Get the listings as clean records: price with currency and period, bedrooms, bathrooms, size, furnished, completion status, location down to the tower with map coordinates, amenities, agent, broker with phone, WhatsApp and email, verified and developer flags, images, listed date.

Run it again with **only new** on and you get only new listings and price changes since last time, with the old and new price. Schedule it daily and you have a market monitor for any search.

Five country sites: UAE, Qatar, Saudi Arabia, Bahrain, Egypt. Rent and sale. No login, no proxies, no browser.

### Property Finder listing data per property

- **id, reference, country, purpose, propertyType, title, url, listedAt, lastRefreshedAt**
- **price** – value, currency, period (yearly / monthly / sell), per-area price, number of cheques, price-drop flag
- **bedrooms, bathrooms, size, furnished, completionStatus**
- **location** – full name, city, community, sub-community, tower, coordinates, the whole location tree
- **amenities, description, images, imagesCount, floorPlans**
- **agent** (name, super-agent flag, languages) and **broker** (name, phone, email, address); **contacts** – phone, WhatsApp, email
- **flags** – verified, directFromDeveloper, newConstruction, featured, premium, exclusive, highDemand, greatValue, luxe, hasVideo, has360
- **isNew, firstSeenAt, priceChange** (from, to, percent), **searchUrl, totalInSearch**

### Use cases

- Agents watching a community.
- Investors tracking price drops.
- Proptech and data teams building datasets.
- Lead generation from broker contacts.

### Input

| Field | Default | Meaning |
|---|---|---|
| `searchUrls` | – | Any search or category page from propertyfinder.ae / .qa / .sa / .bh / .eg. Page numbers, trailing slashes and the default sort are ignored, so the same search written several ways counts once. Listing or agent pages are reported as "not a search page". |
| `queries` | – | Structured searches: `{ country, purpose, propertyType, minPrice, maxPrice, keyword, furnished, sort, locationId }`. |
| `maxListingsPerSearch` | 100 | Up to 10,000. About 25 listings per request. |
| `onlyNew` | false | Only new listings and price changes since the last run. History per search in a key-value store. |
| `minBedrooms`, `maxBedrooms`, `propertyTypes`, `verifiedOnly` | – | Filters (studio = 0 bedrooms). |
| `includeDescription` | true | Keep the description text. |
| `timeoutSecs` | 300 | Time budget per search. |
| `concurrency` | 3 | Searches read in parallel. |
| `stateStoreName` | gulf-property-state | Where the history lives. Use a different name for a separate watchlist. |

### Output example

```json
{ "id": "139205248", "reference": "BH-R-228929-3", "country": "AE", "purpose": "rent", "propertyType": "Apartment", "title": "2-months free rent | Brand new | Metro nearby",
  "url": "https://www.propertyfinder.ae/en/plp/rent/…-139205248.html",
  "price": { "value": 90000, "currency": "AED", "period": "yearly", "isPriceDrop": false, "numberOfCheques": 1 },
  "bedrooms": "studio", "bathrooms": "1", "size": { "value": 538, "unit": "sqft" }, "furnished": false,
  "location": { "full": "City Tower 1, City Towers, Sheikh Zayed Road, Dubai", "city": "Dubai", "community": "Sheikh Zayed Road", "subCommunity": "City Towers", "tower": "City Tower 1", "lat": 25.219, "lon": 55.279 },
  "amenities": ["Central A/C", "Shared Gym", "Shared Pool"], "agent": { "name": "Amanda Hourieh", "isSuperAgent": true, "languages": ["English", "Arabic"] },
  "broker": { "name": "betterhomes - Portfolio Leasing", "phone": "+97144081000", "email": "customercare@bhomes.com" }, "contacts": { "phone": "+97144081000", "whatsapp": "+97145560345", "email": "customercare@bhomes.com" },
  "flags": { "verified": true, "directFromDeveloper": false, "newConstruction": false, "premium": true, "highDemand": true },
  "images": ["https://static.shared.propertyfinder.ae/…/668x452.jpg"], "listedAt": "2026-09-02T06:09:59Z",
  "isNew": true, "priceChange": null, "searchUrl": "…", "totalInSearch": 122054 }
```

### How to use

1. Paste your Property Finder search links, or a structured query with country and purpose into the input form. The example input is ready to run as is.
2. Click **Start**. Rows appear in the **Output** tab as they are found.
3. Download the table as CSV, JSON or Excel, or read it through the API.
4. For monitoring, create a **Schedule** and switch on `onlyNew`: later runs return only what changed, and only that is charged.

### Pricing

Pay per event: **`search` $0.005** per search that answered, **`listing` $0.002** per listing in the output. 1,000 listings is about $2.05. A daily `onlyNew` monitor on 20 searches costs a few cents. Searches that fail (blocked, wrong link, timeout) are free.

### Good to know

- **Property Finder only.** Bayut and Dubizzle block automated access and are not covered.
- **Bedroom filters** are applied after fetching, so a narrow bedroom filter reads more pages than it returns.
- **Agent emails** are usually masked by the site; broker phone, WhatsApp and email are present on nearly every listing.
- **Stopping at your spend limit** is safe: the history is not touched by a stopped run, so the next run still reports the undelivered listings as new.
- **Errors are in plain words:** `blocked (403)`, `timeout`, `not a search page`, `ENOTFOUND (domain not found)`.

### Use from code or an AI agent

Every run can be started and read through the Apify API, the JavaScript and Python clients, or an AI agent with tool access. Open the **API** tab on this page for ready-made snippets. Pricing is per event, so an agent pays only for what it receives.

### FAQ

**Are Bayut and Dubizzle covered?**
Not yet. They block automated access from data centres. Property Finder covers UAE, Qatar, Saudi Arabia, Bahrain and Egypt.

**Are the phone numbers real broker numbers?**
Yes, the broker phone, WhatsApp and email the listing publishes, not a masked portal number.

**How are rent and sale prices reported?**
With the currency of the country and the period for rentals: yearly, monthly, weekly or daily as the listing states.

**Can I get price-drop alerts?**
Yes. Switch on `onlyNew`; later runs return new listings and any listing whose price changed, with the old and new price.

**What if a search returns no listings?**
A genuinely empty search is charged as one search and returns nothing. A blocked or changed page is reported and free.

# Actor input Schema

## `searchUrls` (type: `array`):

Any search or category page from propertyfinder.ae / .qa / .sa / .bh / .eg, e.g. https://www.propertyfinder.ae/en/buy/dubai/apartments-for-sale.html. Page numbers and trailing slashes are ignored; listing or agent pages are reported as not a search page.

## `queries` (type: `array`):

Objects with country (ae|qa|sa|bh|eg), purpose (rent|buy), propertyType (apartment, villa, townhouse, penthouse, office, shop, land…), minPrice, maxPrice, keyword, furnished, sort (newest|price-asc|price-desc), locationId.

## `maxListingsPerSearch` (type: `integer`):

Newest listings first, 25 per page. Stops when reached; the site total is reported in every row as totalInSearch.

## `onlyNew` (type: `boolean`):

Remembers listing ids and prices per search in a key-value store; later runs return only new listings and price changes. Ideal for daily schedules.

## `minBedrooms` (type: `integer`):

Keep listings with at least this many bedrooms. Studio counts as 0. Applied after download, so filtered listings are not charged.

## `maxBedrooms` (type: `integer`):

Keep listings with at most this many bedrooms. Applied after download, so filtered listings are not charged.

## `propertyTypes` (type: `array`):

Keep only these property types as the site names them, e.g. Apartment, Villa, Townhouse. Case-insensitive, applied after download.

## `verifiedOnly` (type: `boolean`):

Keep only listings the site marks as verified.

## `includeDescription` (type: `boolean`):

Include the full listing description text. Off makes rows smaller.

## `timeoutSecs` (type: `integer`):

A search that takes longer is reported as timed out; listings already delivered stay delivered.

## `concurrency` (type: `integer`):

How many searches to read at the same time. Three is gentle on the site.

## `stateStoreName` (type: `string`):

Key-value store in your account that keeps the history per search for "only new". Letters, digits and dashes.

## Actor input object example

```json
{
  "searchUrls": [
    "https://www.propertyfinder.ae/en/rent/dubai/properties-for-rent.html"
  ],
  "queries": [],
  "maxListingsPerSearch": 100,
  "onlyNew": false,
  "propertyTypes": [],
  "verifiedOnly": false,
  "includeDescription": true,
  "timeoutSecs": 300,
  "concurrency": 3,
  "stateStoreName": "gulf-property-state"
}
```

# Actor output Schema

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

One row per listing: price with period and currency, bedrooms, size, location with coordinates, agent, broker contacts, flags, images, isNew, priceChange.

## `summary` (type: `string`):

Counts, skipped inputs with reasons, errors in plain words, charge-limit state.

# 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 = {
    "searchUrls": [
        "https://www.propertyfinder.ae/en/rent/dubai/properties-for-rent.html"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("asgardlabs/gulf-property-api").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 = { "searchUrls": ["https://www.propertyfinder.ae/en/rent/dubai/properties-for-rent.html"] }

# Run the Actor and wait for it to finish
run = client.actor("asgardlabs/gulf-property-api").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 '{
  "searchUrls": [
    "https://www.propertyfinder.ae/en/rent/dubai/properties-for-rent.html"
  ]
}' |
apify call asgardlabs/gulf-property-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,asgardlabs/gulf-property-api"
        }
    }
}
```

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/K2MGmRxJkXfmLLWqz/builds/c62TRIixiWxC0Nanp/openapi.json
