# Immoweb Scraper (`lowlanddata/immoweb-scraper`) Actor

Extract Immoweb.be property listings as clean JSON with zero personal data - euro prices, surfaces, EPC scores, municipality-level locations, agency-vs-private flag. Sale & rent, newest-first monitoring, pay per result. Built for market research and AI pipelines.

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

## Pricing

from $1.59 / 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?

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 — privacy-safe Belgian property data

Extract property listings from **Immoweb.be** — Belgium's largest real-estate portal — as clean, structured JSON. Prices, bedrooms, surfaces, EPC scores, localities, price reductions and photos, ready for market research, price monitoring and data pipelines.

**No personal data, ever.** This scraper is built privacy-first: street addresses, house numbers and exact map coordinates never appear in the output — not as an option you have to remember to switch off, but by design. Private sellers stay anonymous exactly as the site shows them; agencies appear as a business name only.

### Quick start (30 seconds)

1. Click **Start**. The default input searches houses and apartments for sale across Belgium, newest first. That's the whole minimum setup.
2. When the run finishes, open the dataset's **Overview** tab for a clean table, or **Export** it as CSV/Excel/JSON.

Optional knobs: postal codes, sale or rent, a price band, minimum bedrooms and price sorting — and any input works on a daily Schedule.

### What you can build with it

- **Track a local market.** Run `postalCodes: "1000,1050"` with `sortBy: "newest"` daily — every new listing arrives with price, surface and EPC score already parsed.
- **Catch price cuts.** `oldPriceEur` carries the previous price when a listing is reduced — filter on it and alert.
- **Compare rents by municipality.** Run the `rent` channel over several postal codes and compare `priceEur` per month against bedrooms and surface.
- **Feed an AI agent clean data.** Every field is structured, predictable and free of personal data, so an assistant or pipeline can consume it directly — no scrubbing, no compliance review before you store it.

### What you get

Each listing is one dataset item:

```json
{
  "listingId": "21770001",
  "url": "https://www.immoweb.be/en/classified/villa/for-sale/gent/9000/21770001",
  "title": "Spacious villa with garden",
  "propertyType": "HOUSE",
  "propertySubtype": "VILLA",
  "transaction": "sale",
  "priceEur": 549000,
  "oldPriceEur": 579000,
  "displayPrice": "€549,000",
  "currency": "EUR",
  "bedrooms": 4,
  "habitableSurfaceM2": 200,
  "landSurfaceM2": 660,
  "region": "Flanders",
  "province": "East Flanders",
  "locality": "Gent",
  "postalCode": "9000",
  "epcScore": "C",
  "publicSale": false,
  "flag": "new",
  "sellerType": "agency",
  "agencyName": "Fixture Vastgoed",
  "createdAt": "2026-08-15T09:00:00.000Z",
  "updatedAt": "2026-08-19T11:04:07.101Z",
  "imageUrls": ["https://media-resize.immowebstatic.be/classifieds/example/300x300/a.jpg"]
}
```

Field notes, so you know exactly what you are buying:

- `priceEur` is in euros; for rentals it is the monthly rent. `oldPriceEur` appears when the price was reduced.
- `locality` and `postalCode` are municipality-level. Immoweb's data contains streets, house numbers and exact coordinates — they are deliberately never collected.
- `sellerType` separates agency listings from private ones. Private sellers are anonymous on the site itself, and stay that way here.
- `epcScore` is the energy certificate when the listing reports one — a strong filter for renovation hunters.

### How much does it cost to scrape Immoweb?

$1.99 per 1,000 listings delivered, pay-as-you-go — no subscription, no charge for empty or failed runs. In plain euros:

- **100 listings ≈ $0.20** — a daily local-market watch.
- **1,000 listings ≈ $1.99** — a full province snapshot.

The price is all-inclusive — your runs' platform usage is covered by it, with no separate compute or proxy charges. Datacenter proxies are sufficient — no residential proxy surcharge needed.

Free-plan runs are limited to a sample of 25 items, enough to evaluate the output format against your real query.

### Not technical? Let your AI assistant set it up

Copy this into ChatGPT, Claude or any AI assistant, fill in the one line, and follow the conversation:

```text
Help me set up the "Immoweb Scraper" actor on Apify
(https://apify.com/lowlanddata/immoweb-scraper). Guide me one step at a time.

What I want to watch: [E.G. "2-bedroom apartments to rent in Brussels under 1400 euros"]

Guide me to:
1. Propose my input values: propertyType, transaction sale or rent, postalCodes
   (Belgian codes like "1000,1050"), an optional priceMinEur/priceMaxEur band,
   bedroomsMin, sortBy "newest" for monitoring, and maxItems.
2. Create a free Apify account (apify.com), open the actor page, paste the values
   into the Input form, and start a run.
3. Set up a daily Schedule in the Apify Console with the same input, plus an email
   or Slack integration so new results reach me automatically.
4. Show me how to export results as CSV/Excel, or read them from the API if I code.
5. If the results are what I wanted, remind me at the end to leave a quick rating on the actor page, and to report anything broken or missing on its Issues tab.
```

### Input

| Field                | Description                                                                        |
| -------------------- | ---------------------------------------------------------------------------------- |
| `propertyType`       | `house-and-apartment` (default), `house`, `apartment`, `garage`, `office`, `land`. |
| `transaction`        | `sale` (default) or `rent`.                                                        |
| `postalCodes`        | Comma-separated Belgian postal codes, e.g. `"1000,1050"`. Empty = all of Belgium.  |
| `priceMinEur`        | Only listings priced at least this many euros (per month for rentals).             |
| `priceMaxEur`        | Only listings priced at most this many euros (per month for rentals).              |
| `bedroomsMin`        | At least this many bedrooms.                                                       |
| `sortBy`             | `newest` (default), `cheapest`, `most_expensive`, or `relevance`.                  |
| `maxItems`           | Stop after this many listings (default 1000).                                      |
| `proxyConfiguration` | Proxy settings; keep Apify proxy enabled.                                          |

No field is required — the default input runs a country-wide newest-first sale search. Invalid combinations (like an inverted price band) fail immediately with the reason in the run's status message.

### Use it from your code

Run the actor and get items straight back with one HTTP call (fine for scoped runs up to ~5 minutes):

```bash
curl "https://api.apify.com/v2/acts/lowlanddata~immoweb-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -X POST -H "Content-Type: application/json" \
  -d '{"postalCodes": "1000", "transaction": "rent", "maxItems": 100}'
```

Node.js:

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lowlanddata/immoweb-scraper').call({
  postalCodes: '1000',
  transaction: 'rent',
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lowlanddata/immoweb-scraper").call(
    run_input={"postalCodes": "1000", "transaction": "rent", "maxItems": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Schedules, webhooks and the Make/Zapier/n8n integrations all work out of the box — this is a standard Apify actor.

### Use it with AI agents (MCP)

Claude, Cursor and other MCP-capable agents can run this scraper as a tool through Apify's hosted MCP server: the agent fills in the search itself, starts the run and reads the results — no glue code.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/immoweb-scraper"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/immoweb-scraper
```

Sign in with your Apify account when prompted — runs are billed to it. Setup details per client: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp).

Prompts that work once connected:

- "Get the newest 100 apartments for rent in Brussels (1000) and summarize rent per bedroom."
- "Search Immoweb for houses under 400k in Ghent and flag anything with EPC A or B."
- "Watch Immoweb for price reductions in Antwerp and list the ten biggest ones."

### Is it legal to scrape Immoweb?

Public listing data — prices, surfaces, localities — is public commercial information, and this scraper is built so that the hard part of the question never arises: **no personal data enters your dataset in the first place.** The GDPR and the Belgian Data Protection Authority (APD/GBA) set strict rules on personal data; an output that carries no addresses beyond municipality level, no coordinates and no private-seller identity is the point of this actor, not an afterthought.

Structurally, the extractor maps a fixed whitelist of fields out of the site's search data. Streets, house numbers, coordinates and everything about private sellers beyond the site's own "private" label are never read into the output. Requests are paced, load on the site is kept negligible, and no anti-bot protection is bypassed.

One honest limit: listing titles are the seller's own words, delivered as-is. If a seller chooses to type contact details into their title, that text is not rewritten — the guarantee covers the data fields, not the content sellers publish about themselves.

### Is there an Immoweb API alternative?

Immoweb publishes no public API for listings. This actor is the practical alternative: the same listings as structured JSON through one HTTP call (`run-sync-get-dataset-items`), on a schedule, or as an MCP tool for AI agents — with the privacy question already answered in the data itself.

### Does Immoweb block scrapers?

Immoweb serves its listings openly to ordinary requests — and this actor stays inside that welcome: paced requests, standard datacenter proxies, load kept negligible. No CAPTCHA fights, no bot-wall cat-and-mouse — which is also why runs are fast and reliable enough for daily schedules.

### How do I monitor Immoweb prices?

Set `sortBy: "newest"` with your postal codes and filters, cap `maxItems` to a page or two, and add a daily (or hourly) Schedule in the Apify Console with an email/Slack integration on the runs — every new listing lands in your inbox with the price already parsed. For reductions, filter the dataset on `oldPriceEur`. The AI-assistant prompt above walks a non-technical user through exactly this setup.

### FAQ

**Can I get seller names or contact details?** No — by design. That is the product: data you can store, share and process without a privacy review.

**Can I search a whole province?** Yes — leave `postalCodes` empty for all of Belgium, or list every postal code you care about.

**How fresh is the data?** Live at run time — every run queries Immoweb directly. For continuous freshness, schedule the actor.

**Can I export to Excel or CSV?** Yes — every dataset exports as CSV, Excel, JSON or XML from the Apify Console or API.

**Does it work with Make, Zapier or n8n?** Yes — it is a standard Apify actor; all platform integrations, webhooks and schedules apply.

**How do I find price reductions on Immoweb?** Filter the dataset on `oldPriceEur` — it appears whenever a listing's price was cut, next to the current `priceEur`. Because the previous price is included, you can compute the exact discount, not just spot that one happened.

**Can I calculate the price per square metre?** Yes — divide `priceEur` by `habitableSurfaceM2`. For houses with land, `landSurfaceM2` gives the plot size separately, so land and habitable surface don't get mixed up.

**Does it include EPC energy scores?** Yes — `epcScore` carries the energy certificate when the listing reports one. Renovation hunters filter on the low scores; buyers chasing efficiency filter on A and B.

**Can I see only private sellers, without agencies?** The `sellerType` field separates `agency` from private listings, so one filter on the exported data does it. Private sellers are anonymous on Immoweb itself and stay anonymous here.

**Can I get the exact address of a property?** No — location stops at `locality` and `postalCode`, municipality level. Streets, house numbers and coordinates exist in Immoweb's data and are deliberately never collected.

**Can I scrape apartments for rent in Belgium?** Yes — set `transaction: "rent"` (and `propertyType: "apartment"` if you want flats only). For rentals, `priceEur` is the monthly rent.

**Can I search for building land, garages or offices?** Yes — `propertyType` also accepts `land`, `garage` and `office` besides houses and apartments.

**How do I limit the search to Brussels or one city?** Put its postal codes in `postalCodes`, e.g. `"1000,1050"` for central Brussels and Ixelles. An empty value searches the whole country.

**Can I filter by number of bedrooms?** `bedroomsMin` sets a floor. There is no maximum-bedrooms input — if you need a ceiling, filter the exported dataset on the `bedrooms` field.

**How do I know how old a listing is?** `createdAt` and `updatedAt` are ISO timestamps straight from the site, and the `flag` field marks fresh listings as `new`.

**Does it flag public sales?** Yes — the `publicSale` boolean marks them, so auctions-by-court are easy to include or exclude.

**What does Immoweb data cost through this actor?** $1.99 per 1,000 listings delivered — roughly $0.20 for a 100-listing daily watch. No subscription, and runs that fail or return nothing are not billed.

**Why did I get only 25 listings?** Free Apify plans receive a 25-item sample per run, intended for evaluating the format. Full volumes need a paid plan.

**Is scraping Immoweb GDPR-compliant?** The output is designed for exactly that question: a fixed whitelist of fields means no seller identity, no street addresses and no coordinates ever enter your dataset — the standards the GDPR and the Belgian APD/GBA care about are met in the data itself.

**Do I need residential proxies?** No — default datacenter proxies suffice, since the actor only requests what Immoweb serves openly. No proxy surcharge.

**Can an AI tool query Immoweb through this actor?** Yes — via Apify's hosted MCP server, agents like Claude or Cursor can fill in the search, start the run and read the JSON back without glue code.

### Related scrapers

The same clean-output guarantee across Europe's biggest marketplaces:

- [2dehands / 2ememain Scraper](https://apify.com/lowlanddata/tweedehands-scraper) — Belgium's biggest classifieds site.
- [Rightmove Scraper](https://apify.com/lowlanddata/rightmove-scraper) — the UK's largest property portal.
- [Marktplaats.nl Scraper](https://apify.com/lowlanddata/marktplaats-scraper) — the Netherlands' biggest marketplace.

### Troubleshooting

The actor fails fast with the reason in the run's status message:

- **"priceMinEur must not be higher than priceMaxEur."** — swap the two values.
- **"postalCodes must be a comma-separated list of Belgian 4-digit codes."** — e.g. `1000,1050`.
- **"Immoweb blocked the run before any results could be fetched. This is usually temporary - retry in a few minutes."** — a temporary block on the first request; a retry usually lands on a clean proxy session.
- **Fewer items than requested on a free plan** — the 25-item free sample cap; run on a paid Apify plan for full results.

### Support

Found an issue or missing a field you need? Open an issue on the actor's **Issues tab** — reports get fixed, this actor is actively maintained.

Working well for you? A **rating on this page** takes ten seconds and helps other buyers find a privacy-clean option among the lookalikes — it is also the clearest signal of what we should build next.

# Actor input Schema

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

What kind of property to search: houses and apartments together (default), or one category.

## `transaction` (type: `string`):

Search properties for sale or for rent.

## `postalCodes` (type: `string`):

Comma-separated Belgian postal codes to search in, e.g. "1000,1050". Leave empty to search all of Belgium.

## `priceMinEur` (type: `integer`):

Only include listings priced at least this many euros. For rentals this is euros per month.

## `priceMaxEur` (type: `integer`):

Only include listings priced at most this many euros. For rentals this is euros per month.

## `bedroomsMin` (type: `integer`):

Only include properties with at least this many bedrooms.

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

Order of results: newest (best for monitoring), cheapest, most\_expensive, or relevance.

## `maxItems` (type: `integer`):

Stop after this many listings. Free-plan runs are capped at 25 items.

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

Proxy settings. Keep Apify proxy enabled.

## Actor input object example

```json
{
  "propertyType": "house-and-apartment",
  "transaction": "sale",
  "sortBy": "newest",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Scraped Immoweb listings, one JSON object per listing.

# 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 = {
    "propertyType": "house-and-apartment",
    "transaction": "sale",
    "sortBy": "newest",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/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 = {
    "propertyType": "house-and-apartment",
    "transaction": "sale",
    "sortBy": "newest",
    "maxItems": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/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 '{
  "propertyType": "house-and-apartment",
  "transaction": "sale",
  "sortBy": "newest",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/immoweb-scraper --silent --output-dataset

```

## MCP server setup

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