# Dubizzle.com Scraper - Property, Motors, Agents & UAE Listings (`abotapi/dubizzle-com-scraper`) Actor

From $1/1K. Scrape dubizzle.com across the UAE for property, motors, and agent listings. Search by filters or URLs with auto pagination. Returns price, beds, baths, area, agent/agency contacts, WhatsApp, email, GPS, photos, amenities, verification, and Dubai Land Department history.

- **URL**: https://apify.com/abotapi/dubizzle-com-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 18 total users, 3 monthly users, 96.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listing results

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/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

## Dubizzle Scraper: UAE Property, Motors and Agent Listings

Dubizzle Scraper turns dubizzle.com into structured data across the United Arab Emirates: property for sale, property for rent, used cars (motors) and the property agents directory. Get price, beds, baths, area, GPS coordinates, verification status, and full agent, agency and contact details on every card, plus an optional detail pass for the complete description, categorized amenities, photo gallery and Dubai Land Department transaction history. Search by city and filters, or paste any Dubizzle URL you already refined in a browser, then export to JSON, CSV or Excel, or pull results straight into your app through the API.

### Why This Scraper?

- **Four sections, one actor.** Property for sale, property for rent, motors and the agents directory, across all eight UAE city slugs the site serves.
- **Two ways in.** Search mode builds the URL from city, price, bedrooms, area, furnishing, completion status and sort, so you don't craft links by hand. URL mode takes any Dubizzle link you already refined in a browser.
- **Nothing dropped by default.** Every card already returns the full nested agent, agency and contact objects, plus geocoded coordinates, even without the detail pass.
- **Optional detail mode.** Adds the full description, categorized amenities, agent email, permit numbers, the full photo gallery and, for Dubai property, Dubai Land Department transaction history. Billed when you turn it on, or when you paste a single listing URL in URL mode, which always returns the full detail record.
- **One predictable cap.** Max listings, not a page limit, decides run size and cost.
- **Resumable and checkpointed runs.** Point Resume at a previous run to collect only what it doesn't already have, and a run that gets restarted by the platform continues on its own instead of starting over.
- **Incremental mode for recurring monitoring.** Schedule the same search and get back only what actually changed, with the state tracked for you between runs.

### Use Cases

- **Property portals and PropTech tools:** mirror live for-sale and for-rent inventory with agent contact details already attached.
- **Market and pricing research:** track price, area and bedroom mix across UAE cities and neighborhoods over time.
- **Used-car aggregation:** pull motors listings for price comparison and inventory tracking.
- **Agency and lead-generation tools:** build a directory of agents and agencies with phone, WhatsApp and verification status.
- **Change monitoring:** schedule a recurring run and get notified only when new listings appear or a tracked listing's price or details change.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live listing. Every record also carries `scrapedAt` (when the row was fetched) and `detailMissing` (true only when detail mode was on and this one listing's detail fetch didn't land this run); both are bookkeeping fields, not listing content, so they aren't shown below.

| Field | Example |
| --- | --- |
| `id` | `"12345678"` |
| `url` | `"https://dubai.dubizzle.com/property-for-sale/residential/apartment/2026/1/1/sample-0/"` |
| `title` | `"Sample Listing Title"` |
| `price` / `currency` | `1500000` / `"AED"` |
| `section` | `"property-for-sale"` |
| `categorySlug` | `"apartment"` |
| `bedrooms` / `bathrooms` | `2` / `2` |
| `area` / `areaUnit` | `1200` / `"sqft"` |
| `city` / `neighborhood` | `"Dubai"` / `"Sample Community"` |
| `latitude` / `longitude` | `25.0000` / `55.0000` |
| `isVerified` | `true` |
| `agentName` | `"Agent Name"` |
| `agencyName` | `"Sample Agency"` |
| `phoneNumber` / `whatsapp` | `"+971500000000"` / `"+971500000000"` |
| `addedOn` | `1700000000` |
| `furnished` / `completionStatus` | `true` / `"completed"` |
| `propertyReference` | `"REF-0001"` |
| `hasDldHistory` / `photosCount` | `true` / `12` |
| `raw` | `{ complete upstream listing object }` |
| `description` | full text, detail mode only |
| `amenities` | categorized facility list, detail mode only |
| `email` | agent email, detail mode only |
| `dldHistory` | Dubai Land Department transactions, detail mode only, Dubai property only |
| `changeType` / `changedFields` | `"NEW"` / `["price"]`, incremental mode only |
| `firstSeenAt` / `lastSeenAt` | ISO timestamps, incremental mode only |

Motors (used cars) and property agents directory results come through this same record shape. A motors record carries the same fields, with the property-only ones (`bedrooms`, `bathrooms`, `area`, `completionStatus`) empty; vehicle detail like make, model, mileage and year lives inside `raw` rather than a dedicated top-level field. A property agents record represents the agent's own profile card: `agentName` is the agent's own display name, `phoneNumber` and `whatsapp` are the agent's own numbers, and the property-specific fields are empty.

### How to Use

1. Pick a **mode**: `search` (city and filters) or `url` (paste links).
2. For search mode, choose the city or cities, the section (property for sale, property for rent, motors, or agents) and any filters. For URL mode, paste one or more Dubizzle links.
3. Turn on **Include listing details** if you need the full description, amenities, email and photo gallery, and set **Max listings** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search mode, basic:**

```json
{
  "mode": "search",
  "locations": ["dubai"],
  "section": "property-for-sale",
  "propertyType": "residential",
  "maxListings": 20
}
```

**Search mode with filters and sort:**

```json
{
  "mode": "search",
  "locations": ["dubai", "abu-dhabi"],
  "section": "property-for-rent",
  "propertyType": "apartment",
  "minPrice": 50000,
  "maxPrice": 150000,
  "minBedrooms": 1,
  "maxBedrooms": 2,
  "furnishing": "furnished",
  "sortBy": "newest",
  "maxListings": 50
}
```

**Motors (used cars):**

```json
{
  "mode": "search",
  "locations": ["dubai"],
  "section": "motors",
  "maxListings": 30
}
```

**URL mode, multiple links, with detail mode on:**

```json
{
  "mode": "url",
  "urls": [
    "https://dubai.dubizzle.com/en/property-for-sale/residential/",
    "https://uae.dubizzle.com/en/property-agents/"
  ],
  "fetchDetails": true,
  "maxListings": 100
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/dubizzle-com-scraper").call(run_input={
    "mode": "search",
    "locations": ["dubai"],
    "section": "property-for-sale",
    "maxListings": 20,
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(listing["title"], listing["price"], listing["currency"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/dubizzle-com-scraper').call({
  mode: 'search',
  locations: ['dubai'],
  section: 'property-for-sale',
  maxListings: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Detail mode and the listings cap

Max listings is the one cap that decides run size; Max pages is an optional extra bound on top of it, not a substitute for it, and can be left at `0` so each search walks as deep as the source allows on its own. Detail mode (`fetchDetails`) adds one extra fetch per listing and is billed as a per-item surcharge only for listings that actually reach the dataset, never for one an incremental run decides to suppress. A single listing URL pasted in URL mode is always fetched as a full detail record and always carries this surcharge, even with detail mode off. Include Dubai Land Department history only takes effect when detail mode is on and the listing is a Dubai property; it's ignored everywhere else.

#### Resume and incremental mode (recurring updates)

**Resume** (`resumeFromRunId`) continues one specific interrupted run: paste its run or dataset id and this run skips every listing already collected there, so a follow-up run plus the original together give you the full set without double charges. The actor also checkpoints its own progress automatically within a run, so a platform restart or a retry of a failed run picks up where it stopped instead of re-collecting anything.

**Incremental mode** (`incrementalMode`) is for a different job: scheduling the same search repeatedly and getting back only what changed. The actor remembers the previous run itself, keyed on your filters (or a State key you set, unaffected by Max pages/Max listings), and classifies every listing as `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (skipped and not billed unless Emit unchanged is on), or `EXPIRED` (only after a run that reached the natural end of every search or URL, with no cap hit and no Resume, and only with Emit expired on). `REAPPEARED` is not something a normal scheduled run produces by itself: it only appears for a listing that an earlier complete run already marked `EXPIRED`, and that later shows up again. Combining Incremental mode with Resume fails fast if that search already has saved incremental state; combining them the first time, before any state exists, is fine and bootstraps a new monitoring baseline from the resumed dataset.

**What Incremental mode compares.** Every listing field takes part in the comparison, including price, title, bedrooms, area, agent and agency details and, with detail mode on, description, amenities, photos and permit. Left out of the comparison but kept in the output: the scrape timestamp, the detail-fetch status flag, the raw detail payload, the Dubai Land Department history (so a new transaction alone does not mark a listing `UPDATED`), and the promotion flags `promoted`, `featuredListing` and `highlightedAd` together with the same three flags inside the raw card (`raw.promoted`, `raw.featured_listing`, `raw.highlighted_ad`), which flip with paid promotion rather than with the listing itself. Use **Ignore fields when detecting changes (incremental mode only)** (`ignoreFieldsForChanges`) to leave out more: a top-level name such as `price`, or a dotted path such as `raw.some_field` for a nested value. Ignored fields stay in every row and never appear in `changedFields`. Changing the ignore list does not mark tracked listings `UPDATED` by itself. A run that starts from a pasted URL at `?page=2` or later, or that is capped, never produces `EXPIRED` rows, because it did not see the whole search.

#### URL shapes

| Shape | Example | Notes |
| --- | --- | --- |
| City property search | `https://dubai.dubizzle.com/en/property-for-sale/residential/` | Walks pages from 1. Live-verified; part of the default |
| Paginated | `https://dubai.dubizzle.com/en/property-for-sale/residential/?page=2` | Starts from the given page; same confirmed path as above, with the page parameter the search mode walks |
| Rent sub-category | `https://dubai.dubizzle.com/en/property-for-rent/residential/apartmentflat/` | Any property sub-category path. Not live-verified in URL mode |
| Motors listing | `https://dubai.dubizzle.com/motors/used-cars/` | No `/en/` prefix. Not live-verified in URL mode |
| Agents directory | `https://uae.dubizzle.com/en/property-agents/` | Not live-verified in URL mode; the Agents section of search mode is the supported route |
| Single listing permalink | a listing page link | Returned as a full detail record |

A link with the Arabic `/ar/` prefix, a non-Dubizzle link, or a page that is not a property, motors or agents page logs a clear warning for that URL instead of failing silently. In search mode, Locations accepts typed city names such as `Abu Dhabi` or `Ras Al Khaimah`; a name that matches no city stops the run with an error.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
2. Select it in the "Pipe results into your apps" input field. If the picker is empty, you haven't authorized a connector yet.
3. For Notion, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` builds the URL from filters; `url` scrapes pasted URLs. |
| `locations` | array | none (prefill: `["dubai"]`) | City slugs: dubai, abu-dhabi, sharjah, ras-al-khaimah, ajman, fujairah, umm-al-quwain, al-ain. Search mode. If left empty, the actor still searches Dubai, a code fallback rather than a schema default. |
| `section` | string | `property-for-sale` | `property-for-sale`, `property-for-rent`, `motors`, or `property-agents`. Search mode. |
| `propertyType` | string | `residential` | Property sub-type for the property sections. Search mode. |
| `minPrice` | integer | none | Minimum price in AED. Search mode. |
| `maxPrice` | integer | none | Maximum price in AED. Search mode. |
| `minBedrooms` | integer | none | Minimum bedrooms. Property sections. |
| `maxBedrooms` | integer | none | Maximum bedrooms. Property sections. |
| `minArea` | integer | none | Minimum built-up area in sqft. Property sections. |
| `maxArea` | integer | none | Maximum built-up area in sqft. Property sections. |
| `furnishing` | string | `any` | `any`, `furnished`, `unfurnished`. Property sections. |
| `completionStatus` | string | `any` | `any`, `completed`, `off-plan`. Property sections. |
| `sortBy` | string | `popular` | `popular`, `newest`, `oldest`, `price-asc`, `price-desc`, `verified`. Search mode. |
| `urls` | array | the two default example URLs (see URL shapes) | Full Dubizzle URLs. URL mode. Filter fields are ignored here. Leaving the field untouched in URL mode now scrapes the two default examples instead of nothing; send an empty list to scrape nothing. |
| `maxPages` | integer | `0` | Optional bound on pages per search or URL. `0` = walk as deep as the source serves, stopping on its own at the storefront's reported total or a repeated page. Does not cap listings; use Max listings for that. |
| `maxListings` | integer | `20` | The single result cap. `0` = unlimited, bounded by Max pages or the storefront total. |
| `fetchDetails` | boolean | `false` | Include the full record for each listing (description, amenities, email, full photo gallery, permit numbers). Billed as a per-item surcharge. |
| `includeDldHistory` | boolean | `true` | With detail mode on, also pull Dubai Land Department history for Dubai property listings. Ignored otherwise. |
| `resumeFromRunId` | string | none | ID of a previous run (or dataset) of this actor. Listings already there are skipped, so this run returns only new ones. |
| `incrementalMode` | boolean | `false` | For a scheduled run against the same search. Classifies every listing as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED against remembered state. |
| `stateKey` | string | none | Names the monitoring campaign so it keeps its own baseline. Left empty, one is auto-derived from your search filters. Incremental mode only. |
| `emitUnchanged` | boolean | `false` | Also return (and bill) UNCHANGED listings every run. Incremental mode only. |
| `emitExpired` | boolean | `false` | Also return (and bill) a one-time EXPIRED row for a tracked listing that disappeared, only after a run that reached the natural end of the search. Incremental mode only. |
| `ignoreFieldsForChanges` | array | `[]` | Field names or dotted paths to leave out of change detection. Ignored fields stay in the output. Incremental mode only. |
| `proxy` | object | none (prefill: Apify Residential, country AE) | Connection settings. If this field is omitted, the actor falls back to its own built-in backup connection instead of Apify Residential and logs a warning; see Plan Requirement below. |
| `mcpConnectors` | array | none | Optional: send a summary of each record to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | none | Notion connector only: page under which records are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. Does not affect the dataset. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live listing.

```json
{
  "id": "12345678",
  "url": "https://dubai.dubizzle.com/property-for-sale/residential/apartment/2026/1/1/sample-0/",
  "title": "Sample Listing Title",
  "price": 1500000,
  "currency": "AED",
  "section": "property-for-sale",
  "categorySlug": "apartment",
  "bedrooms": 2,
  "bathrooms": 2,
  "area": 1200,
  "areaUnit": "sqft",
  "city": "Dubai",
  "neighborhood": "Sample Community",
  "latitude": 25.0000,
  "longitude": 55.0000,
  "isVerified": true,
  "agentName": "Agent Name",
  "agencyName": "Sample Agency",
  "phoneNumber": "+971500000000",
  "whatsapp": "+971500000000",
  "addedOn": 1700000000,
  "furnished": true,
  "completionStatus": "completed",
  "propertyReference": "REF-0001",
  "hasDldHistory": true,
  "photosCount": 12,
  "isPremium": false,
  "recordType": "listing",
  "detailMissing": false,
  "scrapedAt": "2026-01-01T00:00:00Z",
  "raw": { "external_id": 12345678, "name": { "en": "Sample Listing Title" } }
}
```

### Plan Requirement

Dubizzle sits behind an interstitial ("Pardon Our Interruption") that is served with a normal HTTP 200 status, so a plain request on a datacenter connection does not get listings. Datacenter proxies are not enough: keep the prefilled Connection setting (Apify Residential proxy, country AE), which needs a paid Apify plan. The actor then clears the interstitial with its own browser step before reading pages.

If the Connection field is left unset, the actor falls back to its own built-in backup connection and can return few or no listings.

What you see when the connection is the problem:

- **Warning in the log:** "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable."
- **Info in the log:** "Served over the backup connection (the default connection was unavailable)." when the backup served the pages.
- **Run fails** (no page could be read) with one of: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required" (every connection refused), "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested Dubizzle pages", or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search." A run that could not read any page is marked failed, never a quiet empty success.

A single listing URL pasted in URL mode is always fetched as a full detail record and carries the detail surcharge, even with detail mode off.

#### Pricing

You pay per listing that reaches the dataset, a surcharge only for listings where detail mode actually fetched extra data, and a small per-run start event. Failed or suppressed rows are never billed. In Incremental mode UNCHANGED rows are skipped and not billed unless Emit unchanged is on, and EXPIRED rows are billed only when Emit expired is on. The Pricing tab shows the current rates.

#### Output views and extra fields

The dataset has three views: **Overview** (core card fields plus the incremental columns), **Detail** (description, amenities, photos, emails, permit, payment plan, Dubai Land Department history) and **Changes** (id, url, title, price and change columns for incremental runs). Multi-search runs also store an OUTPUT summary per search.

Cards now also carry additive fields lifted from the live card: `coordinates`, `tourUrl`, `videoUrl`, `tour360`, `building`, `neighborhoods`, `hasWhatsappNumber`, and the agency fields `agencySlug` and `agencyLogo`. The promotion flags `featuredListing`, `promoted` and `highlightedAd` are also in every row. Detail records add `contactEmail` and `contactWebsite`. Fields are `null` when the listing has no value for them. The promotion flags are left out of change detection (see What Incremental mode compares), and tracked listings are not re-marked `UPDATED` just because these fields now exist.

#### Default input change

In URL mode, leaving Urls untouched now scrapes the two default example URLs (see URL shapes) instead of nothing. Send an empty list to scrape nothing.

### FAQ

#### How much does it cost?

You pay per listing returned, plus a surcharge only for listings where detail mode actually fetched extra data. The Pricing tab shows current rates. Use Max listings to cap the cost of any run.

#### Is it legal to scrape Dubizzle?

This actor collects only publicly available listing data. You are responsible for how you use it: follow Dubizzle's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Contact details on a listing belong to the person or agency that posted it, so handle them accordingly.

#### Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab against the same search and turn on Incremental mode. Each run then returns only NEW and UPDATED listings, unchanged ones are skipped and not billed, and EXPIRED only appears once a full, uncapped, non-resumed run has confirmed a tracked listing is really gone.

#### What's the difference between Resume and Incremental mode?

Resume continues one specific interrupted run from a pasted run or dataset id, useful for a single very large one-off collection. Incremental mode is for a recurring, scheduled run against the same search: the actor remembers state itself between runs, no id to paste. They solve different problems and can be combined once, to bootstrap a new monitoring baseline from an existing dataset, but not once that baseline already exists.

#### Why did my run fail instead of returning an empty dataset?

A run stops with a clear error when no results page could be loaded (see Plan Requirement), when `resumeFromRunId` points to a run or dataset it cannot read, when Incremental mode is combined with Resume on a search that already has saved incremental state, or when a Locations entry in search mode matches no known city (a name that matches no city stops the run with an error instead of silently searching somewhere else). Everything else, an empty URLs list in URL mode, or a scheduled Incremental run where nothing changed since last time, finishes as a normal successful run that simply returns zero or few rows. An empty Locations input in search mode does not return zero rows; it falls back to searching Dubai.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each result into Notion, Linear or Airtable.

### 🔗 Want more car data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🚗 <a href="https://apify.com/abotapi/trademe-co-nz-scraper"><b>Trade Me NZ Scraper</b></a><br>Scrape trademe.co.nz across all five sections: Marketplace goods and auctions, Property...</td><td>🏷️ <a href="https://apify.com/abotapi/gumtree-uk-scraper"><b>Gumtree.com Scraper</b></a><br>Scrape Gumtree.com classifieds across motors, property, jobs, services, pets and goods...</td></tr>
<tr><td>🏷️ <a href="https://apify.com/abotapi/avito-ru-scraper"><b>Avito.ru Scraper</b></a><br>From $1/1K. Scrape structured listings from Avito.ru by region, category, filters, or...</td><td>🏷️ <a href="https://apify.com/abotapi/subito-it-scraper"><b>Subito.it Scraper</b></a><br>Scrape Subito.it listings across cars, real estate, marketplace, jobs, and more. Search...</td></tr>
<tr><td>🏷️ <a href="https://apify.com/abotapi/gumtree-au-scraper"><b>Gumtree AU Scraper</b></a><br>Scrape gumtree.com.au classifieds across every vertical: for-sale goods, motors, real...</td><td>🏷️ <a href="https://apify.com/abotapi/kleinanzeigen-de-scraper"><b>Kleinanzeigen.de Scraper</b></a><br>From $1/1K. Scrape Kleinanzeigen.de ads by keyword, category, location, price, seller...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/dubizzle-com-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Search mode = pick city + section + filters below and the scraper builds the URL for you. URL mode = paste any dubizzle.com listing URL(s) you already refined in a browser. URL mode supports multiple URLs.

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

One or more UAE cities, typed naturally ('Abu Dhabi', 'Ras Al Khaimah') or as URL slugs ('abu-dhabi', 'ras-al-khaimah'): Dubai, Abu Dhabi, Sharjah, Ajman, Ras Al Khaimah, Umm Al Quwain, Fujairah, Al Ain. An unknown name stops the run with a clear error. For sub-areas use the city slug; refine further with neighborhood in URL mode.

## `section` (type: `string`):

Which Dubizzle vertical to search. Property for sale / rent, used motors (cars), or property agents directory.

## `propertyType` (type: `string`):

Property sub-type. 'residential' includes everything residential. Applies only to the property sections.

## `minPrice` (type: `integer`):

Minimum price filter in AED. Leave empty for no minimum. Search mode only.

## `maxPrice` (type: `integer`):

Maximum price filter in AED. Leave empty for no maximum. Search mode only.

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

Minimum bedrooms (0 = studio). Property sections only.

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

Maximum bedrooms. Property sections only.

## `minArea` (type: `integer`):

Minimum built-up area in square feet. Property sections only.

## `maxArea` (type: `integer`):

Maximum built-up area in square feet. Property sections only.

## `furnishing` (type: `string`):

Furnishing filter. Property sections only.

## `completionStatus` (type: `string`):

Completed = ready to move in. Off-plan = under construction / pre-launch. Property sections only.

## `sortBy` (type: `string`):

How to order results. Search mode only - in URL mode the sort is taken from your pasted URL.

## `urls` (type: `array`):

One or more full dubizzle.com URLs (property, motors, or agents). Multi-URL supported. Filter-mode fields (city, section, price, beds, etc.) are ignored in URL mode - paste the URL exactly as Dubizzle produced it, including any filters. A URL ending with `?page=N` starts from that page.

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

Optional bound on result pages walked per location / URL. Dubizzle returns ~35 listings per page. Default 0 = walk as deep as the source serves: the run stops on its own once the storefront's reported total is reached or a page returns no new listings. This does NOT cap the number of listings; use Max listings for that.

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

The single cap on this run. Default 20 keeps first runs cheap and fast. Set 0 for unlimited (then the run stops at the storefront total / Max pages).

## `fetchDetails` (type: `boolean`):

Adds the full description, categorized amenities, agent email + agency license, the full photo gallery (vs SERP cover photo only), RERA/Trakheesi permit, off-plan payment plans, and (for Dubai property) the Dubai Land Department transaction history. Turn off for a faster, cheaper run with just the SERP fields (which already include lat/lng, agent phone, WhatsApp, and basic agency info). Each detail page is an extra fetch, so this run costs a per-item surcharge when enabled.

## `includeDldHistory` (type: `boolean`):

When detail mode is on, also pull the Dubai Land Department transaction history for Dubai property listings (past sale prices and dates for the building). Ignored when detail mode is off or for non-Dubai listings.

## `proxy` (type: `object`):

Apify residential proxy with country=AE is strongly recommended. Datacenter proxies and free-tier accounts often return empty pages; residential UAE IPs give the most reliable results. The scraper rotates the exit IP and refreshes its session automatically on rejection.

## `resumeFromRunId` (type: `string`):

Optional. ID of a previous run of this actor (or a dataset ID). Listings already in that dataset are skipped, so this run returns only NEW listings not seen before. Combine both runs' datasets for the full set. Max listings then counts only the new listings. The actor also checkpoints its own progress automatically, so a platform migration or a Resurrect of a FAILED/ABORTED run continues that same run without re-collecting or re-charging what it already pushed. For a recurring/scheduled monitoring campaign against the SAME search instead, use Incremental mode below - the two are complementary, not interchangeable, and combining them on a search with no prior incremental state bootstraps that state from this resumed dataset.

## `incrementalMode` (type: `boolean`):

For a scheduled/recurring run against the SAME search. When on, the actor remembers the previous run's listings itself (keyed on your filters, see State key) and classifies every listing as NEW, UPDATED, REAPPEARED, or UNCHANGED - UNCHANGED listings are skipped (not pushed, not charged) unless Emit unchanged is on. Compared: every listing field including price, title, bedrooms, area, agent and agency details, and (with details on) description, amenities, photos and permit. Excluded from the comparison but kept in the output: the scrape timestamp, the detail-fetch status flag, the raw detail payload, the Dubai Land Department history, the promotion flags (promoted, featuredListing, highlightedAd, and the same three flags inside raw: raw.promoted, raw.featured_listing, raw.highlighted_ad), plus anything you list in Ignore fields. This is different from Resume above, which continues one specific interrupted run from a pasted run/dataset ID rather than remembering state itself.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign so it keeps its own baseline regardless of which caps you happen to pass. Leave empty to auto-derive one from your search filters (city, section, price, bedrooms, etc. - Max pages/Max listings never affect it, so raising or lowering those does not fork a new baseline or re-bill your whole search). Only relevant when Incremental mode is on.

## `emitUnchanged` (type: `boolean`):

When off (default), a listing identical to the last incremental run is skipped entirely - not pushed, not charged. Turn on to also emit UNCHANGED rows in the dataset (still marked changeType: UNCHANGED). This returns and bills every listing every run, defeating the point of incremental mode for most users - leave off unless you specifically need the full set every time. Only relevant when Incremental mode is on.

## `emitExpired` (type: `boolean`):

When on, a listing tracked by a previous incremental run that no longer appears is emitted once as changeType: EXPIRED (this returns and bills one extra row per delisted listing). Only fires after a run that reached the natural end of every search/URL with no cap hit and no Resume - a capped or resumed run cannot tell "delisted" apart from "not reached yet", so it is skipped that run and retried next time. Only relevant when Incremental mode is on.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names to leave out of change detection, in addition to the built-in handling (the scrape timestamp, the detail-fetch status flag, the raw detail payload, the Dubai Land Department history, the promotion flags promoted / featuredListing / highlightedAd and raw.promoted / raw.featured_listing / raw.highlighted_ad never trigger UPDATED). Use a top-level name such as price, or a dotted path such as raw.some_field for a nested value. Ignored fields stay in the output. Only used when Incremental mode is on.

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

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON - the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "locations": [
    "dubai"
  ],
  "section": "property-for-sale",
  "propertyType": "residential",
  "furnishing": "any",
  "completionStatus": "any",
  "sortBy": "popular",
  "urls": [
    "https://dubai.dubizzle.com/en/property-for-sale/residential/",
    "https://dubai.dubizzle.com/en/property-for-sale/residential/?page=2"
  ],
  "maxPages": 0,
  "maxListings": 20,
  "fetchDetails": false,
  "includeDldHistory": true,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AE"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `changes` (type: `string`):

No description

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

No description

# 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 = {
    "mode": "search",
    "locations": [
        "dubai"
    ],
    "urls": [
        "https://dubai.dubizzle.com/en/property-for-sale/residential/",
        "https://dubai.dubizzle.com/en/property-for-sale/residential/?page=2"
    ],
    "maxPages": 0,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AE"
    },
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/dubizzle-com-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 = {
    "mode": "search",
    "locations": ["dubai"],
    "urls": [
        "https://dubai.dubizzle.com/en/property-for-sale/residential/",
        "https://dubai.dubizzle.com/en/property-for-sale/residential/?page=2",
    ],
    "maxPages": 0,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AE",
    },
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/dubizzle-com-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 '{
  "mode": "search",
  "locations": [
    "dubai"
  ],
  "urls": [
    "https://dubai.dubizzle.com/en/property-for-sale/residential/",
    "https://dubai.dubizzle.com/en/property-for-sale/residential/?page=2"
  ],
  "maxPages": 0,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AE"
  },
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/dubizzle-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/dubizzle-com-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/1PiyqbXmQ5emYCCyI/builds/hMq6ZlFa9t1REcCen/openapi.json
