Woningmarktdashboard voor je gemeente
Eén pagina per gemeente met verkoopprijzen, WOZ-waarde, woningvoorraad, bouwjaren, woninggrootte en leefbaarheid, naast het landelijk gemiddelde. Alles uit open API's zonder sleutel.
geef_project("woningmarkt-dashboard")geef_bron("cbs-statline")geef_bron("pdok-bag")geef_bron("leefbaarometer")
Ik heb het project, de geteste aanroepen en de valkuilen. Ik bouw een dashboard met CBS StatLine, Basisregistratie Adressen en Gebouwen (BAG) en Leefbaarometer. Zo kan het eruitzien:
Dit bouw je zelf. Kopieer de prompt naar Claude, ChatGPT of Cursor, met de MCP-server aan, of volg de stappen hieronder.
Gemiddelde verkoopprijs
DelftNederlandDelft is ruim twee keer zo duur als in 2015.
Bouwjaar van de woningen
BAG · okt 2026 · 54.862- vóór 194521,4%
- 1945–7431,0%
- 1975–9425,0%
- 1995–1412,4%
- 2015+10,3%
Dit is een mockup, geen werkende versie, met de cijfers voor Delft uit onze proefdraai van 16 oktober 2026 en de CBS-prijsreeks 1995–2025, opgehaald op 17 oktober 2026. De MCP-server zet je aan met het adres op Voor AI.
Voor wie
Raadsleden en wethouders die het woningdebat willen onderbouwen, lokale journalisten, makelaars en kopers die gemeenten willen vergelijken, en studenten die een eerste dashboard met echte overheidsdata willen bouwen.
Wat je krijgt
Een dashboard dat voor één gemeente in een oogopslag laat zien hoe de woningmarkt ervoor staat. Proefdraai voor Delft (GM0503) op 16 oktober 2026: - Gemiddelde verkoopprijs van een bestaande koopwoning in 2025: 453.866 euro, tegen 479.527 euro in heel Nederland. In 2015 was dat in Delft 211.971 euro, dus ruim twee keer zo weinig. Delft staat op plek 205 van de 342 gemeenten; Blaricum is het duurst (1.105.604 euro), Kerkrade het goedkoopst (270.119 euro). - Gemiddelde WOZ-waarde op 1 januari 2026: 393.000 euro (voorlopig), een jaar eerder 352.000 euro. Landelijk 439.000 euro. In 2025: koopwoningen 488.000, corporatiewoningen 249.000, overige huur 311.000 euro. - Woningvoorraad op 1 januari 2026: 54.777 woningen, 3.282 meer dan op 1 januari 2021 (51.495). Gemiddelde oppervlakte 88 m², landelijk 120 m². - BAG, oktober 2026: 54.862 woningen in gebruik in de woonplaats Delft. 52,4% is gebouwd vóór 1975 (21,4% vóór 1945), 10,3% in 2015 of later. 43,9% is kleiner dan 75 m². - Leefbaarometer 2024: score 4,052, klasse 6 van 9, plek 318 van 342 gemeenten. De deelscore woningvoorraad (-0,049) trekt het meest omlaag. Het script haalt dit alles in ongeveer 17 seconden op; de BAG-tellingen kosten de meeste tijd.
Gemiddelde verkoopprijs van een bestaande koopwoning: 505 duizend euro in september 2026, 5,7 keer zo veel als in januari 1995
Gemiddelde verkoopprijs van een bestaande koopwoning, januari 1995 – september 2026, in duizend euro. Dat is het hoogste punt in de reeks.
Zo zou je kunnen starten7 stappen
- 1
Zoek de juiste CBS-tabellen in de catalogus
De CBS-catalogus noemt elke tabel met titel, periode en wijzigingsdatum. Filter op een woord in de titel en sluit stopgezette tabellen uit: er staan tientallen oude woningtabellen in (prijsindex 2010=100, 2015=100) die niet meer worden bijgewerkt. Voor dit dashboard heb je drie tabellen per gemeente nodig: 83625NED (gemiddelde verkoopprijzen, 1995 tot en met 2025), 85036NED (gemiddelde WOZ-waarde naar eigendom, vanaf 2019) en 85035NED (woningvoorraad en gemiddelde oppervlakte op 1 januari, vanaf 2021). Let op: de prijsindex per regio (85792NED) heeft alleen de vier grote steden als gemeente.
https://opendata.cbs.nl/ODataCatalog/Tables?$format=json&$filter=substringof('koopwoningen',Title) and Frequency ne 'Stopgezet'&$select=Identifier,Title,Modified,Period
{"odata.metadata":"https://opendata.cbs.nl/ODataCatalog/$metadata#Tables&$select=Identifier,Title,Modified,Period","value":[ {"Identifier":"85773NED","Title":"Bestaande koopwoningen; verkoopprijzen prijsindex 2020=100","Modified":"2026-09-22T06:30:00","Period":"januari 1995 - augustus 2026"}, {"Identifier":"85792NED","Title":"Bestaande koopwoningen; verkoopprijzen, prijsindex 2020=100, regio","Modified":"2026-07-22T06:30:00","Period":"1e kwartaal 1995 - 2e kwartaal 2026"}, ... {"Identifier":"83625NED","Title":"Bestaande koopwoningen; gemiddelde verkoopprijzen, regio","Modified":"2026-02-17T02:00:00","Period":"1995 t/m 2025"}]} - 2
Haal de gemiddelde verkoopprijs op, gemeente en Nederland
We gebruiken de nieuwere OData-v4-API van het CBS (datasets.cbs.nl). Daar hebben sleutels geen opvulspaties en heten de maten codes (M001534 = gemiddelde verkoopprijs, in euro; zie /MeasureCodes). Nederland heet NL01. De gemiddelde verkoopprijs is geen prijsindex: verkopen in een jaar veel grote huizen, dan stijgt het gemiddelde ook zonder dat huizen duurder worden. Het CBS zegt dat zelf in de tabeltoelichting. Toon hem daarom als 'wat er gemiddeld betaald is'.
https://datasets.cbs.nl/odata/v1/CBS/83625NED/Observations?$filter=RegioS eq 'GM0503' or RegioS eq 'NL01'&$orderby=Perioden desc&$top=4&$select=RegioS,Perioden,Value
{"@odata.context":"https://datasets.cbs.nl/odata/v1/CBS/83625NED/$metadata#Observations(RegioS,Perioden,Value)","value":[ {"Value":479527.0,"RegioS":"NL01","Perioden":"2025JJ00"}, {"Value":453866.0,"RegioS":"GM0503","Perioden":"2025JJ00"}, {"Value":450985.0,"RegioS":"NL01","Perioden":"2024JJ00"}, {"Value":409999.0,"RegioS":"GM0503","Perioden":"2024JJ00"}]} - 3
Voeg de WOZ-waarde toe, met de status van het jaar
Tabel 85036NED geeft de gemiddelde WOZ-waarde per 1 januari in duizenden euro's (393.0 = 393.000 euro). Eigendom T001132 is het totaal, 1014800 koopwoningen, A047047 corporatiewoningen, A047048 overige verhuurders. Het nieuwste jaar is voorlopig: haal de status uit /PeriodenCodes en zet hem in beeld. Volgens de tabeltoelichting komen de definitieve cijfers over 2026 begin november 2026. Bij de voorlopige cijfers van Delft stond alleen het totaal, nog niet de uitsplitsing naar eigendom.
https://datasets.cbs.nl/odata/v1/CBS/85036NED/Observations?$filter=RegioS eq 'GM0503' and Eigendom eq 'T001132'&$orderby=Perioden desc&$top=2&$select=Measure,Eigendom,RegioS,Perioden,Value
{"@odata.context":"https://datasets.cbs.nl/odata/v1/CBS/85036NED/$metadata#Observations(Measure,Eigendom,RegioS,Perioden,Value)","value":[ {"Measure":"M003039","Value":393.0,"Eigendom":"T001132","RegioS":"GM0503","Perioden":"2026JJ00"}, {"Measure":"M003039","Value":352.0,"Eigendom":"T001132","RegioS":"GM0503","Perioden":"2025JJ00"}]} - 4
Tel de woningvoorraad en de gemiddelde oppervlakte
Tabel 85035NED geeft per 1 januari twee maten in één antwoord: D002936 (beginstand woningvoorraad, aantal) en M002978 (gemiddelde oppervlakte, m²). Kies Woningtype T001100 en Woningkenmerk T001727 voor het totaal; A053381 geeft alleen nieuwbouw, ZW10290 en ZW10340 splitsen eengezins- en meergezinswoningen. De reeks begint pas in 2021. Filter in je code op Measure, want de twee maten staan door elkaar.
https://datasets.cbs.nl/odata/v1/CBS/85035NED/Observations?$filter=RegioS eq 'GM0503' and Woningtype eq 'T001100' and Woningkenmerk eq 'T001727'&$orderby=Perioden desc&$top=2&$select=Measure,RegioS,Perioden,Value
{"@odata.context":"https://datasets.cbs.nl/odata/v1/CBS/85035NED/$metadata#Observations(Measure,RegioS,Perioden,Value)","value":[ {"Measure":"D002936","Value":54777.0,"RegioS":"GM0503","Perioden":"2026JJ00"}, {"Measure":"M002978","Value":88.0,"RegioS":"GM0503","Perioden":"2026JJ00"}]} - 5
Tel woningen per bouwjaar en oppervlakte in de BAG
De BAG-WFS van PDOK kan tellen zonder data te sturen: resultType=hits geeft alleen numberMatched. Een woning is een verblijfsobject met 'woonfunctie' in gebruiksdoel (een kommalijst, dus PropertyIsLike) en status 'Verblijfsobject in gebruik'. Voeg per klasse een PropertyIsBetween op bouwjaar of oppervlakte toe. Met filter duurt een telling 2 tot 4 seconden, zonder filter rond 30 seconden. De BAG kent geen gemeentecode, alleen woonplaatsen: Delft is één woonplaats, maar veel gemeenten hebben er meerdere. De vijf bouwjaarklassen en de vijf oppervlakteklassen telden elk precies op tot 54.862.
https://service.pdok.nl/lv/bag/wfs/v2_0?service=WFS&version=2.0.0&request=GetFeature&typeNames=bag:verblijfsobject&resultType=hits&FILTER=<Filter><And><PropertyIsEqualTo><ValueReference>woonplaats</ValueReference><Literal>Delft</Literal></PropertyIsEqualTo><PropertyIsEqualTo><ValueReference>status</ValueReference><Literal>Verblijfsobject in gebruik</Literal></PropertyIsEqualTo><PropertyIsLike wildCard="*" singleChar="." escapeChar="!"><ValueReference>gebruiksdoel</ValueReference><Literal>*woonfunctie*</Literal></PropertyIsLike></And></Filter>
<?xml version='1.0' encoding="UTF-8" ?> <wfs:FeatureCollection xmlns:bag="http://bag.geonovum.nl" ... timeStamp="2026-10-16T21:39:56" numberMatched="54862" numberReturned="0"
- 6
Haal de leefbaarheidsscore van alle gemeenten op
De Leefbaarometer-WFS heeft per meting een gemeentelaag (gemeentescore24 = 2024). Vraag alleen de velden die je nodig hebt en laat geom weg, dan is het antwoord klein. Het veld id is de CBS-gemeentecode, dus je koppelt direct aan de CBS-tabellen. lbm is de score, kscore de klasse (1 tot 9, hoger is beter), afw de afwijking van het landelijk gemiddelde, won en onv zijn deelscores. Haal alle 342 gemeenten op als je een plek in de ranglijst wilt tonen. Gebruik JSON, geen CSV: 'Nuenen, Gerwen en Nederwetten' heeft een komma in de naam.
https://geo.leefbaarometer.nl/lbm3/ows?service=WFS&version=2.0.0&request=GetFeature&typeNames=lbm3:gemeentescore24&outputFormat=application/json&propertyName=id,name,lbm,afw,won,onv,kscore&cql_filter=id='GM0503'
{"type":"FeatureCollection","features":[{"type":"Feature","id":"gemeentescore24.fid-6ce20098_1a146a7d447_-7c93","geometry":null, "properties":{"id":"GM0503","name":"Delft","lbm":4.05173106759454,"afw":-0.0505337835491484,"onv":-0.0255306299775484, "won":-0.0491488887163183,"kscore":6},"bbox":[81743,442446.208,87703.775,449847.9507]}], "totalFeatures":1,"numberMatched":1,"numberReturned":1,"timeStamp":"2026-10-16T21:39:44.924Z","crs":null} - 7
Zet de gemeente naast de rest van Nederland
Een getal zegt pas iets naast een ander getal. Haal voor de ranglijst de verkoopprijs van alle gemeenten in één keer op. De regiodimensie bevat alle 728 gemeentecodes die ooit bestonden; in 2025 hebben er 342 een waarde, de rest is null. Filteren op Value kan niet (de API geeft een fout), dus gooi de lege waarden in je eigen code weg. Gemeentenamen haal je uit /RegioSCodes.
https://datasets.cbs.nl/odata/v1/CBS/83625NED/RegioSCodes?$filter=startswith(Identifier,'GM')&$select=Identifier,Title&$top=3
{"@odata.context":"https://datasets.cbs.nl/odata/v1/CBS/83625NED/$metadata#RegioSCodes(Identifier,Title)","value":[ {"Identifier":"GM1680","Title":"Aa en Hunze"}, {"Identifier":"GM0738","Title":"Aalburg"}, {"Identifier":"GM0358","Title":"Aalsmeer"}]}
Hoe de bronnen samenkomen
- CBS StatLineLeefbaarometervia
gemeentecode (GM0503); in de Leefbaarometer het veld idDe Leefbaarometer gebruikt dezelfde CBS-codes, dus prijs, WOZ en voorraad komen zonder vertaaltabel naast de leefbaarheidsscore. Beide gebruiken de gemeentelijke indeling van hun eigen jaar: na een herindeling verschijnen nieuwe codes.
- CBS StatLineBasisregistratie Adressen en Gebouwen (BAG)via
woonplaatsnaam (de BAG-WFS heeft geen gemeentecode)CBS telt de voorraad uit de BAG, dus de twee horen bijna gelijk te zijn: Delft had volgens CBS 54.777 woningen op 1 januari 2026 en volgens de BAG-WFS 54.862 woningen in gebruik in oktober 2026. Een groot verschil betekent dat je de verkeerde woonplaatsen telt. CBS telt ook woningen die buiten gebruik of in verbouwing zijn.
- Basisregistratie Adressen en Gebouwen (BAG)Leefbaarometervia
ligging (RD-coördinaten, EPSG:28992)Wil je dieper dan de gemeente, dan liggen BAG-objecten en Leefbaarometer-buurten en -rastercellen in hetzelfde coördinatenstelsel. Zo zet je bouwjaren naast de score per buurt.
Laat AI het bouwen
Plak deze prompt in Claude, ChatGPT, Cursor of Lovable. Hij noemt de echte endpoints, de koppelsleutels en de valkuilen, zodat de assistent meteen werkende code schrijft. Controleer de uitkomst altijd met de bron zelf.
Bouw een woningmarktdashboard (Next.js of één HTML-bestand met JavaScript) waarin ik een gemeente kies en zie: gemiddelde verkoopprijs door de jaren heen, gemiddelde WOZ-waarde, woningvoorraad en gemiddelde oppervlakte, woningen naar bouwjaar en oppervlakte, en de leefbaarheidsscore. Elk cijfer naast het landelijk gemiddelde en met de plek van de gemeente in de ranglijst van 342. Bronnen (alle drie open, geen sleutel, eerlijke User-Agent meesturen): 1. CBS OData v4, https://datasets.cbs.nl/odata/v1/CBS/<tabel>/Observations?$filter=... - 83625NED: gemiddelde verkoopprijs bestaande koopwoningen per jaar (1995 tot en met 2025), maat M001534, euro. - 85036NED: gemiddelde WOZ-waarde per 1 januari, maat M003039, in 1.000 euro (393.0 = 393.000 euro). Eigendom: T001132 totaal, 1014800 koop, A047047 corporatie, A047048 overige verhuur. - 85035NED: woningvoorraad per 1 januari (D002936, aantal) en gemiddelde oppervlakte (M002978, m²). Woningtype T001100 + Woningkenmerk T001727 = totaal. Reeks vanaf 2021. - Nederland heet NL01, gemeenten GM + 4 cijfers. Namen: /<tabel>/RegioSCodes. Status per jaar (Definitief/Voorlopig): /<tabel>/PeriodenCodes. Eenheden: /<tabel>/MeasureCodes. - Voorbeeld: https://datasets.cbs.nl/odata/v1/CBS/83625NED/Observations?$filter=RegioS eq 'GM0503' or RegioS eq 'NL01' 2. BAG via PDOK WFS: https://service.pdok.nl/lv/bag/wfs/v2_0, laag bag:verblijfsobject, met resultType=hits en een FES-filter in de parameter FILTER (XML, URL-gecodeerd). Velden: woonplaats, status, gebruiksdoel, bouwjaar, oppervlakte. 3. Leefbaarometer WFS: https://geo.leefbaarometer.nl/lbm3/ows?service=WFS&version=2.0.0&request=GetFeature&typeNames=lbm3:gemeentescore24&outputFormat=application/json&propertyName=id,name,lbm,afw,won,onv,kscore Valkuilen die je moet afvangen: - De gemiddelde verkoopprijs is geen prijsindex (andere huizen verkocht = ander gemiddelde). Noem het 'gemiddeld betaald'. De prijsindex per regio (85792NED) heeft alleen Amsterdam, Den Haag, Rotterdam en Utrecht als gemeente. - De regiodimensie heeft 728 gemeentecodes, ook opgeheven gemeenten. Neem alleen gemeenten met een waarde in het nieuwste jaar (342 in 2025). Filteren op Value geeft een fout: doe dat in je eigen code. - Het nieuwste WOZ-jaar is voorlopig (2026, definitief begin november 2026) en had bij Delft nog geen uitsplitsing naar eigendom. Toon de status en vang ontbrekende categorieën af. - In 85035NED staan twee maten door elkaar in dezelfde lijst: filter op Measure. - Gebruik je de oude OData v3 (opendata.cbs.nl/ODataApi/OData/<tabel>/TypedDataSet), dan zijn sleutels aangevuld met spaties tot de langste code in die dimensie: 'NL01 ' (twee spaties) maar 'GM0503' zonder. Zonder de juiste spaties krijg je een lege lijst zonder fout. Velden heten daar GemiddeldeVerkoopprijs_1, GemiddeldeWOZWaardeVanWoningen_1, BeginstandWoningvoorraad_1, GemiddeldeOppervlakte_2. Op 16 oktober 2026 gaf v3 's avonds een tijd lang HTTP 503 terwijl v4 werkte: bouw een nette foutmelding of een terugval. - BAG: een woning is een verblijfsobject met 'woonfunctie' in gebruiksdoel. Dat veld is een kommalijst (bijvoorbeeld 'woonfunctie,winkelfunctie'), dus PropertyIsLike met *woonfunctie*, geen PropertyIsEqualTo. Neem status 'Verblijfsobject in gebruik'. - BAG heeft geen gemeentecode, alleen woonplaatsen. Een gemeente heeft vaak meerdere woonplaatsen; tel die bij elkaar. Woonplaatsnamen zijn niet altijd de gewone naam: 'Bergen (NH)', 'Bergen L', 'Hengelo (Gld)'. Maak een lijst per gemeente of kies de woonplaatsen met de hand. - BAG-telling zonder filter duurt ongeveer 30 seconden, met filter 2 tot 4 seconden. Doe maximaal drie verzoeken tegelijk en cache de uitkomst een dag. - GetFeature zonder resultType=hits stuurt altijd de geometrie mee en maximaal 1.000 objecten per pagina: tel, haal niet alles op. - Leefbaarometer: id is de CBS-gemeentecode. Gebruik JSON, niet CSV (een gemeentenaam bevat een komma). De score is een modelschatting over 2024, gepubliceerd in juli 2026, elke twee jaar. - Vergelijk CBS-voorraad (1 januari) met de BAG-telling (vandaag) als controle: ze moeten binnen een paar procent liggen. Gewenste uitkomst: een gemeentekiezer, vijf kaarten met het cijfer, het landelijke cijfer en de plek in de ranglijst, een lijngrafiek van de verkoopprijs sinds 1995 (gemeente en Nederland), staafgrafieken voor bouwjaar en oppervlakte, en onder elk blok de bron, tabelcode en peildatum. Laat bij voorlopige cijfers een label 'voorlopig' zien.
Probeer het zelf
De kern van het project in een klein script. Nodig: Node 20+ (ingebouwde fetch), opslaan als woningmarkt.mjs en draaien met node woningmarkt.mjs. Getest op 2026-10-16; hieronder de echte uitvoer van die proefdraai.
// Woningmarkt van één gemeente: verkoopprijs, WOZ-waarde, voorraad (CBS), bouwjaar en oppervlakte (BAG), leefbaarheid.
// Draait met Node 20+ (ingebouwde fetch). Geen sleutels nodig. node woningmarkt.mjs
const UA = { "User-Agent": "mijn-woningdashboard/1.0 (+jij@voorbeeld.nl)" };
const GM = "GM0503"; // Delft; CBS-gemeentecode
const WOONPLAATS = "Delft"; // BAG kent woonplaatsen, geen gemeenten: kies de woonplaats(en) van jouw gemeente
const CBS = "https://datasets.cbs.nl/odata/v1/CBS";
async function cbs(tabel, filter) { // OData v4: sleutels zonder opvulspaties
const url = `${CBS}/${tabel}/Observations?$filter=${encodeURIComponent(filter)}`;
const r = await fetch(url, { headers: UA });
if (!r.ok) throw new Error(`${tabel}: HTTP ${r.status}`);
return (await r.json()).value;
}
async function status(tabel) { // per periode: Definitief, Voorlopig of null
const r = await (await fetch(`${CBS}/${tabel}/PeriodenCodes`, { headers: UA })).json();
return Object.fromEntries(r.value.map((p) => [p.Identifier.slice(0, 4), p.Status]));
}
const perJaar = (rijen) => Object.fromEntries(rijen.map((r) => [r.Perioden.slice(0, 4), r.Value]));
// 1. Gemiddelde verkoopprijs bestaande koopwoningen (83625NED), gemeente en Nederland
const prijs = perJaar(await cbs("83625NED", `RegioS eq '${GM}'`));
const prijsNL = perJaar(await cbs("83625NED", "RegioS eq 'NL01'"));
// 2. Gemiddelde WOZ-waarde, alle woningen (85036NED, Eigendom T001132 = totaal), in 1.000 euro
const woz = perJaar(await cbs("85036NED", `RegioS eq '${GM}' and Eigendom eq 'T001132'`));
// 3. Woningvoorraad op 1 januari (85035NED): D002936 = aantal, M002978 = gemiddelde oppervlakte
const vr = await cbs("85035NED", `RegioS eq '${GM}' and Woningtype eq 'T001100' and Woningkenmerk eq 'T001727'`);
const voorraad = perJaar(vr.filter((r) => r.Measure === "D002936"));
const wozStatus = await status("85036NED");
const j = Object.keys(prijs).at(-1), jw = Object.keys(woz).at(-1), jv = Object.keys(voorraad).at(-1);
const f = (n) => Math.round(n).toLocaleString("nl-NL");
console.log(`${GM} ${WOONPLAATS}`);
console.log(`Verkoopprijs ${j}: ${f(prijs[j])} euro (Nederland ${f(prijsNL[j])}), 2015: ${f(prijs["2015"])} euro`);
console.log(`WOZ-waarde ${jw}: ${f(woz[jw] * 1000)} euro (${wozStatus[jw].toLowerCase()}), ${jw - 1}: ${f(woz[jw - 1] * 1000)} euro`);
console.log(`Woningvoorraad 1 januari ${jv}: ${f(voorraad[jv])} woningen, 1 januari 2021: ${f(voorraad["2021"])}`);
// 4. BAG: woningen in gebruik naar bouwjaar en oppervlakte, geteld met resultType=hits (alleen een getal terug)
const BAG = "https://service.pdok.nl/lv/bag/wfs/v2_0";
const is = (v, w) => `<PropertyIsEqualTo><ValueReference>${v}</ValueReference><Literal>${w}</Literal></PropertyIsEqualTo>`;
const tussen = (v, a, b) => `<PropertyIsBetween><ValueReference>${v}</ValueReference><LowerBoundary><Literal>${a}</Literal></LowerBoundary><UpperBoundary><Literal>${b}</Literal></UpperBoundary></PropertyIsBetween>`;
const woning = is("woonplaats", WOONPLAATS) + is("status", "Verblijfsobject in gebruik") +
`<PropertyIsLike wildCard="*" singleChar="." escapeChar="!"><ValueReference>gebruiksdoel</ValueReference><Literal>*woonfunctie*</Literal></PropertyIsLike>`;
async function tel(extra = "") {
const p = new URLSearchParams({ service: "WFS", version: "2.0.0", request: "GetFeature", typeNames: "bag:verblijfsobject",
resultType: "hits", FILTER: `<Filter><And>${woning}${extra}</And></Filter>` });
const t = await (await fetch(`${BAG}?${p}`, { headers: UA })).text();
return Number(t.match(/numberMatched="(\d+)"/)[1]);
}
async function rustig(taken) { const uit = []; for (let i = 0; i < taken.length; i += 3) uit.push(...await Promise.all(taken.slice(i, i + 3).map((t) => t()))); return uit; }
const BOUWJAAR = [["voor 1945", 0, 1944], ["1945-1974", 1945, 1974], ["1975-1994", 1975, 1994], ["1995-2014", 1995, 2014], ["2015 en later", 2015, 2100]];
const OPP = [["tot 50 m2", 0, 49], ["50-74 m2", 50, 74], ["75-99 m2", 75, 99], ["100-149 m2", 100, 149], ["150 m2 of meer", 150, 1e6]];
const totaal = await tel();
const bj = await rustig(BOUWJAAR.map(([, a, b]) => () => tel(tussen("bouwjaar", a, b))));
const op = await rustig(OPP.map(([, a, b]) => () => tel(tussen("oppervlakte", a, b))));
const pct = (n) => `${(100 * n / totaal).toFixed(1).replace(".", ",")}%`;
console.log(`\nBAG, woningen in gebruik in woonplaats ${WOONPLAATS}: ${f(totaal)}`);
BOUWJAAR.forEach(([k], i) => console.log(` gebouwd ${k.padEnd(14)} ${f(bj[i]).padStart(7)} ${pct(bj[i])}`));
OPP.forEach(([k], i) => console.log(` ${k.padEnd(22)} ${f(op[i]).padStart(7)} ${pct(op[i])}`));
// 5. Leefbaarometer 2024, alle 342 gemeenten (JSON, niet CSV: sommige namen bevatten een komma)
const q = new URLSearchParams({ service: "WFS", version: "2.0.0", request: "GetFeature", typeNames: "lbm3:gemeentescore24",
outputFormat: "application/json", propertyName: "id,name,lbm,afw,won,onv,kscore" });
const gem = (await (await fetch(`https://geo.leefbaarometer.nl/lbm3/ows?${q}`, { headers: UA })).json()).features
.map((x) => x.properties).sort((a, b) => b.lbm - a.lbm);
const i = gem.findIndex((g) => g.id === GM), g = gem[i];
console.log(`\nLeefbaarometer 2024: score ${g.lbm.toFixed(3)}, klasse ${g.kscore} van 9, plek ${i + 1} van ${gem.length}`);
console.log(` afwijking van het landelijk gemiddelde ${g.afw.toFixed(3)}; deelscores woningvoorraad ${g.won.toFixed(3)}, overlast en onveiligheid ${g.onv.toFixed(3)}`);
GM0503 Delft Verkoopprijs 2025: 453.866 euro (Nederland 479.527), 2015: 211.971 euro WOZ-waarde 2026: 393.000 euro (voorlopig), 2025: 352.000 euro Woningvoorraad 1 januari 2026: 54.777 woningen, 1 januari 2021: 51.495 BAG, woningen in gebruik in woonplaats Delft: 54.862 gebouwd voor 1945 11.731 21,4% gebouwd 1945-1974 17.000 31,0% gebouwd 1975-1994 13.706 25,0% gebouwd 1995-2014 6.785 12,4% gebouwd 2015 en later 5.640 10,3% tot 50 m2 10.339 18,8% 50-74 m2 13.753 25,1% 75-99 m2 14.436 26,3% 100-149 m2 12.088 22,0% 150 m2 of meer 4.246 7,7% Leefbaarometer 2024: score 4.052, klasse 6 van 9, plek 318 van 342 afwijking van het landelijk gemiddelde -0.051; deelscores woningvoorraad -0.049, overlast en onveiligheid -0.026
Waar het misgaat
- De gemiddelde verkoopprijs (83625NED) is geen prijsontwikkeling: het is het gemiddelde van wat dat jaar verkocht is. Verkopen er meer grote huizen, dan stijgt het zonder dat iets duurder werd. Voor echte prijsontwikkeling is er de prijsindex (85792NED), maar die heeft alleen de vier grote steden als gemeente.
- CBS-regiocodes: de dimensie bevat 728 gemeentecodes, ook van opgeheven gemeenten (Aalburg). In 2025 hebben er 342 een waarde. Filteren op Value mag niet in de v4-API (fout 'The property Value cannot be used in the $filter query option'): gooi null-waarden zelf weg.
- Opvulspaties in de oude OData v3: sleutels worden aangevuld tot de langste code in die dimensie. In 83625NED is het 'NL01 ' (twee spaties) maar 'GM0503' zonder spaties; met spaties erachter krijg je een lege lijst. De v4-API (datasets.cbs.nl) heeft geen opvulspaties.
- Het nieuwste WOZ-jaar is voorlopig en kan nog categorieën missen: bij Delft stond voor 2026 alleen het totaal, niet koop of huur. Lees de status uit /PeriodenCodes en toon die. De definitieve WOZ-cijfers 2026 komen volgens het CBS begin november 2026.
- De BAG-WFS kent geen gemeente, alleen woonplaatsen, en de namen zijn niet altijd wat je verwacht: 'Bergen (NH)', 'Bergen L', 'Hengelo (Gld)' naast 'Hengelo'. Een gemeente met meerdere woonplaatsen tel je per woonplaats en dan op. Controleer altijd met de CBS-voorraad (54.777 tegen 54.862 voor Delft).
- gebruiksdoel in de BAG is een kommalijst: een woning boven een winkel heeft 'woonfunctie,winkelfunctie'. Tel met PropertyIsLike '*woonfunctie*', niet met gelijk-aan, anders mis je die woningen.
- BAG-WFS: zonder resultType=hits krijg je altijd de geometrie mee en maximaal 1.000 objecten per pagina; GetPropertyValue geeft numberMatched 'unknown'. Tellen met hits en een filter is veel sneller (2 tot 4 seconden) dan alles ophalen. Zonder filter duurt een telling ongeveer 30 seconden.
- Leefbaarometer als CSV lijkt makkelijk, maar 'Nuenen, Gerwen en Nederwetten' heeft een komma in de naam en de regels eindigen op CRLF. Met een simpele split op komma's schuiven de kolommen en klopt je ranglijst niet meer. Neem outputFormat=application/json.
Verder bouwen
- Kaart van alle gemeenten: koppel de verkoopprijs 2025 aan de gemeentegrenzen van PDOK (pdok-wijkenbuurten) of aan de Leefbaarometer-laag met geometrie, en kleur naar prijs of naar prijs gedeeld door WOZ-waarde.
- Per buurt: de Leefbaarometer heeft buurtscore24 met de CBS-buurtcode, en de BAG kun je met een BBOX- of Within-filter per buurt tellen. Zo zie je welke buurten oud en klein gebouwd zijn en hoe ze scoren.
- Nieuwbouwteller: tel in de BAG panden met status 'Bouw gestart' of 'Bouwvergunning verleend' per woonplaats en zet dat naast de groei van de CBS-voorraad (Woningkenmerk A053381 = nieuwbouw).
- Maandelijkse markt: de landelijke prijsindex per maand (85773NED, tot en met augustus 2026) als extra lijn, met een melding als de nieuwe maand binnen is.
Meer met deze data
Gemiddelde WOZ-waarde van een woning: het hoogst in Bloemendaal (900 duizend euro), het laagst in Pekela en 1 andere gemeente (199 duizend euro)
Gemiddelde WOZ-waarde van een woning per gemeente, 2024, in duizend euro. Heel Nederland: 378. 342 gemeenten met een cijfer.
Woningen in Nederland: 8,35 miljoen in 2025, 5,6 keer zo veel als in 1921
Woningen in Nederland, 1921 – 2025, in miljoen. Dat is het hoogste punt in de reeks.
Panden naar bouwjaar (alleen wat er nu staat): 104.301 panden in 2025, 3% meer dan in 2005
Panden naar bouwjaar (alleen wat er nu staat), 2005 – 2025, in panden. Het hoogste punt was 2021 (184.232). Cijfers met * zijn voorlopig.
Leefbaarheidsscore (Leefbaarometer): het hoogst in Vlieland (4,47 punten), het laagst in Roosendaal (3,97 punten)
Leefbaarheidsscore (Leefbaarometer) per gemeente, 2024, in punten op de Leefbaarometer-schaal. Heel Nederland: 4,10. 342 gemeenten met een cijfer.
De bronnen3

CBS StatLine
De statistiekendatabank van het CBS: bijna 6.000 tabellen over bevolking, economie, werk, wonen, energie, zorg en meer, de meeste met lange reeksen per jaar, kwartaal of maand.

Basisregistratie Adressen en Gebouwen (BAG)
Alle adressen en gebouwen van Nederland met bouwjaar, oppervlakte en gebruiksdoel. De ruggengraat voor alles wat op adresniveau gekoppeld moet worden.

Leefbaarometer
Een schatting van hoe prettig het wonen is, voor elk bewoond vierkant van 100 bij 100 meter in Nederland, en opgeteld per buurt, wijk, postcodegebied en gemeente. Het model gebruikt 45 kenmerken van de woonomgeving (94 onderliggende variabelen), zoals voorzieningen, geluid en onveiligheid. Metingen voor 2002 tot en met 2024, met vijf deelscores.
Meer om te bouwen
Aardbevingentracker: elke beving op de kaart, met gemeente en woningenKaart
Buurtmonitor veiligheid: overlast en misdrijven per buurtDashboard
Dashboard asielopvang: landelijk en per gemeenteDashboard
Hoe snel rijdt jouw gemeente elektrisch?Analyse
Klimaatrisico-check voor een adresTool
Monitor voor inflatie, hypotheekrente en spaarrenteDashboard