# Immoweb Commercial Scraper - Belgian Offices & Land (`studio-amba/immoweb-commercial-scraper`) Actor

Scrape commercial property listings from Immoweb.be, Belgium's largest real-estate portal: offices, commercial premises, industrial buildings and building land, for sale or rent. Prices, surfaces, locations, agency names.

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

## Pricing

from $1.20 / 1,000 result scrapeds

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/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 Commercial Scraper

Scrape commercial property listings from [Immoweb.be](https://www.immoweb.be), Belgium's largest real-estate portal. This actor covers the commercial side of the portal: offices (kantoor / bureau), commercial premises (handelszaak / commerce), industrial buildings and warehouses (industrie), land and building land (bouwgrond / terrain à bâtir), and garages. For sale and for rent.

Each result comes from the portal's own structured data feed, not from parsed page text. You get clean numbers: asking price or monthly rent, rent per m2 per year, price per m2 for sales, floor and plot surfaces, the full address with postal code, province and region, coordinates, the listing agency's name, and a direct link to the listing.

The portal carries roughly 2,400 offices, 6,600 commercial buildings, 3,500 industrial properties and well over 9,000 land listings for sale at any time, plus the rental side of each market.

### Why use it

- **Market research**: track asking prices and rents per municipality, province or segment across Belgium.
- **Investment screening**: building land (bouwgrond) is a strong Belgian investor niche; filter plots by location and compare price per m2.
- **Site selection**: compare office or retail rents across cities before committing to a location.
- **Lead generation**: every listing carries the agency name, so you can see who is active in a segment and where.
- **Monitoring**: run it on a schedule with sort order "Newest first" and diff against the previous dataset to catch new listings the day they appear.

### How to scrape Immoweb commercial data

1. Set **Location** to a Belgian city, district or province. Dutch, French and English spellings all work: `Gent`, `Gand`, `Antwerpen`, `Anvers`, `Liège`, `Luik`, `Brussel`, `Bruxelles`. A 4-digit postal code (`9000`) or a comma-separated list (`9000,9030`) also works. Leave it empty to scrape the whole country.
2. Pick a **Property Segment**: office, commercial premises, business (the broadest commercial category), industry, land, building land, or garage. "All commercial" runs offices, business, industry and land in one go.
3. Pick a **Listing Type**: for sale, for rent, or both.
4. Set **Max Results** and run. Results land in the dataset as one flat JSON object per listing.

Example: kantoren te huur in Gent (offices for rent in Ghent):

```json
{
    "searchQuery": "Gent",
    "segment": "office",
    "listingType": "rent",
    "maxResults": 200
}
```

Example: bouwgrond te koop in de provincie Antwerpen (building land for sale in the province of Antwerp):

```json
{
    "searchQuery": "Antwerpen",
    "segment": "building-land",
    "listingType": "sale",
    "maxResults": 500
}
```

Example: bureaux à louer à Liège (offices for rent in Liège, French spelling):

```json
{
    "searchQuery": "Liège",
    "segment": "office",
    "listingType": "rent",
    "maxResults": 100
}
```

An empty input `{}` works as well. It returns commercial listings for sale from all of Belgium, up to the default cap of 100.

#### How the location filter works

The actor resolves your location text through Immoweb's own location search, the same one behind the search box on the site. It takes the top suggestion, exactly as if you clicked the first entry in the dropdown. `Gent` resolves to the Gent district, `Antwerpen` to the Antwerp district, `9000` to that postal code. If the text cannot be resolved to a Belgian location, the run fails with a clear message instead of silently returning country-wide results.

### Input options

| Field | Type | Description |
|-------|------|-------------|
| `searchQuery` | string | Belgian city, district or province (NL, FR or EN spelling), or postal code(s). Empty = all of Belgium. |
| `segment` | string | `all-commercial` (default), `office`, `commercial-premises`, `business`, `industry`, `land`, `building-land`, `garage`. |
| `listingType` | string | `sale` (default), `rent`, or `all`. |
| `orderBy` | string | `relevance` (default) or `newest`. |
| `maxResults` | integer | Cap on total listings returned, across all selected segments. Default 100. Each segment and listing type combination can yield at most about 10,000 listings, which is the portal's own pagination ceiling. |
| `proxyConfiguration` | object | Belgian residential proxy by default. Immoweb blocks datacenter IPs. |

### Output fields

| Field | Example | Description |
|-------|---------|-------------|
| `id` | `21724601` | Immoweb classified id |
| `title` | `"Office space for rent along Kortrijksesteenweg"` | Listing headline |
| `segment` | `"office"` | Property type: office, commercial, industry, land, garage |
| `subtype` | `"offices"` | Immoweb subtype (office\_block, commercial\_premises, warehouse, building\_land, ...) |
| `listingType` | `"rent"` | sale or rent |
| `price` | `2805` | Sale: total asking price. Rent: monthly rent. Null when the price is on request |
| `currency` | `"EUR"` | Always EUR |
| `priceUnit` | `"EUR/month"` | `EUR total` for sales, `EUR/month` for rentals |
| `priceText` | `"€2,805 (+ €1,122)"` | Price exactly as Immoweb displays it |
| `monthlyCosts` | `1122` | Monthly charges on top of the rent |
| `yearlyRentPerSqm` | `110` | Rent in EUR per m2 per year, the standard commercial quote |
| `salePricePerSqm` | `142` | Price per m2 for sale listings |
| `surface` | `306` | Floor area in m2 (null for bare land) |
| `landSurface` | `850` | Plot area in m2 |
| `street`, `houseNumber` | `"Kortrijksesteenweg"`, `"88"` | Address |
| `postalCode`, `locality` | `"9830"`, `"Sint-Martens-Latem"` | Municipality |
| `district`, `province`, `region` | `"Gent"`, `"East Flanders"`, `"Flanders"` | Administrative location (English names) |
| `latitude`, `longitude` | `51.0124`, `3.6409` | Coordinates |
| `agencyName` | `"CD-Vastgoed"` | Listing agency |
| `imageUrl` | `"https://media-resize.immowebstatic.be/..."` | First listing photo |
| `publicationDate` | `"2026-07-30T13:58:39.007Z"` | Last modification date |
| `url` | `"https://www.immoweb.be/en/classified/21724601"` | Direct link to the listing |
| `source` | `"immoweb.be"` | Constant |
| `scrapedAt` | `"2026-08-18T12:00:00.000Z"` | Scrape timestamp |

### Example output

```json
{
    "id": 21724601,
    "title": "Office space for rent along Kortrijksesteenweg",
    "segment": "office",
    "subtype": "offices",
    "listingType": "rent",
    "price": 2805,
    "currency": "EUR",
    "priceUnit": "EUR/month",
    "priceText": "€2,805 (+ €1,122)",
    "priceLabel": "Requested monthly rental price",
    "monthlyCosts": 1122,
    "yearlyRentPerSqm": 110,
    "salePricePerSqm": null,
    "surface": 306,
    "landSurface": 306,
    "street": "Kortrijksesteenweg",
    "houseNumber": "88",
    "postalCode": "9830",
    "locality": "Sint-Martens-Latem",
    "district": "Gent",
    "province": "East Flanders",
    "region": "Flanders",
    "country": "Belgium",
    "latitude": 51.0124381,
    "longitude": 3.6408877,
    "agencyName": "CD-Vastgoed",
    "imageUrl": "https://media-resize.immowebstatic.be/classifieds/...jpg",
    "publicationDate": "2026-07-30T13:58:39.007Z",
    "url": "https://www.immoweb.be/en/classified/21724601",
    "source": "immoweb.be",
    "scrapedAt": "2026-08-18T12:00:00.000Z"
}
```

### Cost estimate

Pricing is per result: about $0.002 per listing plus a small per-run start fee, so roughly 500 listings per $1. One request to the portal returns 30 listings, so proxy and compute overhead stay low even on large runs.

Note that a run's usage cost only settles after the run reports SUCCEEDED. A cost read mid-run shows a partial number that can be far too low; wait for the run to finish before estimating spend from it.

### Limitations

- Prices marked "on request" by the seller are returned as `price: null` with the portal's wording in `priceText`. This is normal in commercial real estate; a meaningful share of offices and commercial premises list without a public price.
- `surface` is null for bare land; use `landSurface` for plots.
- Each segment and listing-type combination paginates up to about 10,000 listings, the portal's own ceiling. Narrow by location if you need a complete slice of a bigger market.
- Land for rent barely exists on the portal; a land + rent search will usually return nothing.
- Residential property (houses, apartments) is out of scope here. Use the Immoweb Scraper actor for those.

# Actor input Schema

## `searchQuery` (type: `string`):

Belgian city, district or province — Dutch, French or English spelling all work ('Gent', 'Gand', 'Antwerpen', 'Anvers', 'Liège', 'Luik'). A 4-digit postal code (or comma-separated list like '9000,9030') also works. Leave empty to search all of Belgium.

## `segment` (type: `string`):

Commercial property type as Immoweb defines them. 'Business (all commercial)' is the broadest commercial category (includes commercial premises and mixed-use buildings); 'Building land' (bouwgrond) is the plots-only subset of 'Land'. 'All commercial' runs offices + business + industry + land in one go.

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

For sale (te koop / à vendre), for rent (te huur / à louer), or both. Note: land for rent barely exists on Immoweb.

## `orderBy` (type: `string`):

How Immoweb orders results. 'Newest first' is the right choice for monitoring runs.

## `maxResults` (type: `integer`):

Maximum number of listings to return, counted across all selected segments. Each segment/listing-type combination can yield at most ~10,000 listings (the portal's own pagination ceiling).

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

Proxy settings. Immoweb blocks datacenter IPs — Belgian residential proxy is the reliable default (see docs/site-recon/immoweb-commercial.md).

## Actor input object example

```json
{
  "searchQuery": "Gent",
  "segment": "office",
  "listingType": "rent",
  "orderBy": "newest",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "BE"
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchQuery": "Gent",
    "segment": "office",
    "listingType": "rent",
    "orderBy": "newest",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "BE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/immoweb-commercial-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 = {
    "searchQuery": "Gent",
    "segment": "office",
    "listingType": "rent",
    "orderBy": "newest",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "BE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/immoweb-commercial-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 '{
  "searchQuery": "Gent",
  "segment": "office",
  "listingType": "rent",
  "orderBy": "newest",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "BE"
  }
}' |
apify call studio-amba/immoweb-commercial-scraper --silent --output-dataset

```

## MCP server setup

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