# Immoweb Scraper — Belgian Real Estate Listings (`estatelab/immoweb-property-scraper`) Actor

Scrape Immoweb.be property listings: price, surface, bedrooms, location, photos. Clean normalized output, no personal data. Pay only for listings delivered.

- **URL**: https://apify.com/estatelab/immoweb-property-scraper.md
- **Developed by:** [EstateLab](https://apify.com/estatelab) (community)
- **Categories:** Real estate, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 listing scrapeds

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

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

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Immoweb Scraper — Belgian Real Estate Listings

Extract property listings from **Immoweb.be**, Belgium's largest real estate
portal: asking price, habitable surface, bedrooms, locality, postal code,
province, photos and publication dates — in a clean, stable JSON schema.

**You pay only for listings actually delivered.** No start fee, no charge for
empty runs.

### What you get

Houses and apartments for sale or for rent, with a normalized output that stays
identical from run to run — so your spreadsheet, database or dashboard never
breaks. Plus two things other Immoweb scrapers don't give you: **price per m²
on every listing**, and a **market summary** of median €/m² by locality.

Typical uses: market and price analysis, comparable-property research,
investment screening, competitor monitoring for agencies, feeding a valuation
model, tracking new listings in a given area.

### Input

**The easy way — paste your search URL.** Build the search you want on
Immoweb itself, with any filters the site offers (price, surface, EPC rating,
build year, garden, terrace…), then paste the address into `searchUrl`. The
Actor paginates through it. No need to rebuild your filters in a form.

```json
{
  "searchUrl": "https://www.immoweb.be/en/search/house/for-sale?countries=BE&maxPrice=400000&minBedroomCount=3",
  "maxPages": 10
}
```

**Or use the simple filters**, if you'd rather not touch a URL:

| Field | What it does | Default |
| --- | --- | --- |
| `searchUrl` | Immoweb search URL to paginate. Overrides the filters below | — |
| `propertyType` | `house`, `apartment`, `land`, `building`, `garage`, `office`, `commercial` | `house` |
| `transactionType` | `sale` or `rent` | `sale` |
| `postalCodes` | Restrict to specific Belgian postal codes; empty covers the country | `[]` |
| `maxPages` | Each page yields up to 30 listings | `5` |
| `maxListings` | Hard cap on delivered listings, `0` for none | `0` |
| `language` | `fr`, `nl` or `en` — all three fully supported | `fr` |
| `marketSummary` | Write the median €/m² summary to the key-value store | `true` |
| `requestDelaySeconds` | Pause between page requests | `1` |

```json
{
  "propertyType": "apartment",
  "transactionType": "sale",
  "postalCodes": ["1000", "2000"],
  "maxPages": 10
}
```

### Output

One row per listing:

```json
{
  "portal": "immoweb",
  "listingId": "21773122",
  "url": "https://www.immoweb.be/fr/annonce/maison/a-vendre/woluwe-saint-lambert/1200/21773122",
  "transactionType": "sale",
  "propertyType": "HOUSE",
  "propertySubtype": "HOUSE",
  "title": "Maison avec jardin et beau potentiel",
  "price": 649000,
  "priceMin": null,
  "priceMax": null,
  "priceDisplay": "649 000 €",
  "currency": "EUR",
  "habitableSurface": 180,
  "landSurface": null,
  "bedrooms": 4,
  "rooms": null,
  "pricePerSqm": 3606,
  "country": "Belgique",
  "region": "Bruxelles",
  "province": "Bruxelles",
  "locality": "Woluwe-Saint-Lambert",
  "postalCode": "1200",
  "images": ["https://media-resize.immowebstatic.be/..."],
  "flags": ["new"],
  "agency": "ABITA IMMO",
  "publishedAt": null,
  "updatedAt": "2026-08-20T10:04:48.571Z",
  "scrapedAt": "2026-08-20T18:22:10.004Z"
}
```

New-development projects are sold as a range rather than a single figure: for
those, `price` is `null` and `priceMin` / `priceMax` carry the bracket, while
`priceDisplay` always holds the human-readable value.

### Market summary

At the end of each run, a `MARKET_SUMMARY` entry is written to the run's
key-value store: median, minimum and maximum price per m² for every locality
with at least three comparable listings.

```json
[
  { "locality": "Liège", "transactionType": "sale", "propertyType": "HOUSE",
    "listings": 4, "medianPricePerSqm": 1548,
    "minPricePerSqm": 1063, "maxPricePerSqm": 1878 }
]
```

Sales and rentals are grouped separately, as are property types — mixing them
would produce a meaningless median, since a rent per m² is monthly. Set
`marketSummary` to `false` to skip it.

### No personal data

This Actor describes **properties, not people**. It never collects seller
names, phone numbers, email addresses or any contact details.

The `agency` field is filled only when the advertiser's name carries a
recognised company legal form (NV, BV, SA, SPRL, GmbH, Ltd…), which identifies
a legal entity. Any name that could belong to a private individual is dropped
rather than published. That keeps the output outside the scope of personal data
processing under the GDPR.

### Reliability

- A page that fails is retried up to three times, then recorded in the
  `FAILED_PAGES` key of the run's key-value store. **A single bad page never
  aborts the run** — you always know exactly what was and wasn't collected.
- Listings are deduplicated by ID across pages.
- No headless browser is used, which makes runs fast and cheap: one HTTP
  request returns thirty listings.

### Pricing

Pay-per-event, charged **per listing delivered to the dataset**. A run that
returns nothing costs nothing.

### Terms of use

You are responsible for how you use the data this Actor returns. Review
Immoweb's terms of service and your local regulations before running it,
especially if you intend to redistribute or publish the collected data. Keep
request volumes reasonable — the default delay between pages exists for that
purpose. This Actor is not affiliated with, endorsed by, or connected to
Immoweb.

### Roadmap

Same schema, other European portals: Idealista (ES), Rightmove (UK), Funda
(NL), ImmoScout24 (DE), Immobiliare (IT), SeLoger (FR), Zoopla (UK).
Swap the Actor, keep your pipeline.

# Actor input Schema

## `searchUrl` (type: `string`):

Paste a search URL straight from Immoweb. Build your search on the site with any filters you like — price, surface, EPC, build year — and paste the address here. Leave empty to use the simple filters below.

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

Which kind of property to collect.

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

For sale or for rent.

## `postalCodes` (type: `array`):

Limit the search to these Belgian postal codes, e.g. 1000, 2000, 9000. Leave empty to cover the whole country.

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

Each page yields up to 30 listings. The run stops on its own when a page comes back empty.

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

Hard cap on delivered listings. Set 0 for no cap. Useful to keep a run predictable.

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

Language of the Immoweb pages requested. Affects locality spelling, property titles and country name in the output.

## `requestDelaySeconds` (type: `integer`):

Pause between page requests. Keeping a small delay is courteous to the site and keeps runs reliable.

## `marketSummary` (type: `boolean`):

Write a per-locality summary of median price per m2 to the MARKET\_SUMMARY key of the run's key-value store.

## Actor input object example

```json
{
  "searchUrl": "https://www.immoweb.be/en/search/house/for-sale?countries=BE&maxPrice=400000",
  "propertyType": "house",
  "transactionType": "sale",
  "postalCodes": [
    "1000"
  ],
  "maxPages": 5,
  "maxListings": 0,
  "language": "fr",
  "requestDelaySeconds": 1,
  "marketSummary": true
}
```

# Actor output Schema

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

One row per property: asking price, price per m2, habitable surface, bedrooms, locality, postal code, province, photos and publication dates. Same schema across every portal we cover.

## `marketSummary` (type: `string`):

Median, minimum and maximum price per m2 for each locality found in the run. Written only when the Market summary option is enabled.

# 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 = {
    "searchUrl": "https://www.immoweb.be/en/search/house/for-sale?countries=BE&maxPrice=400000",
    "postalCodes": [
        "1000"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("estatelab/immoweb-property-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 = {
    "searchUrl": "https://www.immoweb.be/en/search/house/for-sale?countries=BE&maxPrice=400000",
    "postalCodes": ["1000"],
}

# Run the Actor and wait for it to finish
run = client.actor("estatelab/immoweb-property-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 '{
  "searchUrl": "https://www.immoweb.be/en/search/house/for-sale?countries=BE&maxPrice=400000",
  "postalCodes": [
    "1000"
  ]
}' |
apify call estatelab/immoweb-property-scraper --silent --output-dataset

```

## MCP server setup

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