# Mourjan Scraper | MENA Properties, Cars & Jobs (`haketa/mourjan-scraper`) Actor

Mourjan scraper & API (MENA classifieds): search listings by keyword and category and export title, price, description, city, seller, contact, photos, date and URL. Middle East marketplace data and seller lead generation — fast, no login.

- **URL**: https://apify.com/haketa/mourjan-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Real estate, Automation, Jobs
- **Features:** Limited permissions
- **Stats:** 11 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 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

## Mourjan Scraper — MENA Classifieds Data Extractor for Properties, Cars, Jobs & Services

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-00C853?style=flat-square\&logo=apify)](https://apify.com/haketa/mourjan-scraper)
[![8 MENA Countries](https://img.shields.io/badge/🌍-8_MENA_Markets_\(UAE_·_KSA_·_KW_·_EG\)-purple?style=flat-square)]()
[![Properties, Cars & Jobs](https://img.shields.io/badge/🏠-Properties_·_Cars_·_Jobs_·_Services-1f6feb?style=flat-square)]()
[![1,000+ Deep Pagination](https://img.shields.io/badge/🔁-1,000%2B_Listings_Pagination-orange?style=flat-square)]()
[![No Login](https://img.shields.io/badge/🔓-No_Login_Required-2da44e?style=flat-square)]()
[![Export](https://img.shields.io/badge/⬇️-JSON_·_CSV_·_Excel_·_API-24292f?style=flat-square)]()

**Extract structured classified listings from [Mourjan.com](https://www.mourjan.com) — one of the Middle East & North Africa's largest pan-Arab classifieds marketplaces — with no login and no coding.** This **Mourjan scraper** collects **properties for rent, properties for sale, used cars & vehicles, job postings, and local services** across **8 MENA countries (UAE, Saudi Arabia, Kuwait, Bahrain, Jordan, Lebanon, Egypt, and Iraq)** and returns normalized JSON records with **listing ID, title, category, property type, country, city, price, currency, payment terms, bedrooms, bathrooms, area, furnished flag, full description, images, listing URL, and optional seller phone & contact details.**

Bulk export your **Mourjan classifieds dataset** to **JSON, CSV, Excel (XLSX), HTML, XML, RSS, or via the Apify API**.

> 🏢 **Built for** MENA proptech analysts, real-estate brokerages, GCC used-car dealers and exporters, regional recruitment agencies, relocation consultants, B2B lead-generation teams, and macroeconomic researchers tracking Middle East housing, automotive, and labor markets.

***

### ⚡ At a glance

| Feature | Details |
| :--- | :--- |
| 🎯 **Target marketplace** | [Mourjan.com](https://www.mourjan.com) — English & Arabic classifieds across the Arab world |
| 🌍 **8 MENA countries** | **UAE** (`ae`), **Saudi Arabia** (`sa`), **Kuwait** (`kw`), **Bahrain** (`bh`), **Jordan** (`jo`), **Lebanon** (`lb`), **Egypt** (`eg`), **Iraq** (`iq`) |
| 📂 **5 marketplace verticals** | `properties-rental`, `properties-sale`, `cars`, `jobs`, `services`, or `all` (multi-vertical sweep) |
| 📦 **Structured fields** | `listingId`, `title`, `listingType`, `category`, `propertyType`, `country`, `city`, `price`, `currency`, `paymentTerms`, `bedrooms`, `bathrooms`, `area`, `furnished`, `description`, `images`, `listingUrl`, `scrapedAt` + detail fields (`phone`, `sellerName`, `features`, `year`, `mileage`) |
| 🔁 **Pagination & 1,000+ scale** | Follows canonical next-page links across pages and automatically expands categories/countries when `maxRecords: 1000+` is requested (**0% duplicates**) |
| ⚡ **Speed & efficiency** | Pure HTTP extraction — collects **100 listings in ~15 seconds** and **1,000+ listings in ~2–3 minutes** |
| ⬇️ **Export formats** | **JSON, CSV, Excel, HTML, XML, RSS**, or direct consumption via **Apify REST API & Webhooks** |

***

### 🔎 Why scrape Mourjan classifieds?

[Mourjan.com](https://www.mourjan.com) is a foundational classifieds portal across the Gulf (GCC), Levant, and North Africa. Every day, landlords, real-estate brokers, private car sellers, employers, and service contractors publish thousands of listings in Dubai, Sharjah, Ajman, Abu Dhabi, Riyadh, Jeddah, Kuwait City, Manama, Amman, Beirut, Cairo, and Baghdad. Particularly in high-growth residential hubs like **Ajman, Sharjah, Al Ain, Kuwait, and secondary Saudi cities**, Mourjan carries deep inventory that often never appears on luxury-only portals.

However, Mourjan provides **no public API** and embeds critical attributes—like price (`AED 29,000`), payment cadence (`6 installments`), bedroom/bathroom counts (`2 BHK`, `1 - Bedroom`), and surface area (`1,200 sq ft`)—inside unstructured text blocks across eight separate country sub-trees.

This **Mourjan data extractor** turns that raw HTML into clean, database-ready intelligence:

- 🏠 **MENA real-estate price & yield monitoring** — track annual and monthly rental rates across UAE emirates and GCC cities by `propertyType` (`Apartment`, `Studio`, `Villa`, `Furnished Apartment`, `Office`, `Shop`, `Warehouse`, `Labor Camp`) and `bedrooms`.
- 📞 **Real-estate & automotive seller lead generation** — enable `scrapeDetails: true` to extract direct seller phone numbers (`phone`), poster names (`sellerName`), and full photo galleries for broker outreach.
- 🚗 **GCC used-car price benchmarking** — monitor private-party and dealer vehicle listings across the UAE, Saudi Arabia, and Kuwait.
- 💼 **Regional labor & hiring intelligence** — scrape the `jobs` and `services` verticals to analyze blue-collar and white-collar hiring demand across 8 Arab economies.
- 📊 **Proptech AVM & cost-of-living datasets** — schedule recurring runs to build historical time-series datasets keyed on `listingId`.

***

### ✨ What this Mourjan scraper does

- ✅ **Multi-country & multi-vertical targeting** — select one or more countries (`ae`, `sa`, `kw`, `bh`, `jo`, `lb`, `eg`, `iq`), pick a specific vertical or `all`, and optionally narrow down to specific city slugs (`dubai`, `sharjah`, `ajman`, `abu-dhabi`, `riyadh`, `jeddah`, `kuwait`, `manama`).
- ✅ **Smart attribute extraction from card text & URL slugs** — automatically parses numeric `price`, maps the country's ISO `currency` (`AED`, `SAR`, `KWD`, `BHD`, `JOD`, `USD`, `EGP`, `IQD`), extracts `bedrooms`, `bathrooms`, `area`, `furnished` status, and `paymentTerms`, and infers `city` and `propertyType` directly from the listing URL structure.
- ✅ **Unlocked 1,000+ deep pagination (`maxPages: 0`, `maxRecords: 0`)** — walks listing pages automatically (~20 listings per page) and, when a high target (`1,000+` or `0` unlimited) is requested, seamlessly expands across categories and countries if a narrow filter runs out of pages.
- ✅ **Optional detail-page enrichment (`scrapeDetails: true`)** — visits individual listing URLs to extract `phone`, `sellerName`, `features` (amenity bullets), complete `images` galleries, and car `year` / `mileage`.
- ✅ **100% deduplicated output** — every record is keyed by a composite `listingId` (`{country}-{numericId}`, e.g. `ae-30558790`) so cross-page and cross-category overlaps never produce duplicate rows.

***

### 🎯 Use cases & MENA market workflows

| Sector / Team | How They Use Mourjan Data |
| :--- | :--- |
| 🏘️ **Real-Estate Brokerages & Portals (UAE / KSA / KW)** | Scrape daily `properties-rental` and `properties-sale` feeds across Dubai, Sharjah, Ajman, and Abu Dhabi. Identify direct-from-owner listings (`scrapeDetails: true`) to acquire fresh agency mandates. |
| 📈 **Proptech & Automated Valuation Models (AVMs)** | Ingest thousands of property records weekly into Snowflake/BigQuery. Group by `city`, `propertyType`, and `bedrooms` to compute median annual rent per bedroom and payment-term distributions (`4 cheques`, `6 installments`, `monthly`). |
| 🚗 **Used-Car Dealers & Export Traders** | Monitor `cars` listings across `ae`, `sa`, `kw`, and `jo` to spot underpriced vehicles for domestic flipping or regional export. |
| 👷 **Corporate Relocation & Facility Managers** | Track `Labor Camp` (`labor-accommodation`), `Furnished Apartment`, and `Warehouse` supply and pricing across industrial zones in the UAE and Saudi Arabia. |
| 🤝 **Staffing & Recruitment Agencies** | Extract `jobs` and `services` postings across the Gulf and Levant to map employer demand and build B2B outreach lists. |

***

### 📥 Input configuration

All parameters are optional (`"required": []`). Click **Start** with the prefill to immediately collect 100 UAE property rental listings in ~15 seconds.

| Parameter | Type | Default / Prefill | Description |
| :--- | :--- | :--- | :--- |
| `countries` | `array<string>` | Prefill `["ae"]` | Countries to scrape: `ae` (UAE), `kw` (Kuwait), `bh` (Bahrain), `sa` (Saudi Arabia), `jo` (Jordan), `lb` (Lebanon), `eg` (Egypt), `iq` (Iraq). Leave empty to sample across all 8 countries. |
| `category` | `string` | `"properties-rental"` | Vertical to scrape: `properties-rental`, `properties-sale`, `cars`, `jobs`, `services`, or `all`. |
| `cities` | `array<string>` | `[]` | Optional city slugs as used in Mourjan URLs (e.g. `"dubai"`, `"sharjah"`, `"ajman"`, `"abu-dhabi"`, `"riyadh"`). Empty = all cities in the chosen countries. |
| `scrapeDetails` | `boolean` | `false` | When `true`, fetches each listing's detail page to add `phone`, `sellerName`, `features`, full `images`, and car `year`/`mileage`. Keep `false` for fast bulk runs. |
| `maxRecords` | `integer` | Default `0` (Prefill `100`) | Maximum listings to save (`0` = unlimited; supports `1,000+` bulk runs). Also accepts `maxItems` / `maxResults`. |
| `maxPages` | `integer` | `0` | Maximum pages to read per country/category task (`0` = auto/unlimited governed by `maxRecords`). |
| `requestDelay` | `integer` | `400` | Pause between page requests in milliseconds (`100`–`5000`). |
| `startUrls` | `array<string\|object>` | `[]` | Advanced: paste exact Mourjan category or search URLs to scrape directly. Overrides `countries` and `category`. |
| `proxyConfiguration` | `object` | `{ "useApifyProxy": true }` | Standard Apify Proxy configuration. Works out of the box. |

#### Example input — 1,000+ multi-country MENA classifieds sweep

```json
{
  "countries": ["ae", "sa", "kw"],
  "category": "all",
  "cities": [],
  "scrapeDetails": false,
  "maxRecords": 1000,
  "maxPages": 0,
  "requestDelay": 400,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

#### Example input — UAE rentals with seller phone & detail enrichment

```json
{
  "countries": ["ae"],
  "category": "properties-rental",
  "cities": ["dubai", "sharjah", "ajman"],
  "scrapeDetails": true,
  "maxRecords": 100,
  "requestDelay": 500,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

***

### 📤 Output schema & field reference

Every record shares a consistent, flat JSON schema across all 8 countries and 5 categories. Below is a real record from a UAE property rentals run:

```json
{
  "listingId": "ae-30558790",
  "title": "1 - Bedroom Apartment for Annual rent - Al Jerf 2, Ajman Very spacious layout - Separate living room - Master bedroom - 2 bathrooms",
  "listingType": "rental",
  "category": "Properties",
  "propertyType": "Apartment",
  "country": "UAE",
  "city": "Ajman",
  "district": null,
  "price": 29000,
  "currency": "AED",
  "paymentTerms": "6 installments",
  "bedrooms": 1,
  "bathrooms": 2,
  "area": null,
  "furnished": null,
  "features": null,
  "sellerType": null,
  "sellerName": null,
  "phone": null,
  "description": "1 - Bedroom Apartment for Annual rent - Al Jerf 2, Ajman Very spacious layout - Separate living room - Master bedroom - 2 bathrooms - Central air conditioning - Full maintenance covered by the landlord - Prime location near Delta Center and Al Rawda Bridge Annual rent AED 29000, 6 installments.",
  "images": [
    "https://doxplxe8wce37.cloudfront.net/repos/m/p1002/10021392/6a992b30ae8af.webp"
  ],
  "listingUrl": "https://www.mourjan.com/ae/ajman/apartments/rental/en/30558790/",
  "postedDate": null,
  "make": null,
  "model": null,
  "year": null,
  "mileage": null,
  "scrapedAt": "2026-11-09T20:15:00.000Z"
}
```

#### 🏷️ Core Identity, Category & Location Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `listingId` | `string` | 🟢 High (100%) | Composite unique key `{countryCode}-{numericId}` (e.g., `ae-30558790`). |
| `title` | `string` | 🟢 High (100%) | Clean listing headline extracted from the ad card (~150 chars). |
| `listingType` | `string \| null` | 🟢 High (Properties) | `"rental"` for rentals, `"for-sale"` for property sales, `null` for cars/jobs/services. |
| `category` | `string` | 🟢 High (100%) | Normalized vertical label: `"Properties"`, `"Cars"`, `"Jobs"`, or `"Services"`. |
| `propertyType` | `string \| null` | 🟢 High (~92% Properties) | Subtype inferred from URL slug: `Apartment`, `Studio`, `Villa`, `Furnished Apartment`, `Office`, `Shop`, `Land`, `Room`, `Labor Camp`, `Warehouse`, `Building`, `Floor`, `Traditional House`. |
| `country` | `string` | 🟢 High (100%) | Country name (`UAE`, `Saudi Arabia`, `Kuwait`, `Bahrain`, `Jordan`, `Lebanon`, `Egypt`, `Iraq`). |
| `city` | `string \| null` | 🟢 High (~98%) | City name parsed from the listing URL (`Dubai`, `Ajman`, `Sharjah`, `Abu Dhabi`, `Riyadh`, `Kuwait`, etc.). |
| `district` | `string \| null` | 🟡 Conditional | Sub-district or neighborhood when structured separately. |
| `listingUrl` | `string` | 🟢 High (100%) | Canonical URL of the listing on Mourjan.com. |
| `scrapedAt` | `string` | 🟢 High (100%) | ISO 8601 UTC timestamp of the run. |

#### 💰 Pricing & Property Specification Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `price` | `number \| null` | 🟡 Conditional (~55%) | Numeric price parsed from the ad text (`null` when the poster omits a price or writes "Call for price"). |
| `currency` | `string` | 🟢 High (100%) | Local ISO currency (`AED`, `SAR`, `KWD`, `BHD`, `JOD`, `USD`, `EGP`, `IQD`). |
| `paymentTerms` | `string \| null` | 🟡 Conditional (~50%) | Payment cadence (`monthly`, `per year`, `annually`, `4 cheques`, `6 installments`). |
| `bedrooms` | `integer \| null` | 🟡 Conditional | Number of bedrooms (`0` for studios, integer for `1 BR`, `2 BHK`, etc.). |
| `bathrooms` | `integer \| null` | 🟡 Conditional | Number of bathrooms when stated in the listing text. |
| `area` | `string \| null` | 🟡 Conditional | Surface area string when stated (e.g., `"1,200 sq ft"`, `"150 SQM"`). |
| `furnished` | `boolean \| null` | 🟡 Conditional | `true` for furnished, `false` for unfurnished, `null` when unspecified. |
| `description` | `string \| null` | 🟢 High (~93%) | Full text body of the classified ad. |
| `images` | `array<string>\|null` | 🟢 High (~80%) | Thumbnail URL in fast card mode; full image gallery when `scrapeDetails: true`. |

#### 📞 Detail Enrichment & Vehicle Fields (`scrapeDetails: true`)

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `phone` | `string \| null` | 🟡 Detail Mode | Direct contact phone number parsed from `tel:` links or page body. |
| `sellerName` / `sellerType` | `string \| null` | 🟡 Detail Mode | Poster / agency name and seller classification when displayed. |
| `features` | `array<string>\|null` | 🟡 Detail Mode | Array of property or vehicle feature bullets from the detail page. |
| `make` / `model` / `year` / `mileage` | `string` / `int` | 🟡 Cars Detail | Vehicle year (e.g., `2022`) and mileage (e.g., `"85,000 km"`) on car listings. |

***

### 🔁 Deep pagination & scaling to 1,000+ listings

Mourjan serves ~20 classified ads per page (`.../en/2/`, `.../en/3/`, etc.) and signals the next page via `<link rel="next">` in the HTML `<head>`:

1. **Unlimited page walking (`maxPages: 0`):** By default, the Actor walks page after page until it reaches your `maxRecords` target or Mourjan's last page.
2. **Automatic multi-category & multi-country expansion for 1,000+ runs:** If you request a large dataset (e.g., `maxRecords: 1000` or `0`) and your initial category/city filter finishes early, the scraper automatically continues across remaining categories and MENA countries so your run reliably collects **1,000+ unique listings**.
3. **Batch dataset flushing & deduplication:** Every page is deduplicated against a run-wide `seenIds` set (`listingId`) and pushed in clean page batches.

***

### ⚙️ How to use & integrate

1. **Open the Mourjan Scraper** in Apify Console.
2. **Select your target countries** (`ae`, `sa`, `kw`, etc.) and **Category** (`properties-rental`, `properties-sale`, `cars`, `jobs`, `services`, or `all`).
3. **Set `maxRecords`:** Leave at `100` for a fast 15-second run, or set `1000`+ (or `0` for unlimited) for a deep regional sweep.
4. **Click Start** and export your results in **JSON, CSV, Excel, XML, or RSS**, or pull them via the Apify API.

#### API example (Python)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("haketa/mourjan-scraper").call(run_input={
    "countries": ["ae"],
    "category": "properties-rental",
    "maxRecords": 500,
    "scrapeDetails": False,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"[{item['listingId']}] {item['city']} | {item['propertyType']} | {item['price']} {item['currency']}")
```

#### API example (Node.js)

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('haketa/mourjan-scraper').call({
    countries: ['ae', 'sa', 'kw'],
    category: 'cars',
    maxRecords: 1000,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Collected ${items.length} unique MENA car listings.`);
```

***

### 💡 Best practices & tips

- ⚡ **Keep `scrapeDetails: false` for fast market-wide scans:** Card-only mode captures `title`, `description`, `price`, `currency`, `paymentTerms`, `bedrooms`, `bathrooms`, `area`, `city`, `propertyType`, and thumbnail `images` at ~20 listings per HTTP request. Enable `scrapeDetails: true` only on smaller, targeted runs when you need `phone` numbers and full photo galleries.
- 🎯 **Target specific property subtypes via `startUrls`:** You can paste subtype URLs like `https://www.mourjan.com/ae/dubai/studios/rental/en/` or `https://www.mourjan.com/ae/ajman/villas-and-houses/rental/en/` into `startUrls` to scrape only studios or villas.

***

### ⚠️ Honest limitations

- **Unpriced classified ads:** Like most regional classifieds portals, roughly 40–45% of Mourjan posters omit a numeric price (expecting buyers to call or message). On those listings, `price` is `null` rather than a guessed number.
- **Hidden phone numbers:** Even with `scrapeDetails: true`, sellers who restrict their phone number to logged-in messaging or app-only reveal will have `phone: null`.

***

### ❓ Frequently asked questions (FAQ)

**Do I need a Mourjan account or login cookies?**
No. The Actor scrapes public English listing pages directly with zero authentication required.

**How many listings can I collect in one run?**
You can collect **1,000+ to 10,000+ listings** in a single run. Set `maxRecords: 1000` (or `0` for unlimited) and keep `maxPages: 0`.

**Why did my first test run stop at 100 listings?**
The Console prefill sets `maxRecords: 100` so your initial test finishes in ~15 seconds. Change `maxRecords` to `1000` or `0` to unlock full multi-page extraction.

**Do I need expensive residential proxies?**
No. Standard Apify Proxy (`useApifyProxy: true`) works reliably out of the box.

**How are duplicate listings prevented?**
Every listing URL contains a unique numeric ID, which the Actor combines with the country code into `listingId` (e.g., `ae-30558790`). The Actor tracks all seen IDs in memory and skips any repeated ads across pages.

***

### 🔌 Integrations & MENA data pipelines

Connect your **Mourjan classifieds data** directly to your real-estate, automotive, or analytics workflows:

- 📊 **Google Sheets & Airtable:** Automatically sync new UAE, Saudi, and Kuwait property or car listings into shared brokerage trackers on a daily schedule.
- ⚡ **Make, Zapier & n8n:** Trigger instant WhatsApp, Telegram, or Slack notifications whenever a new apartment, villa, or vehicle matching your target city and price threshold lands in the dataset.
- 🗄️ **Snowflake, BigQuery & PostgreSQL:** Load normalized JSON records keyed on `listingId` (`ae-...`, `sa-...`, `kw-...`) to track historical rental yields, time-on-market, and regional supply trends across all 8 MENA countries.
- 🤖 **AI Agents & MCP:** Connect this Actor to LLM research agents to answer real-time questions about MENA housing rents, used-car prices, and regional job postings.

***

### 📊 MENA rental yield & city benchmarking recipe (Python / Pandas)

Use this Python snippet to analyze median property prices by city, property type, and bedroom count from your exported Mourjan dataset:

```python
import pandas as pd

## Load exported Mourjan dataset
df = pd.read_json("mourjan_listings.json")

## 1. Filter to priced property rentals and compute median price by city & propertyType
priced = df[(df["category"] == "Properties") & (df["price"].notna()) & (df["price"] > 0)]

summary = (
    priced.groupby(["country", "city", "propertyType", "currency"])
    .agg(
        listings=("listingId", "count"),
        median_price=("price", "median"),
        mean_price=("price", "mean"),
    )
    .reset_index()
    .sort_values("listings", ascending=False)
)
print("MENA Property Price Summary by City & Type:")
print(summary.head(15))

## 2. Break down UAE apartment rentals by bedroom count
uae_apts = priced[(priced["country"] == "UAE") & (priced["propertyType"] == "Apartment")]
by_beds = (
    uae_apts.groupby(["city", "bedrooms"])["price"]
    .agg(["count", "median", "min", "max"])
    .reset_index()
    .sort_values(["city", "bedrooms"])
)
print(by_beds)
```

#### Equivalent SQL query (BigQuery / Postgres)

```sql
SELECT
    country,
    city,
    propertyType,
    bedrooms,
    currency,
    COUNT(*)                        AS listing_count,
    ROUND(AVG(price), 0)            AS avg_price,
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY price) AS median_price
FROM mourjan_classifieds
WHERE category = 'Properties'
  AND price IS NOT NULL
  AND price > 1000
GROUP BY country, city, propertyType, bedrooms, currency
ORDER BY listing_count DESC;
```

***

### 🔗 Related classifieds & real-estate scrapers

- [YallaMotor Scraper (GCC Cars)](https://apify.com/haketa/yallamotor-scraper)
- [Zameen.com Scraper (Pakistan Real Estate)](https://apify.com/haketa/zameen-scraper)
- [Lamudi Scraper (Emerging Markets Real Estate)](https://apify.com/haketa/lamudi-scraper)
- [Kleinanzeigen.de Scraper (Germany Classifieds)](https://apify.com/haketa/kleinanzeigen-scraper)
- [Marktplaats.nl Scraper (Netherlands Classifieds)](https://apify.com/haketa/marktplaats-scraper)
- [Kijiji.ca Scraper (Canada Classifieds)](https://apify.com/haketa/kijiji-scraper)

***

### 📋 Changelog

- **v1.2 (2026-11)** — Unlocked **1,000+ deep pagination** across categories and MENA countries (`maxRecords` default set to `0` with `100` prefill, added `maxItems`/`maxResults` aliases, automatic fallback task expansion for large targets, and per-task category tracking when `category: "all"`), upgraded proxy initialization to standard `Actor.createProxyConfiguration`, and reduced default `requestDelay` to `400ms` for 2× faster multi-page sweeps.
- **v1.1 (2026-10)** — Improved title trimming to preserve leading bedroom counts (`1 - Bedroom...`) and added canonical `<link rel="next">` pagination.
- **v1.0 (2026-09)** — Initial release covering 8 MENA countries and 5 classifieds categories.

***

▶️ **Ready to extract live MENA classifieds?** Pick your countries and category, click **Start**, and export structured Mourjan listings to JSON, CSV, or Excel!

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/mourjan-scraper/changelog.md

# Actor input Schema

## `countries` (type: `array`):

Choose one or more countries to collect listings from. Leave empty to include a mix from all covered countries.

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

Pick what kind of listings you want to collect.

## `cities` (type: `array`):

Narrow results to specific cities. Type a city name as it appears in Mourjan URLs, e.g. 'dubai', 'sharjah', 'ajman', 'abu-dhabi', 'kuwait'. Leave empty to include every city in the chosen countries.

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

Open each listing to also collect phone number, full description, all photos and extra features. Slower, but gives you much richer records and direct contact details.

## `maxRecords` (type: `integer`):

Maximum number of listings to return. Set 0 for unlimited. A value around 100 keeps sample runs fast and low-cost.

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

Limit how many listing pages are read for each country and category (0 = auto/unlimited governed by Max results).

## `requestDelay` (type: `integer`):

Pause between requests, in milliseconds. Higher values are gentler and more reliable; 300–1000ms works well.

## `startUrls` (type: `array`):

Power-user option: paste ready-made Mourjan listing or search URLs to scrape exactly those pages. When set, this overrides the country and category menus above. Most users can leave this empty.

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

Proxy settings used while collecting data. The recommended default works out of the box for most runs.

## Actor input object example

```json
{
  "countries": [
    "ae"
  ],
  "category": "properties-rental",
  "cities": [],
  "scrapeDetails": false,
  "maxRecords": 100,
  "maxPages": 0,
  "requestDelay": 400,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listingId` (type: `string`):

Composite listing identifier

## `title` (type: `string`):

Listing headline

## `listingType` (type: `string`):

Rental or for-sale classification

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

High-level marketplace category

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

Property subtype (Apartment, Villa, Studio, etc.)

## `country` (type: `string`):

Country name

## `city` (type: `string`):

City name

## `district` (type: `string`):

District or neighborhood

## `price` (type: `string`):

Numeric listing price

## `currency` (type: `string`):

ISO currency code

## `paymentTerms` (type: `string`):

Payment frequency or installments

## `bedrooms` (type: `string`):

Number of bedrooms

## `bathrooms` (type: `string`):

Number of bathrooms

## `area` (type: `string`):

Surface area of the property

## `furnished` (type: `string`):

Whether the property is furnished

## `phone` (type: `string`):

Contact phone number

## `sellerType` (type: `string`):

Owner, agent, or agency

## `sellerName` (type: `string`):

Seller or agency name

## `listingUrl` (type: `string`):

Canonical listing URL on Mourjan.com

## `postedDate` (type: `string`):

Date posted

## `scrapedAt` (type: `string`):

ISO UTC timestamp of extraction

# 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 = {
    "countries": [
        "ae"
    ],
    "category": "properties-rental",
    "cities": [],
    "scrapeDetails": false,
    "maxRecords": 100,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/mourjan-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 = {
    "countries": ["ae"],
    "category": "properties-rental",
    "cities": [],
    "scrapeDetails": False,
    "maxRecords": 100,
    "startUrls": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/mourjan-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 '{
  "countries": [
    "ae"
  ],
  "category": "properties-rental",
  "cities": [],
  "scrapeDetails": false,
  "maxRecords": 100,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call haketa/mourjan-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/mourjan-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/x8XmisDI6jOrnvpvO/builds/ZpIWgeR555JkOahmC/openapi.json
