# Immoweb Agency Scraper: Belgian Real Estate Agencies (`studioxl/immoweb-agency-scraper`) Actor

Every Belgian real estate agency on Immoweb.be as a lead list: the agency's own email (not the lead-form relay), phone, website, VAT and IPI numbers, address, opening hours and portfolio size. Add each agency's listings and what it recently sold or let.

- **URL**: https://apify.com/studioxl/immoweb-agency-scraper.md
- **Developed by:** [Kamil Ertekin](https://apify.com/studioxl) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 agencies

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 Agency Scraper: Belgian Real Estate Agencies

Get a clean list of Belgian real estate agencies from Immoweb.be, Belgium's main property portal. Type a postal code or province (or "Belgium") and you get one row per agency: its own email, phone, website, VAT and IPI numbers, office address, opening hours and how many properties it has for sale and for rent. It's built for B2B sales teams, proptech companies and anyone mapping the Belgian agency market.

### What you get

58 columns per agency. Fill rates were measured on all 444 agencies in Brussels.

| Field | Example | Notes |
|---|---|---|
| `name`, `url`, `id` | RealtyCare, immoweb.be/en/agency/realtycare/1796013 | Every row |
| `email` | ot@realtycare.be | The agency's own address (91%). See the FAQ |
| `leadEmail` | storage5928_169@importfrommedia.be | Lead-form inbox, if the agency uses one (50%) |
| `emails` | \[ ... ] | Every address found |
| `phone`, `mobile`, `fax` | +3224505656 | International format. 95% have a phone or mobile |
| `website` | https://www.realtycare.be/ | 57% |
| `vatNumber` | BE 0859.855.906 | Belgian company number, 100% |
| `ipiNumber` | 503442 | Estate-agent licence number (IPI/BIV), 99% |
| `street`, `streetNumber`, `box`, `postalCode`, `locality`, `province`, `region` | Avenue Louise, 409, 1050, Ixelles, Brussels, Brussels | `region` is Brussels, Flanders or Wallonia |
| `latitude`, `longitude` | 50.8343, 4.3569 | Office location, 100% |
| `forSaleActive`, `forRentActive` | 23, 42 | Properties online now |
| `forSaleSold`, `forRentLet` | 25, 127 | Recently sold and let |
| `activeHouses`, `activeApartments`, `activeCommercial`, `activeOffices`, `activeLand` ... | 12, 40, 4 | Portfolio by property type |
| `newListingsCount` | 20 | New listings this week |
| `hoursMonday` ... `hoursSunday` | 09:30-12:30, 14:00-17:30 | "Closed" on closed days. Empty when the agency published no hours (64% did) |
| `description`, `descriptionNl`, `descriptionFr` | ... | Agency presentation text (60%) |
| `rating`, `reviewCount` | ... | Immoreviews score and number of reviews, where shown (6%) |

Columns are the same on every row, so CSV and Excel exports line up. A value Immoweb doesn't show is left empty.

### How to use it

1. Type one or more postal codes or provinces into **Provinces or postal codes**, for example `1000`, `9000` or `Antwerp`.
2. Set **Maximum agencies**. The run stops there, so it also caps what you pay.
3. Click **Start**. Download the table as CSV, Excel or JSON from the **Output** tab.

This input works as-is and returns 10 agencies in central Brussels in under a minute:

```json
{
  "locations": ["1000"],
  "maxItems": 10
}
```

Every agency in a whole province, with each one's listings:

```json
{
  "locations": ["Antwerp"],
  "maxItems": 0,
  "includeListings": true
}
```

### Input

| Field | What it does |
|---|---|
| **Provinces or postal codes** (`locations`) | A province in English, French or Dutch ("Antwerp", "Luik", "Brabant wallon"), a 4-digit postal code ("9000"), a region ("Flanders", "Wallonia"), or "Belgium" for every agency. Text like "B-1050 Ixelles" works too. |
| **Agency pages or IDs** (`startUrls`) | Optional. Specific agencies, as an immoweb.be agency link in any language or just the ID (`3150337`). These come first. |
| **Maximum agencies** (`maxItems`) | Stop after this many. 0 means no limit. |
| **Full agency profile** (`scrapeDetails`) | On by default. Turn off for a quicker list without email or portfolio split. |
| **Add their listings** (`includeListings`) | Every property each agency has online, in a second table. |
| **Add recent sales and lettings** (`includeSoldOrRented`) | What each agency recently sold or let. |
| **Minimum active listings** (`minListings`) | Under More options. Skips small offices, for example 10. |

Postal codes beat town names. Immoweb reads "Gent" as the whole Ghent district, while `9000` is the city. A town name on its own is skipped with a hint in the log.

Useful codes: Brussels 1000 to 1210 (1050 Ixelles, 1180 Uccle), Antwerp 2000, Leuven 3000, Liège 4000, Namur 5000, Charleroi 6000, Bruges 8000, Ghent 9000.

### Output example

```json
{
  "id": "1796013",
  "url": "https://www.immoweb.be/en/agency/realtycare/1796013",
  "name": "RealtyCare",
  "isGroup": false,
  "vatNumber": "BE 0859.855.906",
  "ipiNumber": "503442",
  "website": "https://www.realtycare.be/",
  "email": "ot@realtycare.be",
  "leadEmail": "storage5928_169@importfrommedia.be",
  "phone": "+3224505656",
  "address": "Avenue Louise 409",
  "street": "Avenue Louise",
  "streetNumber": "409",
  "postalCode": "1050",
  "locality": "Ixelles",
  "province": "Brussels",
  "region": "Brussels",
  "latitude": 50.83433496833431,
  "longitude": 4.356907945660585,
  "listingsTotal": 217,
  "forSaleActive": 23,
  "forRentActive": 42,
  "forSaleSold": 25,
  "forRentLet": 127,
  "newListingsCount": 20,
  "activeApartments": 40,
  "activeHouses": 12,
  "activeCommercial": 4,
  "hoursMonday": "09:30-18:00",
  "hoursSaturday": "11:00-12:30",
  "profileScraped": true
}
```

Listing rows (when you add them) have price, property type, bedrooms, living area, address, GPS and photos, plus `agencyId`, `agencyName` and `listingStatus` (`active` or `soldOrRented`). They're the same columns as the search rows of the [Immoweb Scraper](https://apify.com/studioxl/immoweb-scraper).

### Pricing

You pay per row delivered. There's no start fee.

| Apify plan | Agency, per 1,000 | Listing or sold/let property, per 1,000 |
|---|---:|---:|
| Free | $8.00 | $1.00 |
| Starter (Bronze) | $7.00 | $0.90 |
| Scale (Silver) | $6.00 | $0.80 |
| Business (Gold) and higher | $5.00 | $0.70 |

Examples on the Free plan:

- The 10-agency test above costs $0.08.
- Every agency in Brussels (about 444) costs about $3.55. Adding their 9,950 active listings brings it to about $13.50.
- Every agency in Belgium (about 3,200) costs about $26, or about $16 on the Business plan.

Every agency row is charged at the same price, with or without the full profile. Not charged: duplicates, group brands you didn't ask for, unknown places, agencies that have left Immoweb and inputs that can't be used.

### FAQ

**Why is `email` different from the first address on Immoweb?**
Half of Belgian agencies show a lead-form address first (for example `...@importfrommedia.be`). Mail sent there arrives as a web lead, not in someone's inbox. You get the agency's own address in `email`, preferring one on its website domain, and the lead-form address in `leadEmail`.

**What is an IPI number?**
The licence number every Belgian estate agent must hold (IPI in French, BIV in Dutch). It's handy for checking an agency or matching records in your CRM.

**Will I get duplicates if my places overlap?**
No. An agency found under two postal codes, or pasted twice in different languages, is delivered and charged once.

**Why are some big brands missing?**
Umbrella brands such as Dewaele or Heylen Vastgoed have no office or contact details of their own. Their offices are listed one by one. Switch on **Include group brands** under More options to get the brand rows too.

**How fresh is the data, and can I schedule it?**
Each run reads Immoweb at that moment. Schedule the task in Apify (weekly, for example) and send the results to Google Sheets, HubSpot, Make, Zapier or your own system through the Apify API. With listings on, the run's `OUTPUT` record holds the listings table's ID.

**Can I use these contacts for marketing?**
This is business contact data that agencies publish themselves, but some agencies list a named person's address. Under GDPR and Belgian direct-marketing rules, you're responsible for how you use it.

### Limits

- Belgian agencies listed on Immoweb only, about 3,200 in all.
- Without the full profile there's no email and no portfolio split.
- Immoweb doesn't show the price of sold or let properties.
- Opening hours and descriptions appear only when the agency filled them in.
- Group brands have only a name, logo and listing count.

### Related

- [Immoweb Scraper](https://apify.com/studioxl/immoweb-scraper): every Belgian property listing with price, EPC energy score, cadastral income and photos.

# Changelog

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

# Actor input Schema

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

Get every real estate agency in these places. Use a province in English, French or Dutch ("Antwerp", "Liège") or a 4-digit postal code ("9000" for Ghent). Type "Belgium" for the whole country.

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

Optional. Paste agency pages from immoweb.be in any language, for example https://www.immoweb.be/en/agency/century-21-connect/3150337, or just the ID (3150337). These are collected first.

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

The run stops after this many agencies, so it also caps what you pay. 0 means no limit.

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

Adds the agency's own email, portfolio by property type, recently sold and let counts and reviews. Turn off for a quicker list without email.

## `includeListings` (type: `boolean`):

Every property each agency has online, with price, address, size and agencyId.

## `includeSoldOrRented` (type: `boolean`):

Properties the agency recently sold or let, marked listingStatus "soldOrRented". Immoweb doesn't show their price.

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

Which listings to keep when you add them.

## `maxListingsPerAgency` (type: `integer`):

Keep at most this many listings from each agency. 0 means all of them (the biggest agencies have close to 2,000).

## `minListings` (type: `integer`):

Leave out agencies with fewer listings online, for example 10 to skip very small offices. Agencies you paste by URL or ID are always kept. 0 keeps everyone.

## `maxItemsPerLocation` (type: `integer`):

Cap each province or postal code separately, so one busy area doesn't use up the whole run. 0 means no limit.

## `includeGroups` (type: `boolean`):

Also return umbrella brands such as Dewaele or Heylen Vastgoed. They have only a name, logo and listing count. Their offices are returned either way.

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

Leave as is. The default works on every Apify plan.

## Actor input object example

```json
{
  "locations": [
    "Antwerp",
    "9000"
  ],
  "maxItems": 10,
  "scrapeDetails": true,
  "includeListings": false,
  "includeSoldOrRented": false,
  "listingType": "all",
  "maxListingsPerAgency": 0,
  "minListings": 0,
  "maxItemsPerLocation": 0,
  "includeGroups": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `agencies` (type: `string`):

No description

## `portfolio` (type: `string`):

No description

## `contact` (type: `string`):

No description

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "locations": [
        "1000"
    ],
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studioxl/immoweb-agency-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 = {
    "locations": ["1000"],
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("studioxl/immoweb-agency-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 '{
  "locations": [
    "1000"
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call studioxl/immoweb-agency-scraper --silent --output-dataset

```

## MCP server setup

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