# Dutch Housing Figures by Municipality (`vizellie/nl-housing-figures-cbs`) Actor

Average sale price, house price index, WOZ value and rent increase for Dutch municipalities, from CBS open data. One row per municipality, measure and period, with the CBS licence on each row. $0.001 per figure.

- **URL**: https://apify.com/vizellie/nl-housing-figures-cbs.md
- **Developed by:** [Vi Zellie](https://apify.com/vizellie) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 housing figures

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

## Dutch housing figures by municipality

Average sale price, house price index, WOZ value and rent increase for Dutch municipalities. Each figure is one row: municipality, period, measure, value, unit, the CBS table id, and the attribution.

Source: CBS. Licence: CC BY 4.0. Figures selected and units converted.

Not legal, tax or investment advice. General information only.

### Who it is for

Property investors, relocation and expat services, journalists and agencies who want a repeatable table of official municipal figures for a market note, a client brief or a monthly check.

### What you get

- The average sale price of existing owner-occupied homes, for every municipality CBS publishes.
- The house price index, where CBS publishes it for a municipality. That is quarterly, and today it covers Amsterdam, The Hague, Rotterdam and Utrecht.
- The average WOZ value of dwellings on 1 January, in euro.
- The average rent increase, including harmonisation, for the municipalities CBS publishes. Today that is the same four cities. You can also ask for the increase excluding harmonisation.
- One row per municipality, measure and period. The unit, the CBS table id and the attribution are on the row.
- A municipality list, a year or quarter range, and the measures you want. Leave the municipality list empty for all of them.
- A clear note in the run summary when a measure is missing. Figures from the measures that did respond are still saved. If CBS stops a table, the run summary says so.

The average sale price is the average amount paid for homes sold in that period. The mix of homes changes it. The house price index is the measure of price change. Use the index when you want the change, and the average when you want what was paid.

CBS publishes the WOZ average in thousands of euro. The value in the row is the euro amount, so 575 in the publication is 575000 here. A `flag` of `provisional` means CBS still marks that period as preliminary. The newest WOZ year is often preliminary.

The Hague is stored as 's-Gravenhage, which is the municipality name CBS uses. `Den Haag` and `The Hague` in the input select that same municipality.

### Tutorial

1. Leave **Measures** on the average sale price, the house price index, the WOZ value and the rent increase. Add the rent increase excluding harmonisation if you want that as well.
2. Leave **Municipalities** empty for every municipality. Or set the places you follow, for example `Amsterdam`, `GM0599` and `Den Haag`.
3. Leave **Start period** and **End period** empty to keep the latest period of each measure (**Latest periods**, default 1). Or set a range, such as `2024` to `2025`, or `2026-Q1` to `2026-Q3`. A year includes every quarter of the house price index in that year.
4. Run the Actor. The dataset has one row per figure. The `OUTPUT` record says how many rows were saved and whether anything was left out.
5. Schedule a task if you want this after CBS publishes the next year or quarter. Rows that were not saved are not charged.

A default run is the latest period of each of the four measures. Sale prices and WOZ values cover about 340 municipalities. The index and the rent increase cover four. That is about 690 rows. See Pricing.

### Example input

```json
{
  "municipalities": ["Amsterdam", "Den Haag"],
  "measures": ["averageSalePrice", "priceIndex", "wozValue", "rentIncrease"],
  "startPeriod": "2025",
  "endPeriod": "2026-Q3"
}
```

### Example output

```json
{
  "municipality": "Amsterdam",
  "municipalityCode": "GM0363",
  "period": "2025",
  "frequency": "annual",
  "measure": "averageSalePrice",
  "measureName": "Average sale price",
  "value": 630621,
  "unit": "euro",
  "unitDetail": "Average amount paid for existing owner-occupied dwellings sold in the period",
  "tableId": "83625NED",
  "source": "CBS",
  "licence": "CC BY 4.0",
  "attribution": "Source: CBS. Licence: CC BY 4.0. Figures selected and units converted."
}
```

```json
{
  "municipality": "Amsterdam",
  "municipalityCode": "GM0363",
  "period": "2026",
  "frequency": "annual",
  "measure": "wozValue",
  "measureName": "WOZ value",
  "value": 575000,
  "unit": "euro",
  "unitDetail": "Average WOZ value of dwellings on 1 January",
  "tableId": "85036NED",
  "flag": "provisional",
  "source": "CBS",
  "licence": "CC BY 4.0",
  "attribution": "Source: CBS. Licence: CC BY 4.0. Figures selected and units converted."
}
```

```json
{
  "municipality": "Amsterdam",
  "municipalityCode": "GM0363",
  "period": "2026-Q3",
  "frequency": "quarterly",
  "measure": "priceIndex",
  "measureName": "House price index",
  "value": 135.4,
  "unit": "index",
  "unitDetail": "Price index of existing owner-occupied dwellings, 2020 = 100",
  "tableId": "85792NED",
  "source": "CBS",
  "licence": "CC BY 4.0",
  "attribution": "Source: CBS. Licence: CC BY 4.0. Figures selected and units converted."
}
```

Periods look like `2025` for a year and `2026-Q3` for a quarter. Empty cells are left out. They are not filled in.

### Pricing

You pay a small fee when the run starts, then a fee for each figure that is saved. One figure is one municipality, one measure and one period.

| What | Price |
|---|---|
| Run start | $0.00005 |
| Housing figure | $0.001 |

Missing cells, municipalities CBS does not publish, failed reads, and rows past **Max rows** are not charged. You are not charged a second time for the same saved row.

**Examples**

- Amsterdam, The Hague, Rotterdam and Utrecht, latest period, four measures: 16 x $0.001 = **$0.016**, plus the $0.00005 start fee. A single city that has all four measures is 4 x $0.001 = **$0.004**, plus the start fee.
- The defaults, every municipality, latest period, four measures: about 690 x $0.001 = **$0.69**, plus the start fee.
- A run that hits the default cap of 2,000 rows: 2,000 x $0.001 = **$2.00**, plus the start fee.
- A run that saves nothing: **$0.00005**.

Use **Max rows** and the maximum cost per run to cap a single run. The pricing tab on the store is the price you are charged if it ever differs.

### Scheduling and integrations

Save a task and schedule it when you want a fresh file, for example after the annual sale prices or the quarterly index. Keep the same municipalities and measures so each file has the same shape. The dataset can go to Google Sheets, Slack, email, Make or Zapier, or you can read it from the Apify API. The rows are small enough to pass to an AI agent over MCP.

### No personal data

This Actor does not collect personal data.

- It reads published municipal aggregates only. It does not request addresses, property identifiers or person-level records.
- A municipality name in the dataset is the official name of that municipality. An entry that is not recognised is left out. The summary gives only the count, for example 2 entries were not recognised as a municipality, and it does not repeat what you typed.
- Raw responses are not stored.
- Logs, the status message and the failure message do not include the address that was called, or the text of an entry that was not recognised.

### FAQ

**Why does the average sale price move differently from the house price index?**
The average is the mean amount paid for the homes that happened to sell. A year with more expensive homes in the mix can lift the average. The index follows the price of the stock of existing owner-occupied homes. CBS publishes that municipal index for Amsterdam, The Hague, Rotterdam and Utrecht.

**Why is a municipality missing?**
CBS leaves the cell empty when it does not publish a figure, for example when few homes were sold. A municipality that no longer exists has figures only for the years it did. The house price index and the rent increase are published for a short list of municipalities, not for every one.

**Why is The Hague called 's-Gravenhage?**
That is the name CBS uses for the municipality. `Den Haag` and `The Hague` in the input select the code GM0518. Two municipalities that share a name, such as Bergen, need the code.

**Where do the figures come from?**
Statistics Netherlands (CBS) open data, under the Creative Commons Attribution 4.0 licence. Reuse a figure with the attribution on the row: Source: CBS. Licence: CC BY 4.0. Figures selected and units converted. This Actor is not affiliated with CBS and does not use the CBS logo. Figures can be revised. A provisional flag is kept when CBS marks the period as preliminary. The sale price and the house price index are compiled from land registry transactions. The WOZ value is converted from the thousands of euro CBS publishes.

### Next additions

- More of the same kind.
- Broader coverage.
- Small follow-ups later.

### Feedback

Missing a municipality or a measure? Open an issue on the Actor's Issues tab.

# Actor input Schema

## `municipalities` (type: `array`):

Municipality names or codes, for example Amsterdam, GM0599 or Den Haag. Den Haag and The Hague select 's-Gravenhage. Leave the list empty for every municipality.

## `measures` (type: `array`):

Figures to return. The house price index and the rent increase are published for some municipalities only. The other municipalities are left out for those measures.

## `startPeriod` (type: `string`):

First period to keep, inclusive. Use a year such as 2024, or a quarter such as 2026-Q2. Leave empty to take the latest periods. A year keeps every quarter of the house price index in that year.

## `endPeriod` (type: `string`):

Last period to keep, inclusive. Same shapes as the start period. An end in the future is brought back to the current period.

## `lastPeriods` (type: `integer`):

How many newest periods to keep for each measure, when start and end are empty. From 1 to 40. Default 1. The house price index is quarterly. The other measures are yearly.

## `maxRows` (type: `integer`):

Most rows saved in one run, from 1 to 20000. The newest periods are kept. Default 2000.

## Actor input object example

```json
{
  "municipalities": [
    "Amsterdam",
    "Rotterdam"
  ],
  "measures": [
    "averageSalePrice",
    "priceIndex",
    "wozValue",
    "rentIncrease"
  ],
  "startPeriod": "2024",
  "endPeriod": "2025",
  "lastPeriods": 1,
  "maxRows": 2000
}
```

# Actor output Schema

## `figures` (type: `string`):

One row per municipality, period and measure, with the unit, the table id and the CBS attribution.

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

The OUTPUT record in the default key-value store.

# 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 = {
    "measures": [
        "averageSalePrice",
        "priceIndex",
        "wozValue",
        "rentIncrease"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vizellie/nl-housing-figures-cbs").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 = { "measures": [
        "averageSalePrice",
        "priceIndex",
        "wozValue",
        "rentIncrease",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vizellie/nl-housing-figures-cbs").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 '{
  "measures": [
    "averageSalePrice",
    "priceIndex",
    "wozValue",
    "rentIncrease"
  ]
}' |
apify call vizellie/nl-housing-figures-cbs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vizellie/nl-housing-figures-cbs"
        }
    }
}
```

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/4SAFchepsGdGZvYij/builds/KmaZArgHC1cADcL8R/openapi.json
