# Immoweb.be Belgium Property Scraper (`haketa/immoweb-scraper`) Actor

Immoweb scraper & API for Belgian real estate: search property for sale and rent and export address, price, bedrooms, area, EPC energy, property type, agent, photos and coordinates. Belgium property market data and real-estate lead generation — fast, no login.

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

## Pricing

from $3.00 / 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

## Immoweb Scraper 🇧🇪 — Belgium Property Listings, Prices, EPC & Agency Data

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-00B5AD?style=for-the-badge\&logo=apify\&logoColor=white)](https://apify.com/haketa/immoweb-scraper)
[![Target](https://img.shields.io/badge/Target-Immoweb.be-0055A5?style=for-the-badge)](https://www.immoweb.be)
[![Market](https://img.shields.io/badge/Market-Belgium%20%F0%9F%87%A7%F0%9F%87%AA-ED2939?style=for-the-badge)]()
[![Languages](https://img.shields.io/badge/Languages-EN%20%7C%20FR%20%7C%20NL-F57C00?style=for-the-badge)]()
[![Export](https://img.shields.io/badge/Export-JSON%20%7C%20CSV%20%7C%20Excel%20%7C%20API-4A148C?style=for-the-badge)]()

**Turn [Immoweb.be](https://www.immoweb.be) — Belgium's #1 real estate marketplace with 200,000+ active listings — into a clean, structured property dataset.** This **Immoweb scraper** extracts **for-sale (`for-sale`) and for-rent (`for-rent`)** properties across **Brussels, Flanders (Vlaanderen), and Wallonia (Wallonie)**: **listing ID, property subtype, title, price in EUR, bedrooms, living area (m²), land surface, 4-digit Belgian postcode, city, auto-mapped province & region, GPS coordinates, high-resolution photo gallery URLs, agency name, and canonical listing URL** — plus optional deep-detail enrichment (**EPC / PEB energy score & kWh/m²/year, heating type, construction year, building condition, façade count, flood-zone flag, full description, agency phone/email/website, and days on market**). **No login, no coding.**

Export your Belgian real estate dataset directly to **JSON, CSV, Excel, XML, HTML, or via the Apify API** for property investment underwriting, buy-to-let yield modeling, automated valuation models (AVMs), energy-transition analysis, and B2B real estate agency lead generation.

***

### ⚡ At a glance

| Feature | Details |
|---|---|
| **Target platform** | [Immoweb.be](https://www.immoweb.be) — Belgium's largest real estate portal (200,000+ listings) |
| **Transaction types** | Properties **For Sale (`for-sale`)** and **For Rent (`for-rent`)** |
| **Property categories** | Houses & Apartments (`house-and-apartment`), Houses (`house`), Apartments (`apartment`), Land (`land`), Offices (`office`), Commercial (`commercial`), Garages (`garage`) |
| **Geographic coverage** | All 3 Belgian regions (**Brussels**, **Flanders**, **Wallonia**), all 10 provinces, 26 built-in city/province presets, custom location slugs, or **Start URLs** |
| **Language support** | English (`en`), French (`fr`), and Dutch (`nl`) |
| **Detail enrichment** | Fast search-index mode (`scrapeDetails: false`) + optional deep detail mode (`scrapeDetails: true`) for EPC, building specs & agency contacts |
| **Pagination & scale** | ~30 listings per page; unlocked multi-page pagination (`maxPages: 0` auto/unlimited) with 100% `listingId` de-duplication |
| **Output formats** | JSON, CSV, Excel (XLSX), HTML, XML, RSS, and Apify REST API |

***

### 📋 Table of contents

- [Why scrape Immoweb?](#-why-scrape-immoweb)
- [What this Immoweb scraper does](#-what-this-immoweb-scraper-does)
- [Use cases](#-use-cases)
- [Input configuration](#-input-configuration)
- [Output & field reference](#-output--field-reference)
- [Pagination & 1,000+ scale](#-pagination--1000-scale)
- [How to use](#-how-to-use)
- [Pro tips for Belgian real estate data](#-pro-tips-for-belgian-real-estate-data)
- [FAQ](#-faq)
- [Related scrapers](#-related-scrapers)
- [Changelog](#-changelog)

***

### 🔎 Why scrape Immoweb?

[Immoweb.be](https://www.immoweb.be) is the definitive source of truth for the Belgian housing and commercial property market. Every residential house, apartment, penthouse, studio, building plot, office, retail space, and garage listed by Belgian real estate agencies or private sellers appears on Immoweb first — spanning the **Brussels-Capital Region**, **Flanders** (Antwerp, East Flanders, West Flanders, Flemish Brabant, Limburg), and **Wallonia** (Liège, Namur, Hainaut, Walloon Brabant, Luxembourg).

However, Immoweb does not offer a public bulk export, and manual collection across trilingual URL paths and 4-digit postcodes does not scale. Furthermore, raw Immoweb listings only show a 4-digit postal code without normalized province or regional labels (`Brussels` vs. `Flanders` vs. `Wallonia`), making cross-regional analytics tedious.

This **Immoweb data extractor** automates the entire workflow: it paginates through search results, extracts rich property attributes directly from the search cards, normalizes every Belgian postcode to its exact province and region, optionally enriches each property with EPC energy ratings and agency contact details, and outputs a clean, de-duplicated dataset.

#### Key business outcomes

- 📈 **Build Belgian Automated Valuation Models (AVMs) & Comps** — track asking prices (`price`), living area (`livingArea`), land surface (`landSurface`), and €/m² across Belgian municipalities and postcodes.
- 🏘️ **Calculate buy-to-let rental yields** — run paired `for-sale` and `for-rent` jobs for the same city or postcode to benchmark gross rental yields across Brussels, Antwerp, Ghent, Leuven, and Liège.
- ⚡ **Analyze EPC / PEB energy-transition discounts** — enable `scrapeDetails: true` to correlate EPC scores (`A++` to `G`) and `epcValue` (kWh/m²/year) against asking prices ahead of Flanders' and Wallonia's mandatory renovation deadlines.
- 🎯 **Generate Belgian real estate agency B2B leads** — collect active real estate agencies (`agencyName`, `agencyPhone`, `agencyEmail`, `agencyWebsite`) along with their live portfolio volume.
- 🌍 **Power expat relocation & PropTech portals** — feed live English, French, or Dutch rental and sale listings near EU institutions, NATO HQ, or university hubs into custom dashboards and alert bots.

***

### ✨ What this Immoweb scraper does

- ✅ **No-code menu targeting or custom Start URLs** — pick `propertyType`, `transactionType`, `location` (Brussels, Antwerp, Ghent, Bruges, Leuven, Mechelen, Hasselt, Ostend, Liège, Namur, Charleroi, Mons, or any of the 10 provinces), price floor/ceiling, and minimum bedrooms — or paste any pre-filtered Immoweb search or classified URL into `startUrls`.
- ✅ **Rich fast-mode extraction (`scrapeDetails: false`)** — extracts **title, price (EUR), bedroom count, bathroom count, habitable living area (m²), land surface (m²), postcode, city, province, region, GPS latitude/longitude, up to 10 high-resolution CDN photos, and agency name** straight from the search pages at high speed (~30 properties per request).
- ✅ **Optional deep-detail enrichment (`scrapeDetails: true`)** — visits each individual classified page to add **EPC / PEB energy score (`epcScore`), energy consumption (`epcValue` in kWh/m²/year), `heatingType`, `buildYear`, `condition`, `facade` count, `floodZone` flag, full `description`, `agencyPhone`, `agencyEmail`, `agencyWebsite`, `viewCount`, `bookmarkCount`, and `daysOnMarket`**.
- ✅ **Automatic Belgian postcode → Region & Province mapping** — maps every 4-digit Belgian postal code (`1000`–`9999`) to its canonical English `region` (`Brussels`, `Flanders`, `Wallonia`) and `province` (`Antwerp`, `East Flanders`, `West Flanders`, `Flemish Brabant`, `Limburg`, `Liège`, `Namur`, `Hainaut`, `Walloon Brabant`, `Luxembourg`).
- ✅ **Trilingual output (`en` / `fr` / `nl`)** — select English, French, or Dutch for property titles, descriptions, and URLs while keeping all field keys standardized.
- ✅ **Unlocked 1,000+ pagination & de-duplication** — walks `?page=1, ?page=2, ?page=3…` automatically (`maxPages: 0` auto/unlimited) and de-duplicates every record by `listingId`.

***

### 🎯 Use cases

| Audience | How they use Immoweb data |
|---|---|
| **🏦 Property Investors & Private Equity** | Benchmark €/m² pricing, spot undervalued postcodes, and track inventory velocity across Brussels, Flanders, and Wallonia. |
| **🇪🇺 Expat Relocation & Corporate Housing** | Filter apartments and houses for rent (`for-rent`) in Brussels, Leuven, Antwerp, and Waterloo with exact bedroom counts, prices, and GPS coordinates. |
| **🌱 Energy & Sustainability Analysts** | Quantify the green premium / brown discount between EPC `A/B` properties and EPC `E/F/G` renovation targets across Belgian provinces. |
| **💼 PropTech & Mortgage Brokers** | Power consumer home-value estimators, price-drop trackers, and mortgage pre-qualification calculators with live Belgian property feeds. |
| **📇 B2B SaaS & Agency Lead Generation** | Extract `agencyName`, `agencyPhone`, `agencyEmail`, and `agencyWebsite` to pitch CRM, photography, staging, or marketing services to active Belgian realtors. |

***

### 📥 Input configuration

Configure your run via the Apify Console menus or pass a JSON object via the API. **Every parameter is optional** — clicking Start with default settings runs a fast nationwide Belgium sample.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `propertyType` | `string` | `"house-and-apartment"` | Property category: `"house-and-apartment"`, `"house"`, `"apartment"`, `"land"`, `"office"`, `"commercial"`, `"garage"`. |
| `transactionType` | `string` | `"for-sale"` | Transaction mode: `"for-sale"` or `"for-rent"`. |
| `location` | `string` | `""` (All Belgium) | Select from 26 built-in Belgian cities, districts, and provinces (e.g., `"brussels/district"`, `"antwerp/municipality"`, `"ghent/municipality"`, `"liege/province"`), or leave empty for nationwide Belgium. |
| `language` | `string` | `"en"` | Output language for titles, descriptions, and URLs: `"en"` (English), `"fr"` (Français), or `"nl"` (Nederlands). |
| `minPrice` | `integer` | `0` | Minimum price in EUR (`0` = no minimum). |
| `maxPrice` | `integer` | `0` | Maximum price in EUR (`0` = no maximum). |
| `minBedrooms` | `integer` | `0` | Minimum number of bedrooms (`0` = no minimum). |
| `scrapeDetails` | `boolean` | `false` | Open each listing's detail page to also extract EPC energy score, heating type, build year, condition, façades, flood zone, description, and agency phone/email. |
| `maxListings` | `integer` | `0` (prefill `90`) | Maximum total listings to collect (`0` = unlimited). |
| `maxPages` | `integer` | `0` | Maximum search result pages to crawl (~30 listings per page). Set `0` for automatic / unlimited pagination governed by `maxListings`. |
| `startUrls` | `array` | `[]` | Advanced: paste one or more Immoweb search or classified listing URLs to scrape directly (overrides menu filters). |
| `locationCustom` | `string` | `""` | Advanced: custom Immoweb location slug (e.g., `"knokke-heist/municipality"`, `"waterloo/municipality"`) used when `location` is left on All of Belgium. |
| `proxyConfiguration` | `object` | `BE` Residential | Proxy settings. Keep Apify **Belgian (`BE`) Residential** proxy enabled for reliable access. |
| `requestDelay` | `integer` | `2000` | Politeness pause between page requests in milliseconds. |

#### Example 1 — 1,000+ Apartments for sale in Brussels & Antwerp (fast index mode)

```json
{
  "propertyType": "apartment",
  "transactionType": "for-sale",
  "location": "brussels/district",
  "language": "en",
  "minPrice": 180000,
  "maxPrice": 750000,
  "minBedrooms": 2,
  "scrapeDetails": false,
  "maxListings": 1000,
  "maxPages": 0,
  "requestDelay": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "BE"
  }
}
```

#### Example 2 — Houses for sale in Ghent with full EPC & agency contact enrichment

```json
{
  "propertyType": "house",
  "transactionType": "for-sale",
  "location": "ghent/municipality",
  "minBedrooms": 3,
  "scrapeDetails": true,
  "maxListings": 150,
  "maxPages": 0
}
```

#### Example 3 — Scrape custom Immoweb search or listing URLs (`startUrls`)

```json
{
  "startUrls": [
    { "url": "https://www.immoweb.be/en/search/house-and-apartment/for-rent/leuven/municipality?countries=BE" },
    { "url": "https://www.immoweb.be/en/search/house-and-apartment/for-rent/namur/municipality?countries=BE" }
  ],
  "maxListings": 500,
  "maxPages": 0
}
```

***

### 📤 Output & field reference

Every property is saved as a consistent, flat JSON object. Below is a real record from a verification run in fast mode (`scrapeDetails: false`):

```json
{
  "listingId": "21958459",
  "listingType": "for-sale",
  "propertyType": "apartment",
  "title": "Gerenoveerd 2 slp app + garage",
  "price": 349000,
  "currency": "EUR",
  "bedrooms": 2,
  "bathrooms": 1,
  "livingArea": 110,
  "landSurface": null,
  "postcode": "2600",
  "city": "Berchem",
  "province": "Antwerp",
  "region": "Flanders",
  "latitude": 51.1826499,
  "longitude": 4.4385601,
  "epcScore": null,
  "epcValue": null,
  "heatingType": null,
  "buildYear": null,
  "condition": null,
  "facade": null,
  "floodZone": null,
  "description": null,
  "agencyName": "Coprimmo Immobiliën",
  "agencyPhone": null,
  "agencyEmail": null,
  "agencyWebsite": null,
  "viewCount": null,
  "bookmarkCount": null,
  "daysOnMarket": null,
  "images": [
    "https://media-resize.immowebstatic.be/classifieds/0acac86c-bc9c-40b3-8052-d60c9e60e021/736x736/7c0c9b09e50b5d154425b3487c3dc5ac.jpg",
    "https://media-resize.immowebstatic.be/classifieds/0acac86c-bc9c-40b3-8052-d60c9e60e021/736x736/774827b487af343f6d97d4efbc15e370.jpg"
  ],
  "listingUrl": "https://www.immoweb.be/en/classified/apartment/for-sale/berchem/2600/21958459",
  "searchUrl": "https://www.immoweb.be/en/search/apartment/for-sale/antwerp/municipality?countries=BE&page=1&orderBy=relevance",
  "scrapedAt": "2026-11-02T00:04:35.135Z"
}
```

#### Field reference by category

##### 🏷️ Listing identity & classification

| Field | Type | Coverage | Description |
|---|---|---|---|
| `listingId` | `string` | 🟢 High (100%) | Unique numeric Immoweb classified ID (primary key used for de-duplication). |
| `listingType` | `string` | 🟢 High (100%) | Transaction type: `"for-sale"` or `"for-rent"`. |
| `propertyType` | `string` | 🟢 High (100%) | Granular property subtype slug from the classified URL (`apartment`, `house`, `villa`, `duplex`, `penthouse`, `flat-studio`, `town-house`, `building-plot`, `commercial-ground-floor`, etc.). |
| `title` | `string \| null` | 🟢 High (~92%) | Property headline / title in the selected language. |
| `listingUrl` | `string` | 🟢 High (100%) | Canonical URL to the property page on `immoweb.be`. |
| `searchUrl` | `string` | 🟢 High (100%) | The search page URL that surfaced this property (or `"direct"` for direct classified URLs). |
| `scrapedAt` | `string` | 🟢 High (100%) | ISO 8601 UTC timestamp of extraction. |

##### 💶 Pricing & property dimensions

| Field | Type | Coverage | Description |
|---|---|---|---|
| `price` | `number \| null` | 🟢 High (~99%) | Asking sale price or monthly rental price in EUR. |
| `currency` | `string` | 🟢 High (100%) | Always `"EUR"`. |
| `bedrooms` | `integer \| null` | 🟢 High (~90%) | Number of bedrooms (`chambres` / `slaapkamers`). |
| `bathrooms` | `integer \| null` | 🟡 Conditional | Number of bathrooms (populated when exposed on the card or when `scrapeDetails: true`). |
| `livingArea` | `number \| null` | 🟢 High (~88%) | Net habitable surface (`surface habitable` / `bewoonbare oppervlakte`) in square meters (m²). |
| `landSurface` | `number \| null` | 🟡 Conditional | Total plot / land surface in m² (populated for houses, villas, and building plots). |

##### 📍 Belgian location, postcode & GPS

| Field | Type | Coverage | Description |
|---|---|---|---|
| `postcode` | `string` | 🟢 High (100%) | 4-digit Belgian postal code (`1000`–`9999`). |
| `city` | `string` | 🟢 High (100%) | Belgian municipality / locality name (e.g., `"Brussels"`, `"Berchem"`, `"Waterloo"`, `"Gent"`). |
| `province` | `string` | 🟢 High (100%) | Auto-mapped Belgian province (`Brussels`, `Antwerp`, `East Flanders`, `West Flanders`, `Flemish Brabant`, `Limburg`, `Liège`, `Namur`, `Hainaut`, `Walloon Brabant`, `Luxembourg`). |
| `region` | `string` | 🟢 High (100%) | Auto-mapped Belgian region (`"Brussels"`, `"Flanders"`, or `"Wallonia"`). |
| `latitude` | `number \| null` | 🟢 High (~85%) | WGS84 decimal latitude (when the seller permits exact pin display). |
| `longitude` | `number \| null` | 🟢 High (~85%) | WGS84 decimal longitude (when the seller permits exact pin display). |

##### ⚡ Energy (EPC / PEB), building specs & flood risk (`scrapeDetails: true`)

| Field | Type | Coverage | Description |
|---|---|---|---|
| `epcScore` | `string \| null` | 🟡 Detail mode | Official EPC / PEB energy certificate letter (`A++`, `A+`, `A`, `B`, `C`, `D`, `E`, `F`, `G`). |
| `epcValue` | `number \| null` | 🟡 Detail mode | Primary energy consumption in `kWh/m²/year`. |
| `heatingType` | `string \| null` | 🟡 Detail mode | Heating source (e.g., `GAS`, `FUEL_OIL`, `ELECTRIC`, `HEAT_PUMP`). |
| `buildYear` | `integer \| null` | 🟡 Detail mode | Year of construction (`constructionYear`). |
| `condition` | `string \| null` | 🟡 Detail mode | Building state (e.g., `AS_NEW`, `GOOD`, `TO_BE_DONE_UP`, `TO_RENOVATE`, `JUST_RENOVATED`). |
| `facade` | `integer \| null` | 🟡 Detail mode | Number of building façades (`2` = terraced, `3` = semi-detached, `4` = detached). |
| `floodZone` | `boolean \| null` | 🟡 Detail mode | `true` if located in a designated flood-risk zone, `false` if `NON_FLOOD_ZONE`. |
| `description` | `string \| null` | 🟡 Detail mode | Full property description text in the chosen language (`en` / `fr` / `nl`). |

##### 🤝 Agency contacts, media & engagement

| Field | Type | Coverage | Description |
|---|---|---|---|
| `agencyName` | `string \| null` | 🟢 High (~92%) | Listing real estate agency or developer name (extracted right from the search card!). |
| `agencyPhone` | `string \| null` | 🟡 Detail mode | Agency contact phone number (populated when `scrapeDetails: true`). |
| `agencyEmail` | `string \| null` | 🟡 Detail mode | Agency contact email address (populated when `scrapeDetails: true`). |
| `agencyWebsite` | `string \| null` | 🟡 Detail mode | Agency website URL (populated when `scrapeDetails: true`). |
| `viewCount` | `integer \| null` | 🟡 Detail mode | Total listing views on Immoweb (`scrapeDetails: true`). |
| `bookmarkCount` | `integer \| null` | 🟡 Detail mode | Number of users who saved the listing (`scrapeDetails: true`). |
| `daysOnMarket` | `integer \| null` | 🟡 Detail mode | Days elapsed since the listing's creation date (`scrapeDetails: true`). |
| `images` | `array \| null` | 🟢 High (~95%) | Up to 10 high-resolution image URLs on `media-resize.immowebstatic.be` (included in fast mode!). |

***

### 🔁 Pagination & 1,000+ scale

This **Immoweb scraper** is designed for both rapid market snapshots and deep 1,000+ property crawls:

1. **Unlocked `maxPages: 0` default:** When `maxPages` is `0` (the default), pagination is governed entirely by your `maxListings` target. Setting `maxListings: 1000` automatically walks `?page=1`, `?page=2`, `?page=3`… (~30 properties per page) across 34+ pages until 1,000 unique properties are saved.
2. **Fast HTTP card-JSON extraction:** On search pages, the actor extracts the complete embedded JSON payload attached to each property card — capturing 30 properties per page in ~1–2 seconds per page without needing to open individual property pages or launch a heavy browser unless fallback is required.
3. **100% `listingId` de-duplication:** Every property is tracked in an in-memory `seenIds` set by its canonical numeric `listingId`, guaranteeing **0 duplicate records** across pages and multiple `startUrls`.

***

### ⚙️ How to use

1. **Open the actor** in the Apify Console.
2. **Choose your property & transaction filters** — select `propertyType` (e.g., *Houses & Apartments*, *Apartments only*, *Houses only*, *Commercial*), `transactionType` (*For Sale* or *For Rent*), and `location` (or paste custom URLs into `startUrls`).
3. **Choose fast mode vs. detail mode** — keep `scrapeDetails: false` for fast, high-volume pricing/location/photo extraction, or enable `scrapeDetails: true` when you need EPC scores, building specs, and agency phone/email contacts.
4. **Set `maxListings`** — e.g., `90` for a quick test, `1000` for a deep regional crawl, or `0` for unlimited.
5. **Click Start** — keep the default Belgian (`BE`) Residential proxy enabled.
6. **Export or integrate** — download your dataset as **JSON, CSV, Excel (XLSX), HTML, or XML**, or consume it via the **Apify API**, Google Sheets, Make, Zapier, or webhooks.

#### Calling via the Apify API (Python)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("haketa/immoweb-scraper").call(run_input={
    "propertyType": "house-and-apartment",
    "transactionType": "for-sale",
    "location": "brussels/district",
    "minPrice": 200000,
    "maxPrice": 800000,
    "scrapeDetails": False,
    "maxListings": 500,
    "maxPages": 0,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["listingId"], item["city"], f"€{item['price']}", f"{item['livingArea']}m²")
```

#### Calling via the Apify API (Node.js)

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

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

const run = await client.actor('haketa/immoweb-scraper').call({
    propertyType: 'apartment',
    transactionType: 'for-rent',
    location: 'antwerp/municipality',
    maxPrice: 1800,
    minBedrooms: 2,
    scrapeDetails: false,
    maxListings: 300,
    maxPages: 0,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Extracted ${items.length} Belgian rental listings from Immoweb.`);
```

#### Belgian postcode → Region & Province mapping reference

| Postcode Range | Region | Province |
|---|---|---|
| `1000 – 1299` | Brussels | Brussels-Capital Region |
| `1300 – 1499` | Wallonia | Walloon Brabant (`Brabant wallon`) |
| `1500 – 1999`, `3000 – 3499` | Flanders | Flemish Brabant (`Vlaams-Brabant`) |
| `2000 – 2999` | Flanders | Antwerp (`Antwerpen`) |
| `3500 – 3999` | Flanders | Limburg |
| `4000 – 4999` | Wallonia | Liège (`Luik`) |
| `5000 – 5999` | Wallonia | Namur (`Namen`) |
| `6000 – 6599`, `7000 – 7999` | Wallonia | Hainaut (`Henegouwen`) |
| `6600 – 6999` | Wallonia | Luxembourg |
| `8000 – 8999` | Flanders | West Flanders (`West-Vlaanderen`) |
| `9000 – 9999` | Flanders | East Flanders (`Oost-Vlaanderen`) |

***

### 💡 Pro tips for Belgian real estate data

- ⚡ **Use `scrapeDetails: false` for 90% of analytics use cases:** Because our parser decodes Immoweb's embedded search-card JSON, you already get `title`, `price`, `bedrooms`, `bathrooms`, `livingArea`, `landSurface`, `postcode`, `city`, `province`, `region`, `latitude`, `longitude`, `images`, and `agencyName` at 30× the speed and a fraction of the proxy traffic of detail-page crawling.
- 🔗 **Copy-paste any complex Immoweb search URL into `startUrls`:** Want to filter by garden surface, terrace, EPC class A–C, new builds excluded, or a specific radius around a postcode? Build the exact filter on `immoweb.be`, copy the browser URL, and paste it into `startUrls`.
- 📊 **Track price drops with daily schedules:** Schedule a daily run with your target filters and compare `price` keyed by `listingId` in your database or spreadsheet to spot motivated sellers the day they reduce their asking price.

***

### ❓ FAQ

#### Why is a Belgian (`BE`) Residential proxy recommended?

Immoweb restricts datacenter IP ranges. Using Apify's Belgian (`BE`) Residential proxy pool (configured by default) ensures clean, uninterrupted access to search and detail pages.

#### Why are `epcScore`, `buildYear`, `description`, or `agencyPhone` `null` in my dataset?

Those fields only exist on individual property detail pages. To keep default runs fast and low-cost, `scrapeDetails` defaults to `false`. Set **`scrapeDetails: true`** in your input to visit each property page and populate all EPC, building, description, and agency contact fields.

#### How many listings can I scrape in a single run?

With `maxPages: 0` (the default) and `maxListings: 1000` (or `0` for unlimited), you can collect **hundreds to thousands of unique Belgian properties** in a single run. To exceed Immoweb's per-search pagination window (~333 pages / ~10,000 listings), split your run across multiple provinces or municipalities in `startUrls`.

#### Does the scraper work for Flanders, Wallonia, and Brussels?

Yes. It covers all three Belgian regions and automatically maps every 4-digit Belgian postcode (`1000`–`9999`) to its canonical `region` (`Brussels`, `Flanders`, `Wallonia`) and `province`.

#### Can I scrape a single specific property listing?

Yes. Paste one or more `/classified/...` URLs directly into `startUrls` — the actor will automatically fetch and enrich each individual listing page.

***

### 🔗 Related scrapers

Building a pan-European real estate intelligence pipeline? Combine **Immoweb Scraper** with our other European property extractors:

- 🇸🇪 [Hemnet Scraper](https://apify.com/haketa/hemnet-scraper) — Sweden's #1 real estate portal (active listings & historical sold prices / slutpriser).
- 🇩🇰 [Boliga Scraper](https://apify.com/haketa/boliga-scraper) — Danish property listings and historical sold prices.
- 🇩🇪 [ImmobilienScout24 Scraper](https://apify.com/haketa/immobilienscout24-scraper) — Germany's largest real estate marketplace.
- 🇪🇸 [Milanuncios Scraper](https://apify.com/haketa/milanuncios-scraper) — Spanish property and classified listings.
- 🇳🇱 [Marktplaats Scraper](https://apify.com/haketa/marktplaats-scraper) — Dutch classifieds and property listings.

***

### 📋 Changelog

#### v1.2 (2026-11)

- **Unlocked 1,000+ deep pagination:** Changed `maxPages` default from `3` to `0` (automatic/unlimited, governed by `maxListings`) and removed the 5-page cap on nationwide runs so `maxListings: 1000+` paginates all the way to the user's target.
- **Lazy browser initialization:** Optimized the hybrid engine so Chromium is only launched if the fast HTTP path requires fallback, reducing startup overhead and memory usage on standard runs.

#### v1.1 (2026-10)

- **Rich search-card JSON extraction:** Added balanced-brace decoding of `handleClickOnSearchCard` payloads so `title`, `price`, `bedrooms`, `bathrooms`, `livingArea`, `landSurface`, `latitude`/`longitude`, `images`, and `agencyName` populate in fast mode without detail requests.

#### v1.0 (2026-05)

- Initial release supporting Belgian for-sale and for-rent listings across Brussels, Flanders, and Wallonia with postcode-to-province mapping and optional detail enrichment.

# Changelog

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

# Actor input Schema

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

Which kind of property to collect. Choose from the menu.

## `transactionType` (type: `string`):

Collect properties for sale or properties for rent.

## `location` (type: `string`):

Pick a city, province or district. Choose 'All of Belgium' to get a nationwide mix of listings.

## `language` (type: `string`):

Site language for listing descriptions and text.

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

Only keep listings at or above this price in EUR. Leave at 0 for no minimum.

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

Only keep listings at or below this price in EUR. Leave at 0 for no maximum.

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

Only keep listings with at least this many bedrooms. Leave at 0 for no minimum.

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

Also open each listing page to collect extra fields: EPC energy score, full description, heating type, build year, flood zone and agency contact. Slower but more complete.

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

Stop after collecting this many listings. Set 0 for unlimited.

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

Maximum number of search result pages to open (about 30 listings per page). Set 0 for automatic / unlimited pagination (governed by Max Listings).

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

Optional. Paste one or more Immoweb.be search or listing URLs to scrape them exactly. When set, these override the menu filters above. Most users can leave this empty.

## `locationCustom` (type: `string`):

Optional. For a location that is not in the menu, paste the Immoweb location path here, e.g. 'knokke-heist/municipality'. Only used when the Location menu is set to 'All of Belgium'.

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

Proxy settings. A Belgian residential proxy is recommended for reliable results.

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

Pause between page loads in milliseconds. Higher values are gentler on the site.

## Actor input object example

```json
{
  "propertyType": "house-and-apartment",
  "transactionType": "for-sale",
  "location": "",
  "language": "en",
  "minPrice": 0,
  "maxPrice": 0,
  "minBedrooms": 0,
  "scrapeDetails": false,
  "maxListings": 90,
  "maxPages": 0,
  "startUrls": [],
  "locationCustom": "",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "BE"
  },
  "requestDelay": 2000
}
```

# Actor output Schema

## `dataset` (type: `string`):

All scraped Immoweb.be property listings. Open, filter and download as JSON, CSV or Excel.

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

Key fields for every listing: type, price, bedrooms, living area, EPC, city, postcode and agency.

# 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 = {
    "maxListings": 90,
    "startUrls": [],
    "locationCustom": "",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "BE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/immoweb-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 = {
    "maxListings": 90,
    "startUrls": [],
    "locationCustom": "",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "BE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/immoweb-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 '{
  "maxListings": 90,
  "startUrls": [],
  "locationCustom": "",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "BE"
  }
}' |
apify call haketa/immoweb-scraper --silent --output-dataset

```

## MCP server setup

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