# Dubai Property Data Enricher (`galdrcode_dev/dubai-property-data-enricher`) Actor

Scrape Dubai estate listings from Property Finder and Bayut. Get prices, property details, RERA permit numbers, agent info, amenities, GPS coordinates, etc. Supports search URLs and direct listing URLs. Returns structured data ready for analysis. PDPL-compliant - no personal owner data collected.

- **URL**: https://apify.com/galdrcode\_dev/dubai-property-data-enricher.md
- **Developed by:** [Galdrcode](https://apify.com/galdrcode_dev) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 detail results

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

## Property Finder & Bayut Listings Scraper

Extract structured property listing data from Dubai's two largest real estate portals: **Property Finder** and **Bayut**.

### What it does

This actor scrapes search results and individual listing pages from propertyfinder.ae and bayut.com. It extracts:

- **Price, bedrooms, bathrooms, area (sqft + sqm)** — the basics
- **RERA permit number** — scraped from detail pages, with a Trakheesi verification link
- **Location data** — community, building, city, GPS coordinates
- **Agent & agency info** — name, company, broker registration number (BRN), public phone number
- **Listing metadata** — type, purpose (sale/rent), furnishing, completion status, days on market
- **Description & amenities** — full text and feature lists from detail pages
- **Images** — up to 10 photo URLs per listing
- **Cross-portal deduplication** — normalized key to match the same property across PF and Bayut
- **Incremental mode** — skip previously scraped listings on scheduled runs

#### PDPL-Compliant

This actor does **not** extract property owner names or email addresses. It collects only publicly displayed listing and agent data (including agent phone numbers shown on the portal), making it safe for commercial use under UAE data protection law (PDPL).

### How to use

1. Go to [propertyfinder.ae](https://www.propertyfinder.ae) or [bayut.com](https://www.bayut.com)
2. Apply your desired filters (location, price range, bedrooms, property type)
3. Copy the filtered search URL from your browser
4. Paste it into the **Search URLs** input field
5. Run the actor

You can also paste direct listing URLs into the **Direct Listing URLs** field to scrape specific properties.

### Input options

| Field | Description | Default |
|---|---|---|
| **Search URLs** | Filtered search page URLs from Property Finder or Bayut | Required |
| **Direct Listing URLs** | Individual listing page URLs to scrape | Optional |
| **Max Listings** | Cap on total listings to scrape (0 = unlimited) | 100 |
| **Scrape Details** | Visit detail pages for RERA, description, amenities, agent phone | true |
| **Incremental Mode** | Skip listings already scraped in previous runs. Perfect for scheduled jobs — only new listings are scraped and charged. | false |
| **Proxy** | Proxy config — residential recommended for detail pages | Apify Residential |

### Output example

```json
{
    "source": "propertyfinder",
    "listingId": "1234567",
    "title": "Stunning 2BR | Marina View | High Floor",
    "type": "Apartment",
    "purpose": "for-sale",
    "price": 2850000,
    "currency": "AED",
    "pricePerSqFt": 1900,
    "bedrooms": 2,
    "bathrooms": 3,
    "areaSqFt": 1500,
    "areaSqM": 139.35,
    "location": "Marina Heights, Dubai Marina, Dubai",
    "community": "Dubai Marina",
    "building": "Marina Heights",
    "city": "Dubai",
    "latitude": 25.0768,
    "longitude": 55.1385,
    "description": "Fully furnished 2-bedroom apartment with panoramic marina views...",
    "amenities": ["Swimming Pool", "Gym", "Parking", "Security"],
    "portalListingId": "propertyfinder-1234567",
    "normalizedKey": "a1b2c3d4e5f6",
    "daysOnMarket": 23,
    "reraPermitNumber": "12345678",
    "reraPermitUrl": "https://www.dubailand.gov.ae/en/eservices/trakheesi/",
    "completionStatus": "ready",
    "furnishing": "Furnished",
    "listedDate": "2026-08-15",
    "agentName": "Dubai Premier Properties",
    "agentCompany": "Dubai Premier Properties LLC",
    "agentBRN": "54321",
    "agentPhone": "+971501234567",
    "imageUrls": ["https://..."],
    "listingUrl": "https://www.propertyfinder.ae/en/...",
    "scrapedAt": "2026-09-06T10:30:00.000Z"
}
```

### Dataset schema

| Field | Type | Description |
|---|---|---|
| `source` | string | Portal: `propertyfinder` or `bayut` |
| `listingId` | string | Portal-specific listing ID |
| `title` | string | Listing headline |
| `type` | string | Property type (Apartment, Villa, Townhouse, etc.) |
| `purpose` | string | `for-sale` or `for-rent` |
| `price` | number | Listed price in AED |
| `currency` | string | Always `AED` |
| `pricePerSqFt` | number | Computed price per square foot |
| `bedrooms` | integer | Number of bedrooms (0 = studio) |
| `bathrooms` | integer | Number of bathrooms |
| `areaSqFt` | number | Property area in square feet |
| `areaSqM` | number | Property area in square meters (auto-converted) |
| `location` | string | Full location string |
| `community` | string | Community / development name |
| `building` | string | Building name |
| `city` | string | City (Dubai) |
| `latitude` | number | GPS latitude |
| `longitude` | number | GPS longitude |
| `description` | string | Full listing description (detail pages only) |
| `amenities` | array | List of amenities (detail pages only) |
| `portalListingId` | string | Source-prefixed ID for tracking (`propertyfinder-1234567`) |
| `normalizedKey` | string | MD5 hash of community+beds+area+price for cross-portal dedup |
| `daysOnMarket` | integer | Days since listing was published |
| `reraPermitNumber` | string | RERA / Trakheesi permit number |
| `reraPermitUrl` | string | Link to Trakheesi portal for verification |
| `completionStatus` | string | `ready`, `off-plan`, or `under-construction` |
| `furnishing` | string | Furnished, Unfurnished, or Partly Furnished |
| `listedDate` | string | Date the listing was published |
| `agentName` | string | Listing agent or agency display name |
| `agentCompany` | string | Real estate agency name |
| `agentBRN` | string | Broker Registration Number |
| `agentPhone` | string | Agent's publicly displayed phone number |
| `imageUrls` | array | Up to 10 property photo URLs |
| `listingUrl` | string | Direct link to the listing page |
| `scrapedAt` | string | ISO timestamp of when the data was collected |

### Pricing

This actor uses **pay-per-event** pricing with two event tiers:

| Event | When charged | Price per 1,000 |
|---|---|---|
| **search-result** | Listing scraped from search page only (no detail visit) | $3.00 |
| **detail-result** | Listing enriched with detail page data (RERA, amenities, description, agent phone) | $5.00 |

Platform usage is included — no additional compute or proxy costs on top.

#### Cost examples

| Scenario | Listings | Event type | Cost |
|---|---|---|---|
| Quick scan of 500 listings, details off | 500 | search-result | **$1.50** |
| Full scrape of 1,000 listings with details | 1,000 | detail-result | **$5.00** |
| Daily incremental run, ~50 new listings/day | 50 | detail-result | **$0.25/day** |
| Cross-portal comparison, 2,000 from PF + 2,000 from Bayut | 4,000 | detail-result | **$20.00** |

### Use cases

- **Real estate agencies** — monitor competitor listings and pricing across portals
- **Property investors** — track prices, identify below-market opportunities, spot days-on-market outliers
- **Market researchers** — build datasets for Dubai property market analysis
- **PropTech companies** — feed listing data into apps, dashboards, or AI models
- **Compliance teams** — verify RERA permit numbers across published listings using the included Trakheesi URL
- **Cross-portal analysis** — use `normalizedKey` to match the same property listed on both PF and Bayut

### Tips

- Start with a small `maxListings` (10–50) to verify the output matches your needs
- Use **residential proxies** for detail page scraping — both portals use WAF protection
- For large scrapes (1,000+ listings), increase the max and let the actor paginate automatically
- Combine Property Finder and Bayut search URLs in a single run to cross-reference listings
- Enable **Incremental Mode** for scheduled runs — only new listings are scraped and charged
- Set **Scrape Details** to `false` for a faster, cheaper scan when you only need price/location/beds

### Known limitations

- **RERA permit numbers** are only available on detail pages; search-only mode won't capture them
- **Agent phone numbers** are extracted when publicly displayed on the portal — not all listings show one
- **Bayut amenities** require a detail page visit; search results don't include them
- **Days on market** depends on the portal providing a listed date — some listings don't publish one
- **Incremental mode** persists across runs using Apify's key-value store; clearing the store resets the seen-listings history
- Both portals use WAF protection — residential proxies are strongly recommended for detail page scraping

### Changelog

#### v0.2 (2026-09-07)

- **Renamed** to "Property Finder & Bayut Listings Scraper" (better discoverability)
- **Added** `areaSqM` — automatic sqft-to-sqm conversion
- **Added** `agentPhone` — publicly displayed agent phone numbers
- **Added** `daysOnMarket` — computed from listed date
- **Added** `portalListingId` and `normalizedKey` — cross-portal tracking and deduplication
- **Added** `reraPermitUrl` — direct link to Trakheesi verification portal
- **Added** Incremental mode — skip already-seen listings across scheduled runs
- **Added** Split PPE pricing — cheaper rate for search-only scrapes vs. detail-enriched results

#### v0.1 (2026-09-04)

- Initial release with Property Finder and Bayut support
- Search + detail page scraping
- RERA permit extraction, agent/agency info, GPS coordinates
- Pay-per-result pricing

### Legal

This actor scrapes publicly available listing data from real estate portals. It does not access restricted APIs, bypass authentication, or extract personal data beyond what is publicly displayed on each listing page. Agent phone numbers are collected only when shown publicly on the portal. Use responsibly and in accordance with the portals' terms of service.

# Actor input Schema

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

Filtered search page URLs from propertyfinder.ae or bayut.com. Apply your filters on the website first, then paste the resulting URL here.

## `listingUrls` (type: `array`):

Direct URLs to individual property listing pages. Use this if you already have specific listing URLs to enrich.

## `maxListings` (type: `integer`):

Maximum number of listings to scrape. Set to 0 for unlimited.

## `scrapeDetails` (type: `boolean`):

When enabled, the actor visits each listing's detail page to extract RERA permit number, full description, amenities, and agent phone. Slower but richer data (charged at detail-result rate). When disabled, only search-page data is collected (faster, cheaper, charged at search-result rate).

## `enableIncremental` (type: `boolean`):

When enabled, the actor remembers listing IDs from previous runs and skips them. Perfect for scheduled runs — only new listings are scraped and charged. Uses the actor's key-value store to persist state across runs.

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

Proxy settings. Residential proxies recommended for detail pages to avoid WAF blocks.

## Actor input object example

```json
{
  "searchUrls": [
    {
      "url": "https://www.propertyfinder.ae/en/search?c=2&l=1&ob=mr&page=1"
    }
  ],
  "listingUrls": [],
  "maxListings": 100,
  "scrapeDetails": true,
  "enableIncremental": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Dataset containing scraped property data with prices, locations, RERA permits, and agent info

# 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": [
        {
            "url": "https://www.propertyfinder.ae/en/search?c=2&l=1&ob=mr&page=1"
        }
    ],
    "listingUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("galdrcode_dev/dubai-property-data-enricher").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": [{ "url": "https://www.propertyfinder.ae/en/search?c=2&l=1&ob=mr&page=1" }],
    "listingUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("galdrcode_dev/dubai-property-data-enricher").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": [
    {
      "url": "https://www.propertyfinder.ae/en/search?c=2&l=1&ob=mr&page=1"
    }
  ],
  "listingUrls": []
}' |
apify call galdrcode_dev/dubai-property-data-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,galdrcode_dev/dubai-property-data-enricher"
        }
    }
}

```

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/nov4S16RC4ARbG5oU/builds/LN5GROdYjdCKgtdNa/openapi.json
