Klimaatrisico-check voor een adres
Typ een postcode en huisnummer en zie in één rapport hoe het pand ervoor staat bij hitte, wateroverlast, overstroming, droogte en funderingsproblemen, met de kaarten van de Klimaateffectatlas, het AHN, de BAG en echte grondwatermetingen uit de BRO.
geef_project("klimaatrisico-adres")geef_bron("klimaateffectatlas")geef_bron("pdok-bag")geef_bron("ahn")
Ik heb het project, de geteste aanroepen en de valkuilen. Ik bouw een tool met Klimaateffectatlas, Basisregistratie Adressen en Gebouwen (BAG), Actueel Hoogtebestand Nederland (AHN) en Basisregistratie Ondergrond (BRO). 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.
Klimaatrapport
Let op: modelkaarten en één meetput, geen keuring van het pand.
- Hitteper buurtGevoelstemperatuur; hitte-eiland +1,75 °CGevoelstemperatuurBuurt_202245,3 °Cextreme hittestress
- Overstroming> 20 cm waterKleine kans; dan 0,80 m waterplaatsgebonden_overstromingskans_huidig_20_cm_202511201/300tot 1/3.000 per jaar
- DroogtegrondwaterGemeten 12-03-2026; model zegt 3,04 mBRO GMW000000005707 · 32 m0,92 monder maaiveld
- Funderingper buurtBodem daalt 2,2 mm per jaarnl_bodemdaling_totaal_v20260623laagpaalrot 1,73 · zetting 2,47
- Wateroverlastrond het pandNa een hevige bui (99e percentiel)nl_fcab_omgevingsscore_wateroverlast_v202608060 cmgeen hinder
Dit is een mockup, geen werkende versie, met de waarden uit onze proefdraai van 16 oktober 2026 voor het stadhuis van Gouda; de kleur van elk stoplicht is onze lezing van de klasse uit de legenda. De MCP-server zet je aan met het adres op Voor AI.
Voor wie
Huizenkopers en huiseigenaren die willen weten waar ze op moeten letten, makelaars en taxateurs, gemeenten en woningcorporaties die hun bezit willen doorlichten, en journalisten die een straat of wijk willen vergelijken.
Wat je krijgt
Een tool die bij een adres één rapport maakt met vijf risico's. Het adres gaat via de BAG naar een punt, het AHN geeft de hoogte van de grond, de Klimaateffectatlas geeft per kaart de waarde op dat punt met de klasse uit zijn eigen legenda, en de BRO geeft de echte grondwaterstand in de dichtstbijzijnde put.
Proefdraai op 16 oktober 2026 met het stadhuis van Gouda (Markt 1, bouwjaar 1459). De grond rond het stadhuis ligt op -0,17 m NAP (mediaan van 11 AHN-punten). Hitte: de buurt Nieuwe Markt e.o. heeft een gemiddelde gevoelstemperatuur van 45,3 °C op de hittekaart (extreme hittestress) en een hitte-eiland van 1,75 °C. Wateroverlast rond het pand: 0 cm. Overstroming: kleine kans (1/300 tot 1/3.000 per jaar) op meer dan 20 cm water, en bij zo'n overstroming 0,80 m water. Fundering: paalrot laag (score 1,73 per buurt), verschilzetting in 2050 laag (2,47), de bodem daalt 2,2 mm per jaar en volgens het hoge scenario 4 cm tussen 2020 en 2050. Grondwater: put GMW000000005707 op 32 m stond op 12 maart 2026 op -0,74 m NAP, 0,92 m onder het maaiveld bij de put; in het jaar ervoor tussen -1,02 en -0,26 m NAP (38.716 uurmetingen sinds 2021).
Ter vergelijking het Rijksmuseum in Amsterdam (Museumstraat 1, bouwjaar 1885): grond op +2,14 m NAP, gevoelstemperatuur in de buurt Museumplein 47,0 °C, hitte-eiland 1,86 °C, 16 cm water rond het pand na een hevige bui (klasse middel), geen overstromingskansklasse en geen waterdiepte op de overstromingskaart, paalrot en verschilzetting zeer laag, bodembeweging -1,0 mm per jaar.
Het rapport laat ook zien waar model en meting uit elkaar lopen: het landelijke grondwatermodel zegt dat de laagste grondwaterstand in Gouda 3,04 m onder het maaiveld ligt, maar de put naast het stadhuis mat in het jaar tot 12 maart 2026 nooit dieper dan 1,20 m onder het maaiveld. Voor een pand telt de meting.
Berekende gevoelstemperatuur (PET) uit de hittekaart: het hoogst in Schiermonnikoog (47,7 °C), het laagst in Zeist (38,8 °C)
Berekende gevoelstemperatuur (PET) uit de hittekaart per gemeente, 2022, in graden Celsius. Heel Nederland: 43,5. 342 gemeenten met een cijfer.
Zo zou je kunnen starten7 stappen
- 1
1. Van adres naar punt (BAG-WFS)
Zoek het adres in de BAG-WFS van PDOK met een FES-filter op postcode en huisnummer. Je krijgt een punt in RD-coördinaten (EPSG:28992, in meters), het bouwjaar en de pandidentificatie. Met srsName=EPSG:4326 krijg je hetzelfde punt als lengte- en breedtegraad, nodig voor de BRO. Gebruik niet de PDOK Locatieserver: robots.txt van api.pdok.nl sluit /bzk/locatieserver/* uit; service.pdok.nl staat alles toe. Valkuil: bij nul treffers ontbreekt numberMatched in het antwoord, kijk dus naar de lijst features. En bij huisletters (12A, 12B) krijg je meer objecten.
https://service.pdok.nl/lv/bag/wfs/v2_0?service=WFS&version=2.0.0&request=GetFeature&typeNames=bag:verblijfsobject&outputFormat=application/json&filter=<Filter xmlns%3D"http%3A%2F%2Fwww.opengis.net%2Ffes%2F2.0"><And><PropertyIsEqualTo><ValueReference>postcode<%2FValueReference><Literal>2801JG<%2FLiteral><%2FPropertyIsEqualTo><PropertyIsEqualTo><ValueReference>huisnummer<%2FValueReference><Literal>1<%2FLiteral><%2FPropertyIsEqualTo><%2FAnd><%2FFilter>
"numberMatched": 1, "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::28992" } }, "features": [ { "type": "Feature", "properties": { "identificatie": "0513010013060645", "oppervlakte": 1311, "status": "Verbouwing verblijfsobject", "gebruiksdoel": "kantoorfunctie,bijeenkomstfunctie,overige gebruiksfunctie", "openbare_ruimte": "Markt", "huisnummer": 1, "postcode": "2801JG", "woonplaats": "Gouda", "bouwjaar": 1459, "pandidentificatie": "0513100011122752", "pandstatus": "Pand in gebruik" }, "geometry": { "type": "Point", "coordinates": [ 108540.066, 447234.648 ] } } - 2
2. De hoogte van de grond (AHN)
Vraag met WMS GetFeatureInfo op de laag dtm_05m van het AHN de hoogte ten opzichte van NAP. Gebruik een vak van 200 bij 200 meter met 200 pixels en klik met i en j. Valkuil: het BAG-punt ligt in het gebouw, en het maaiveldmodel heeft onder gebouwen geen waarde. Midden in het stadhuis (i=j=100) is de lijst leeg; 30 meter verderop (i=130) staat -0,24 m NAP. Neem daarom de mediaan van een ring punten rondom (het script gebruikt 16 punten op 30 en 60 meter). Dit is AHN4, ingewonnen in 2020 tot en met 2022.
https://service.pdok.nl/rws/ahn/wms/v1_0?service=WMS&version=1.3.0&request=GetFeatureInfo&layers=dtm_05m&query_layers=dtm_05m&styles=&crs=EPSG:28992&bbox=108440,447135,108640,447335&width=200&height=200&i=130&j=100&info_format=application/json
{"type":"FeatureCollection","features":[{"type":"Feature","bbox":[108568.75,447237.25,108568.75,447237.25], "geometry":{"type":"Point","coordinates":[108568.75,447237.25]},"properties":{"value_list":"-0.2389999926"}}], ...} met i=100&j=100 (midden in het stadhuis): {"type":"FeatureCollection","features":[],"crs":{"properties":{"name":"urn:ogc:def:crs:EPSG::28992"},"type":"name"}} - 3
3. Kies de juiste kaartversie (GetCapabilities)
De WMS van de Klimaateffectatlas (GeoServer bij Sogelink, geen sleutel, 185 lagen) heeft laagnamen met een versiedatum, en oude versies blijven naast de nieuwe staan. Haal GetCapabilities op (538 kB), zoek de namen met hetzelfde begin en neem de hoogste datum op het eind (_20260128 boven _20251219; een naam zonder datum telt als oudste). Zet de gekozen laagnaam in je rapport, dan weet de lezer welke kaart het was. De lagen hebben geen omschrijving in de dienst; de uitleg staat op klimaateffectatlas.nl.
https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public/wms?service=WMS&request=GetCapabilities&version=1.3.0
<Name>maximale_waterdiepte_nederland_kleine_kans_20251219</Name> <Name>maximale_waterdiepte_nederland_kleine_kans_20260128</Name> <Name>plaatsgebonden_overstromingskans_huidig_200_cm_20251120</Name> <Name>plaatsgebonden_overstromingskans_huidig_20_cm</Name> <Name>plaatsgebonden_overstromingskans_huidig_20_cm_20251120</Name>
- 4
4. De waarde op je punt en de klasse uit de legenda
GetFeatureInfo met info_format=application/json geeft bij een rasterlaag een getal (GRAY_INDEX), bij een vectorlaag de velden van het vlak. Wat dat getal betekent, staat in GetLegendGraphic met format=application/json: bij type values hoort elk getal bij één klasse (3 = kleine kans), bij type intervals krijgt een waarde de klasse van de eerste grens erboven. Vectorlagen hebben regels met een filter, zoals no_cc_risi > '0.8' AND no_cc_risi <= '3' (laag). Valkuil: nodata ziet er uit als een getal. -9999 bij de waterdiepte betekent droog of buiten het gebied, 2147483647 bij droogtestress betekent geen landbouwgrond, 55537 bij de gevoelstemperatuur betekent een gebouw, en 0 bij de overstromingskans staat niet in de legenda.
https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public/wms?service=WMS&version=1.3.0&request=GetFeatureInfo&layers=plaatsgebonden_overstromingskans_huidig_20_cm_20251120&query_layers=plaatsgebonden_overstromingskans_huidig_20_cm_20251120&styles=&crs=EPSG:28992&bbox=108440,447135,108640,447335&width=200&height=200&i=100&j=100&info_format=application/json
{"type":"FeatureCollection","features":[{"type":"Feature","id":"","geometry":null,"properties":{"GRAY_INDEX":3}}],...} en de legenda (request=GetLegendGraphic&layer=…&format=application/json): "colormap": { "entries": [ { "label": "Extreem kleine kans: <1/30.000 per jaar ", "quantity": "1", "color": "#619900" }, { "label": "Zeer kleine kans: 1/3.000 tot 1/30.000 per jaar", "quantity": "2", "color": "#C5DB00" }, { "label": "Kleine kans: 1/300 tot 1/3.000 per jaar", "quantity": "3", "color": "#FFD900" }, { "label": "Middelgrote kans: 1/30 tot 1/300 per jaar", "quantity": "4", "color": "#FF8400" }, { "label": "Grote kans: > 1/30 per jaar", "quantity": "5", "color": "#FF2600" } ], "type": "values" } - 5
5. Hitte per buurt (WFS met een punt)
De rasterkaart van de gevoelstemperatuur heeft op een gebouw geen waarde (55537). Gebruik daarom de buurtlaag GevoelstemperatuurBuurt_2022 via de WFS met cql_filter=INTERSECTS(geometry,POINT(x y)) in RD. _mean is het gemiddelde over de rastercellen van de buurt, _count het aantal cellen. Met propertyName zonder geometrieveld laat GeoServer de geometrie weg en blijft het antwoord klein. Valkuil: de geometrie heet hier geometry, in andere lagen geom; een verkeerde naam geeft 'Illegal property name'. Welke hete dag de kaart doorrekent, staat niet in de dienst.
https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public/wfs?service=WFS&version=2.0.0&request=GetFeature&typeNames=kea_public:GevoelstemperatuurBuurt_2022&outputFormat=application/json&propertyName=buurtcode,buurtnaam,gemeentena,_count,_mean&cql_filter=INTERSECTS(geometry,POINT(108540.066 447234.648))
{"type":"FeatureCollection","features":[{"type":"Feature","id":"GevoelstemperatuurBuurt_2022.fid--397ef6d2_1a14674f9af_-2df8", "geometry":null,"properties":{"buurtcode":"BU05130100","buurtnaam":"Nieuwe Markt e.o.","gemeentena":"Gouda", "_count":15648,"_mean":45.26546523517382}}],"totalFeatures":1,"numberMatched":1,"numberReturned":1,...} - 6
6. Wateroverlast per pand
De laag nl_fcab_omgevingsscore_wateroverlast_v20260806 heeft per BAG-pand de waterdiepte rondom na een hevige bui (99e percentiel, in meters) en een klasse van 'geen hinderlijke waterdiepte' tot 'meer dan 30 cm'. GetFeatureInfo op het BAG-punt geeft het pand meteen. Valkuil: filteren op identificatie_bag via de WFS liep na 60 seconden vast op een serverfout (geen index op dat veld); zoeken met een punt kost ruim een seconde. Een ander valkuiltje: bij het Rijksmuseum vond de kaart pand 0363100012237298, terwijl de BAG bij het adres pand 0363100012157857 noemt. Beide panden bestaan; het museum bestaat uit meer panden.
https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public/wms?service=WMS&version=1.3.0&request=GetFeatureInfo&layers=nl_fcab_omgevingsscore_wateroverlast_v20260806&query_layers=nl_fcab_omgevingsscore_wateroverlast_v20260806&styles=&crs=EPSG:28992&bbox=120716,485801,120916,486001&width=200&height=200&i=100&j=100&info_format=application/json
{"type":"FeatureCollection","features":[{"type":"Feature","id":"nl_fcab_omgevingsscore_wateroverlast_v20260806.2385481", "geometry":{"type":"Polygon","coordinates":[[[120867.5,485903.2],[120866.2,485902], ...]]},"geometry_name":"geom", "properties":{"identificatie_bag":"0363100012237298","bouwjaar":1885,"ahn_invliegjaar":2023, "waterdiepte_p99":0.156000003218651,"waterdiepte_klasse":"15 tot 20 cm"}}],"totalFeatures":"unknown",...} - 7
7. Grondwater gemeten in de buurt (BRO)
Zoek grondwaterputten met een POST naar characteristics/searches: een cirkel om je punt (straal in kilometer, lat/lon in WGS84) en een registratieperiode. Het antwoord is XML met per put de ligging en de maaiveldhoogte (groundLevelPosition, m NAP). Meer dan 2.000 putten wordt geweigerd: binnen 1 km van het stadhuis van Gouda stonden er al 477. Daarna per put gmw-relations voor de buizen en hun grondwaterstandonderzoeken (GLD), en seriesAsCsv voor de reeks. Valkuilen: veel putten hebben geen reeks of een lege CSV (GLD000000094630 gaf 0 regels), de tijd staat in epoch-milliseconden, en er is een kolom per kwaliteitsregime. publiek.broservices.nl gaf op robots.txt een 503, er staan dus geen regels.
curl -X POST "https://publiek.broservices.nl/gm/gmw/v1/characteristics/searches" \ -H 'Content-Type: application/json' -d '{"registrationPeriod":{"beginDate":"1900-01-01","endDate":"2026-10-16"},"area":{"enclosingCircle":{"center":{"lat":52.0119,"lon":4.7106},"radius":1}}}'<numberOfDocuments>477</numberOfDocuments><dispatchDocument><GMW_C gml:id="BRO_0002"> <brocom:broId>GMW000000005701</brocom:broId><brocom:deregistered>nee</brocom:deregistered> <brocom:qualityRegime>IMBRO/A</brocom:qualityRegime> <brocom:standardizedLocation srsName="urn:ogc:def:crs:EPSG::4258"><gml:pos>52.013343320 4.711304490</gml:pos> ...<groundLevelPosition uom="m">0.030</groundLevelPosition>... <screenPositionRange><shallowestScreenTopPosition uom="m">-1.130</shallowestScreenTopPosition>... en daarna https://publiek.broservices.nl/gm/gld/v1/seriesAsCsv/GLD000000013616: Tijdstip,Voorlopige Waarde [m],Voorlopige Opmerking,Beoordeelde Waarde [m],Beoordeelde Opmerking,Controle Waarde [m],... 1615161616000,-0.789,,,,,,, ... 1773302390000,-0.736,,,,,,,
Hoe de bronnen samenkomen
- Basisregistratie Adressen en Gebouwen (BAG)Klimaateffectatlasvia
RD-coördinaten (EPSG:28992) en de BAG-pandidentificatieHet BAG-punt in RD gaat rechtstreeks in de bbox van GetFeatureInfo en in de INTERSECTS-filter van de WFS. De wateroverlastkaart is per BAG-pand, dus het veld identificatie_bag is te vergelijken met de pandidentificatie uit de BAG.
- Basisregistratie Adressen en Gebouwen (BAG)Actueel Hoogtebestand Nederland (AHN)via
RD-coördinatenHet BAG-punt valt in het gebouw, waar het AHN-maaiveldmodel leeg is. Met een ring punten rondom krijg je de hoogte van de straat.
- Actueel Hoogtebestand Nederland (AHN)Basisregistratie Ondergrond (BRO)via
hoogte in m NAPDe BRO geeft de grondwaterstand in m NAP. Trek die af van het maaiveld (uit de put zelf of uit het AHN) en je hebt de diepte onder de grond. In Gouda gaf de put +0,18 m NAP als maaiveld en het AHN -0,17 rond het stadhuis: kies wat bij de plek van de meting hoort.
- Basisregistratie Ondergrond (BRO)Klimaateffectatlasvia
grondwaterstand onder maaiveldDe droogtekaarten (GLG_Huidig, LG_extreemdroogjaar_Huidig) zijn een landelijk model. Leg ze naast de meting in de put: in Gouda zei het model 3,04 m, de put mat in een jaar niet dieper dan 1,2 m onder het maaiveld.
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 webtool 'Klimaatrisico-check': de gebruiker typt een postcode en huisnummer en krijgt één rapport met vijf risico's (hitte, wateroverlast, overstroming, droogte, fundering), elk met de waarde, de klasse uit de legenda van de kaart, de naam van de kaartlaag en een korte uitleg. Plus een kaartje met het punt en een tabel met de grondwatermeting uit de dichtstbijzijnde put. Alle bronnen zijn open en zonder sleutel. Gebruik een eigen User-Agent (bijvoorbeeld 'mijn-project/1.0 (+jij@voorbeeld.nl)') in elke aanroep, en doe de aanroepen op de server (Klimaateffectatlas en BRO zijn niet als CORS-bron getest).
Stap 1, adres naar punt: BAG-WFS van PDOK, https://service.pdok.nl/lv/bag/wfs/v2_0 met service=WFS, version=2.0.0, request=GetFeature, typeNames=bag:verblijfsobject, outputFormat=application/json en een FES 2.0-filter (namespace http://www.opengis.net/fes/2.0) met PropertyIsEqualTo op postcode (zonder spatie, '2801JG') en huisnummer. Standaard in RD (EPSG:28992); met srsName=EPSG:4326 als [lon, lat]. Bij nul treffers ontbreekt numberMatched. Bij huisletters komen er meer objecten: laat de gebruiker kiezen. NIET de PDOK Locatieserver gebruiken: robots.txt van api.pdok.nl verbiedt /bzk/locatieserver/*.
Stap 2, maaiveld: AHN via https://service.pdok.nl/rws/ahn/wms/v1_0, request=GetFeatureInfo, layers=query_layers=dtm_05m, crs=EPSG:28992, bbox van 200 x 200 m rond het punt, width=height=200, i/j = pixel, info_format=application/json; de hoogte staat in properties.value_list (tekst, m NAP). Onder gebouwen is er geen waarde (lege features), dus neem de mediaan van 16 punten op 30 en 60 m rond het adres. WMS 1.3.0 met EPSG:28992: bbox is x,y (oost, noord).
Stap 3, Klimaateffectatlas: WMS https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public/wms en WFS op .../kea_public/wfs (GeoServer). Laagnamen hebben een versiedatum (_20260128, _v20260806) en oude versies blijven staan: lees GetCapabilities en kies per kaart de hoogste datum. Gebruik deze kaarten:
- Hitte: WFS kea_public:GevoelstemperatuurBuurt_2022 met cql_filter=INTERSECTS(geometry,POINT(x y)) en propertyName=buurtnaam,_mean (gemiddelde gevoelstemperatuur per buurt in °C; klassen uit de legenda van de rasterlaag gevoelstemperatuur_2022). Plus rasterlaag hitteeiland (°C warmer dan het platteland). De rasterlaag gevoelstemperatuur_2022 zelf geeft 55537 op gebouwen: niet gebruiken op het adrespunt.
- Wateroverlast: nl_fcab_omgevingsscore_wateroverlast_v... (vector, per BAG-pand: waterdiepte_p99 in m en waterdiepte_klasse). Vraag via GetFeatureInfo of WFS INTERSECTS; een WFS-filter op identificatie_bag loopt vast (60 s, serverfout).
- Overstroming: plaatsgebonden_overstromingskans_huidig_20_cm_... (klasse 1 tot 5, type values; 0 staat niet in de legenda: toon 'geen kansklasse') en maximale_waterdiepte_nederland_kleine_kans_... (m; -9999 = droog of buiten het gebied).
- Droogte: GLG_Huidig en LG_extreemdroogjaar_Huidig (m onder maaiveld, landelijk model). droogtestress_huidig geeft 2147483647 buiten landbouwgrond: noem dat 'niet van toepassing'.
- Fundering: risicopaalrot_huidig (veld no_cc_risi) en risicoverschilzetting_2050laag (veld mild_cc_ri), per buurt; nl_bodemdaling_totaal_v... (veld snelheid, mm per jaar, negatief = daling) en bodemdaling_2020_2050hoog (m).
GetFeatureInfo: version=1.3.0, crs=EPSG:28992, bbox 200 x 200 m, width=height=200, i=j=100, info_format=application/json. Raster: properties.GRAY_INDEX. Vector: de velden van het vlak (met geometrie erbij). De betekenis haal je uit GetLegendGraphic&layer=<laag>&format=application/json: raster colormap type 'values' = exacte waarde, 'intervals' = klasse van de eerste quantity die groter of gelijk is; vector rules met een filter-tekst zoals "no_cc_risi > '3' AND no_cc_risi <= '6'". De eenheid van de paalrot- en verschilzettingsscores staat niet in de dienst: toon de score met de klasse, verzin geen eenheid.
Stap 4, BRO-grondwater: POST JSON naar https://publiek.broservices.nl/gm/gmw/v1/characteristics/searches met {"registrationPeriod":{"beginDate":"1900-01-01","endDate":"<vandaag>"},"area":{"enclosingCircle":{"center":{"lat":..,"lon":..},"radius":1}}} (straal in km). Antwoord is XML: per GMW_C broId, gml:pos (lat lon, EPSG:4258) en groundLevelPosition (m NAP). Meer dan 2.000 putten wordt geweigerd: maak de straal dan kleiner. Sorteer op afstand, vraag per put https://publiek.broservices.nl/gm/v1/gmw-relations/<GMW-id> (JSON met monitoringTubeReferences[].gldReferences[].broId) en dan https://publiek.broservices.nl/gm/gld/v1/seriesAsCsv/<GLD-id>. CSV-kolommen: Tijdstip (epoch-ms), Voorlopige Waarde [m], Beoordeelde Waarde [m], Controle Waarde [m], Onbekend Waarde [m], elk met een opmerkingskolom. Neem per regel de eerste gevulde waarde. Veel reeksen zijn leeg of oud: neem de dichtstbijzijnde put met een meting in de laatste twee jaar en toon datum, laatste stand, minimum en maximum van het jaar ervoor en de diepte onder het maaiveld van de put.
Rapport: per risico een kaartje met de klasse in kleur (de kleuren staan in de legenda-JSON), de waarde met eenheid, de laagnaam en een zin uitleg. Zet bovenaan: dit zijn modelkaarten en scenario's, per buurt of per rastercel, geen voorspelling voor dit huis. Zet onderaan de bronvermelding 'Klimaateffectatlas, 2026' (CC BY 4.0), BAG en AHN (PDOK), BRO (TNO, CC0). Laat zien als model en meting verschillen (grondwater).
Probeer het zelf
De kern van het project in een klein script. Nodig: Python 3.10+ en requests. Getest op 2026-10-16; hieronder de echte uitvoer van die proefdraai.
# Klimaatrisico-check voor een adres: hitte, wateroverlast, overstroming, droogte en fundering.
# Bronnen: BAG (PDOK WFS), AHN (PDOK WMS), Klimaateffectatlas (WMS/WFS), BRO (grondwaterputten). Geen sleutels.
import math, re, sys, statistics, requests
from datetime import datetime, timezone, timedelta
UA = {"User-Agent": "mijn-project/1.0 (+jij@voorbeeld.nl)"}
KEA = "https://cas.cloud.sogelink.com/public/data/org/gws/YWFMLMWERURF/kea_public"
POSTCODE, HUISNUMMER = (sys.argv[1], sys.argv[2]) if len(sys.argv) > 2 else ("2801JG", "1")
def get(url, **params):
r = requests.get(url, params=params, headers=UA, timeout=90)
r.raise_for_status()
return r
# 1. Adres naar punt: BAG-WFS, één keer in RD (EPSG:28992) en één keer in WGS84 (lon, lat).
def bag(srs):
f = ('<Filter xmlns="http://www.opengis.net/fes/2.0"><And>'
f'<PropertyIsEqualTo><ValueReference>postcode</ValueReference><Literal>{POSTCODE}</Literal></PropertyIsEqualTo>'
f'<PropertyIsEqualTo><ValueReference>huisnummer</ValueReference><Literal>{HUISNUMMER}</Literal></PropertyIsEqualTo>'
'</And></Filter>')
j = get("https://service.pdok.nl/lv/bag/wfs/v2_0", service="WFS", version="2.0.0", request="GetFeature",
typeNames="bag:verblijfsobject", outputFormat="application/json", srsName=srs, filter=f).json()
if not j["features"]: # bij nul treffers ontbreekt numberMatched: kijk naar de lijst zelf
sys.exit(f"Geen adres gevonden voor {POSTCODE} {HUISNUMMER}")
return j["features"][0] # met huisletter of toevoeging kunnen het er meer zijn
vbo = bag("EPSG:28992")
X, Y = vbo["geometry"]["coordinates"]
LON, LAT = bag("EPSG:4326")["geometry"]["coordinates"]
p = vbo["properties"]
print(f"{p['openbare_ruimte']} {p['huisnummer']}, {p['woonplaats']}: bouwjaar {p['bouwjaar']}, {p['gebruiksdoel']}")
print(f" RD {X:.0f}, {Y:.0f} WGS84 {LAT:.5f}, {LON:.5f}\n")
# 2. Waarde op het punt: WMS GetFeatureInfo met een vak van 200 x 200 m en de klik in het midden.
def punt(wms, laag, x=X, y=Y, i=100, j=100):
f = get(wms, service="WMS", version="1.3.0", request="GetFeatureInfo", layers=laag, query_layers=laag, styles="",
crs="EPSG:28992", bbox=f"{x-100},{y-100},{x+100},{y+100}", width=200, height=200, i=i, j=j,
info_format="application/json").json()["features"]
return f[0]["properties"] if f else None
# Maaiveld uit het AHN (DTM): onder een gebouw is er geen waarde, dus mediaan van een ring van 16 punten rondom.
ring = []
for straal in (30, 60):
for k in range(8):
a = k * math.pi / 4
v = punt("https://service.pdok.nl/rws/ahn/wms/v1_0", "dtm_05m", i=100 + round(straal * math.cos(a)), j=100 - round(straal * math.sin(a)))
if v:
ring.append(float(v["value_list"]))
MAAIVELD = statistics.median(ring)
print(f"Maaiveld (AHN4, mediaan van {len(ring)} van 16 punten op 30 en 60 m): {MAAIVELD:+.2f} m NAP\n")
# 3. Klimaateffectatlas: kies per kaart de nieuwste versie uit GetCapabilities (laagnamen eindigen op een datum).
cap = get(f"{KEA}/wms", service="WMS", request="GetCapabilities", version="1.3.0").text
namen = set(re.findall(r"<Name>([^<]+)</Name>", cap))
def nieuwste(begin):
kandidaten = [n for n in namen if n == begin or re.fullmatch(re.escape(begin) + r"_v?\d{8}", n)]
return max(kandidaten, key=lambda n: re.search(r"(\d{8})$", n).group(1) if re.search(r"\d{8}$", n) else "0")
def klasse(laag, waarde, veld=None):
"""Zoek de klasse in de legenda (GetLegendGraphic als JSON)."""
leg = get(f"{KEA}/wms", service="WMS", version="1.3.0", request="GetLegendGraphic", layer=laag, format="application/json").json()
for rule in leg["Legend"][0]["rules"]:
ras = rule["symbolizers"][0].get("Raster")
if ras: # rasterlaag: 'intervals' = eerste grens erboven, 'values' = precies gelijk
cm = ras["colormap"]
for e in cm["entries"]:
q = float(e["quantity"])
if (cm["type"] == "values" and waarde == q) or (cm["type"] != "values" and waarde <= q):
return e.get("label", "").strip()
return "buiten de legenda"
f = rule.get("filter", "") # vectorlaag: filters als "no_cc_risi > '3' AND no_cc_risi <= '6'"
voorwaarden = re.findall(r"(\w+) (>=|<=|>|<|=) '([^']*)'", f)
def ok(v, op, d):
if op == "=":
return str(v) == d
v, d = float(v), float(d)
return {">=": v >= d, "<=": v <= d, ">": v > d, "<": v < d}[op]
if voorwaarden and all(ok(waarde, op, d) for _, op, d in voorwaarden):
return rule.get("title") or rule.get("name")
return "?"
def kea(laag, veld="GRAY_INDEX"):
v = punt(f"{KEA}/wms", laag)
return None if v is None else v.get(veld)
print("HITTE")
buurt = get(f"{KEA}/wfs", service="WFS", version="2.0.0", request="GetFeature", typeNames="kea_public:GevoelstemperatuurBuurt_2022",
outputFormat="application/json", propertyName="buurtnaam,gemeentena,_mean",
cql_filter=f"INTERSECTS(geometry,POINT({X} {Y}))").json()["features"][0]["properties"]
print(f" Gevoelstemperatuur (PET), gemiddeld over buurt {buurt['buurtnaam']}: {buurt['_mean']:.1f} °C ({klasse('gevoelstemperatuur_2022', buurt['_mean'])})")
hi = kea("hitteeiland")
print(f" Stedelijk hitte-eiland: {hi:.2f} °C warmer dan het platteland ({klasse('hitteeiland', hi)})")
print("WATEROVERLAST")
l = nieuwste("nl_fcab_omgevingsscore_wateroverlast")
w = punt(f"{KEA}/wms", l)
if w:
print(f" Water rond pand {w['identificatie_bag']} na een hevige bui (99e percentiel): {w['waterdiepte_p99']*100:.0f} cm ({klasse(l, w['waterdiepte_klasse'])}) [{l}]")
else:
print(" Geen pand van de wateroverlastkaart op dit punt")
print("OVERSTROMING")
l = nieuwste("plaatsgebonden_overstromingskans_huidig_20_cm")
k = kea(l)
print(f" Kans op meer dan 20 cm water: {klasse(l, k) if k else 'waarde 0, geen kansklasse in de legenda'} [{l}]")
l = nieuwste("maximale_waterdiepte_nederland_kleine_kans")
d = kea(l)
print(f" Waterdiepte bij een overstroming met kleine kans: {'droog of buiten het gebied' if d is None or d < 0 else f'{d:.2f} m'} [{l}]")
print("DROOGTE")
for l, wat in [("GLG_Huidig", "Grondwater in een gemiddeld droge periode (GLG)"), ("LG_extreemdroogjaar_Huidig", "Grondwater in een extreem droog jaar")]:
v = kea(l)
print(f" {wat}: {v:.2f} m onder maaiveld ({klasse(l, v)})")
print("FUNDERING EN BODEMDALING")
for l, veld, wat in [("risicopaalrot_huidig", "no_cc_risi", "Risico op paalrot, huidig klimaat"),
("risicoverschilzetting_2050laag", "mild_cc_ri", "Risico op verschilzetting, 2050 laag scenario")]:
v = kea(l, veld)
print(f" {wat}: {v:.2f} ({klasse(l, v)}), per buurt")
l = nieuwste("nl_bodemdaling_totaal")
v = kea(l, "snelheid")
print(f" Gemeten bodembeweging: {v:.1f} mm per jaar ({klasse(l, v)}) [{l}]")
v = kea("bodemdaling_2020_2050hoog")
print(f" Verwachte daling 2020 tot 2050, hoog scenario: {v*100:.0f} cm ({klasse('bodemdaling_2020_2050hoog', v)})")
# 4. BRO: dichtstbijzijnde grondwaterput met een recente meetreeks.
print("GRONDWATER GEMETEN (BRO)")
xml = requests.post("https://publiek.broservices.nl/gm/gmw/v1/characteristics/searches", headers=UA, timeout=90, json={
"registrationPeriod": {"beginDate": "1900-01-01", "endDate": datetime.now().strftime("%Y-%m-%d")},
"area": {"enclosingCircle": {"center": {"lat": LAT, "lon": LON}, "radius": 1}}}).text # straal in km; max 2.000 putten
putten = []
for doc in re.findall(r"<GMW_C.*?</GMW_C>", xml, re.S):
la, lo = map(float, re.search(r"<gml:pos>([\d.]+) ([\d.]+)</gml:pos>", doc).groups()) # EPSG:4258: lat, lon
mv = re.search(r'<groundLevelPosition uom="m">([-\d.]+)', doc)
km = 6371 * math.hypot(math.radians(lo - LON) * math.cos(math.radians(LAT)), math.radians(la - LAT))
putten.append((km, re.search(r"<brocom:broId>([^<]+)", doc).group(1), float(mv.group(1)) if mv else None))
print(f" {len(putten)} putten binnen 1 km")
grens = datetime.now(timezone.utc) - timedelta(days=365)
for km, put, mv in sorted(putten)[:25]:
rel = get(f"https://publiek.broservices.nl/gm/v1/gmw-relations/{put}").json()
for buis in rel["monitoringTubeReferences"]:
for gld in buis["gldReferences"]:
csv = get(f"https://publiek.broservices.nl/gm/gld/v1/seriesAsCsv/{gld['broId']}").text.splitlines()[1:]
reeks = []
for regel in csv:
c = regel.split(",")
waarde = next((c[k] for k in (3, 1, 5, 7) if c[k]), None) # beoordeeld, voorlopig, controle, onbekend
if waarde:
reeks.append((datetime.fromtimestamp(int(c[0]) / 1000, timezone.utc), float(waarde)))
recent = [w for t, w in reeks if t >= reeks[-1][0] - timedelta(days=365)] if reeks else []
if reeks and reeks[-1][0] >= grens - timedelta(days=365):
t, laatst = reeks[-1]
print(f" Put {put} ({km*1000:.0f} m), buis {buis['tubeNumber']}, reeks {gld['broId']}: {len(reeks)} metingen, {reeks[0][0]:%Y} tot {t:%d-%m-%Y}")
print(f" Laatste stand {laatst:+.2f} m NAP; laagste in het jaar ervoor {min(recent):+.2f}, hoogste {max(recent):+.2f} m NAP")
if mv is not None:
print(f" Dat is {mv - laatst:.2f} m onder het maaiveld bij de put ({mv:+.2f} m NAP volgens de BRO)")
raise SystemExit
print(" Geen put met een meetreeks van de afgelopen twee jaar gevonden")
Markt 1, Gouda: bouwjaar 1459, kantoorfunctie,bijeenkomstfunctie,overige gebruiksfunctie RD 108540, 447235 WGS84 52.01153, 4.71047 Maaiveld (AHN4, mediaan van 11 van 16 punten op 30 en 60 m): -0.17 m NAP HITTE Gevoelstemperatuur (PET), gemiddeld over buurt Nieuwe Markt e.o.: 45.3 °C (Extreme Hittestress (niveau 1): 44°C – 45°C) Stedelijk hitte-eiland: 1.75 °C warmer dan het platteland (1.6-1.8 °C) WATEROVERLAST Water rond pand 0513100011122752 na een hevige bui (99e percentiel): 0 cm (Geen hinderlijke waterdiepte) [nl_fcab_omgevingsscore_wateroverlast_v20260806] OVERSTROMING Kans op meer dan 20 cm water: Kleine kans: 1/300 tot 1/3.000 per jaar [plaatsgebonden_overstromingskans_huidig_20_cm_20251120] Waterdiepte bij een overstroming met kleine kans: 0.80 m [maximale_waterdiepte_nederland_kleine_kans_20260128] DROOGTE Grondwater in een gemiddeld droge periode (GLG): 3.04 m onder maaiveld (> 2,0m) Grondwater in een extreem droog jaar: 3.14 m onder maaiveld (> 2,0m) FUNDERING EN BODEMDALING Risico op paalrot, huidig klimaat: 1.73 (Laag), per buurt Risico op verschilzetting, 2050 laag scenario: 2.47 (Laag), per buurt Gemeten bodembeweging: -2.2 mm per jaar (Beperkt (1.5 tot 5 mm/jaar daling)) [nl_bodemdaling_totaal_v20260623] Verwachte daling 2020 tot 2050, hoog scenario: 4 cm (Beperkt (3-10cm)) GRONDWATER GEMETEN (BRO) 482 putten binnen 1 km Put GMW000000005707 (32 m), buis 1, reeks GLD000000013616: 38716 metingen, 2021 tot 12-03-2026 Laatste stand -0.74 m NAP; laagste in het jaar ervoor -1.02, hoogste -0.26 m NAP Dat is 0.92 m onder het maaiveld bij de put (+0.18 m NAP volgens de BRO)
Waar het misgaat
- Modelkaarten, geen voorspelling voor dit huis. De Klimaateffectatlas rekent scenario's door op een raster of per buurt. Paalrot en verschilzetting zijn scores per buurt; een eeuwenoud stadhuis in een buurt met 'laag' kan zelf wel op houten palen staan. Zeg dat bovenaan je rapport.
- Nodata vermomd als getal: -9999 (waterdiepte: droog of buiten het gebied), 2147483647 (droogtestress: geen landbouwgrond), 55537 (gevoelstemperatuur: gebouw), 0 bij de overstromingskans (niet in de legenda). Behandel alles wat niet in de legenda past als 'geen waarde', niet als risico.
- Laagnamen veranderen bij elke update (_20251219 werd _20260128) en oude versies blijven staan. Hardcode geen laagnaam: kies per kaart de nieuwste uit GetCapabilities en toon welke het werd.
- Het adrespunt ligt in het gebouw. Daar is het AHN-maaiveld leeg en geeft de hitte-rasterkaart geen waarde. Kijk rond het pand (ring van punten) of gebruik de buurtlaag.
- Model en meting lopen uiteen. Het landelijke grondwatermodel gaf in Gouda een laagste stand van 3,04 m onder maaiveld; de put 32 m verderop mat tussen maart 2025 en maart 2026 hooguit 1,2 m. Toon beide en zeg welke wat is.
- BRO-putten zonder reeks of met een oude reeks zijn de regel, niet de uitzondering. De dichtstbijzijnde put bij het stadhuis (GMW000000092160, 24 m) had een lege CSV; in Amsterdam was de dichtstbijzijnde bruikbare reeks (25 metingen) van april 2025. Zoek door tot een put met recente metingen en zet de datum erbij.
- Attribuutfilters op grote vectorlagen van de Klimaateffectatlas (zoals identificatie_bag op de wateroverlastkaart) lopen vast op een serverfout na 60 seconden. Zoek altijd ruimtelijk (GetFeatureInfo of INTERSECTS met een punt).
Verder bouwen
- Scenario's naast elkaar: dezelfde kaarten bestaan vaak voor nu, 2050 en 2085 of 2100 (risicopaalrot_2050hoog, GLG_2085Hoog, plaatsgebonden_overstromingskans_norm_plus_klimaatverandering_2100_...). Laat per risico zien hoe het verschuift.
- Een hele straat of wijk: haal alle verblijfsobjecten van een postcode op uit de BAG en zet de wateroverlastklasse per pand op een kaart. Let op het tempo: één aanroep per pand, wees zuinig.
- De grondwaterreeks naast de neerslag: zet de reeks uit de BRO naast de dagneerslag van het dichtstbijzijnde KNMI-station (knmi-daggegevens) en laat zien hoe snel het grondwater na een droge zomer herstelt.
- Wat zit er onder de grond: zoek sonderingen (CPT) in de BRO rond het adres (/sr/cpt/v1/characteristics/searches) en toon tot welke diepte de slappe lagen lopen. Dat zegt meer over funderingsrisico dan een buurtscore.
Meer met deze data
Grondwatermonitoringputten in de BRO naar bouwjaar: 2.786 putten in 2025, 2,2 keer zo veel als in 1990
Grondwatermonitoringputten in de BRO naar bouwjaar, 1990 – 2025, in putten. Het hoogste punt was 2022 (3.698).
De bronnen4

Klimaateffectatlas
Landelijke kaarten van wat klimaatverandering in Nederland doet: gevoelstemperatuur, droogte, grondwater, bodemdaling, waterdiepte bij een overstroming en bij extreme regen. Vaak voor nu en voor 2050, 2085 of 2100. Er is ook een buurtdashboard met cijfers per buurt. Te gebruiken als kaartlaag (WMS), als vectordata (WFS) en als download.

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.

Actueel Hoogtebestand Nederland (AHN)
De hoogtekaart van Nederland, gemeten met een laser vanuit een vliegtuig: minstens tien metingen per vierkante meter. Er zijn twee kaarten. Het maaiveldmodel (DTM) is de kale grond. Het oppervlaktemodel (DSM) is alles wat erop staat, met gebouwen en bomen. Via PDOK als kaartlaag (WMS), als API voor rasters (WCS) en als download.

Basisregistratie Ondergrond (BRO)
De landelijke registratie van wat er onder de grond zit en gemeten wordt: sonderingen, geologische, bodemkundige en geotechnische boringen, grondwatermonitoringputten met hun meetreeksen (soms vanaf de jaren 1950), grondwatersamenstelling, onttrekkingen en mijnbouwvergunningen. Bestuursorganen moeten hun onderzoek hier laten registreren; TNO beheert de landelijke voorziening namens het ministerie van BZK. Veertien REST-diensten op publiek.broservices.nl, elk met een OpenAPI-beschrijving, plus een kopie op PDOK. Op 16 oktober 2026 stonden er 97.768 grondwatermonitoringputten in.
Meer om te bouwen
Aardbevingentracker: elke beving op de kaart, met gemeente en woningenKaart
Alert als de rivier bij jou te hoog of te laag staatAlert
Buurtmonitor veiligheid: overlast en misdrijven per buurtDashboard
Dashboard asielopvang: landelijk en per gemeenteDashboard
Luchtkwaliteit-alert voor je eigen straatAlert
Natuur in je buurt: welke soorten zijn er gezien en hoe groen is het?App