
Using the 3D BAG: CityJSON, API and 3D Tiles
The 3D BAG is an open dataset of 3D building models for the whole of the Netherlands, made by TU Delft and 3DGI from the BAG and the AHN. It comes as CityJSON, GeoPackage, 3D Tiles or through the keyless 3DBAG API, in three levels of detail, under CC BY 4.0 with mandatory credit.

What is the 3D BAG and who makes it?
The 3D BAG combines the building footprints from the BAG (the Dutch key register of addresses and buildings) with height data from the AHN (the national height model, built from airborne laser scanning; page in Dutch) into 3D models. TU Delft (the 3D geoinformation research group) and 3DGI create and maintain the dataset. The documentation calls it the first open 3D building dataset that is generated fully automatically and covers a whole country at this level of detail.
| Property | Value |
|---|---|
| Owner | 3D geoinformation research group (TU Delft) and 3DGI |
| Licence | CC BY 4.0, with mandatory credit |
| Sources | BAG (footprints) and AHN (height points) |
| Latest release in the documentation | 2025.09.03, released on 9 September 2025 |
| Levels of detail | LoD1.2, LoD1.3, LoD2.2 |
| Coordinate system API | Amersfoort / RD New + NAP height (EPSG:7415), the only supported system |
| API | https://api.3dbag.nl, CityJSONFeature objects |
| Tiles | 3D Tiles 1.1 per LoD, https://data.3dbag.nl/v20250903/cesium3dtiles/lod22/tileset.json |
We require that you use the credit "© 3DBAG by tudelft3d and 3DGI". In digital media you must also provide a link to this copyright page.
Source: 3DBAG documentation, Copyright. In a map viewer the credit belongs at the bottom right of the map. More about this type of licence is in the page on open data licences (in Dutch).
Which level of detail do you choose, LoD1.2, LoD1.3 or LoD2.2?
Choose LoD1.2 for simple volume calculations, LoD1.3 when height differences within one building matter, and LoD2.2 for roofs with their actual shape. LoD stands for level of detail. The documentation explains the difference between the first two like this.
the distinction between LoD1.2 and LoD1.3 is that LoD1.3 distinguishes between significant height differences within one building, while in case of LoD1.2 the whole model has a uniform height.
Source: 3DBAG documentation, General Concepts. The difference between LoD1 and LoD2 is also that LoD2 labels surfaces with their function, such as roof, wall and ground surface (semantic surfaces). That lets you colour roofs red and walls grey, or calculate roof area per roof plane. The buildings are modelled as Solids, and the dataset validates each model with the program val3dity.
The three levels are in the same CityJSON tile and the same API response. So you do not have to choose when downloading, only when displaying or calculating. How 3D building data fits into a digital twin is covered under digital twin for municipalities (in Dutch).
Which formats and routes does the 3D BAG offer?
The 3D BAG comes as a file per tile, as a whole and through web services. The choice depends on what you do with it.
| Form | Content and use |
|---|---|
| CityJSON | All three LoDs per tile, only the attributes that apply to the whole building; opens in ninja, azul and QGIS, among others |
| GeoPackage | Per tile and as one file for the whole country, all layers |
| FlatGeobuf, Wavefront OBJ, IFC | Additional file formats; IFC (version 4.3, for BIM users; labelled experimental by 3DBAG itself) and 3D Tiles are new since release 2025.09.03 |
| 3D Tiles 1.1 | Streaming in 3D viewers; glTF with metadata per building; coordinates in EPSG:4978 |
| WFS and WMS | Two-dimensional layers and a tile index |
| 3DBAG API | One building by BAG identifier or all buildings in a bbox, with 3D geometry and all attributes |
The documentation states that the 3DBAG API is "currently not OGC-compliant", with the intention of later fully complying with OGC API Features. What the OGC API Features standard involves is explained at WFS and OGC API Features (in Dutch). The download links per tile are on the Downloads page of 3dbag.nl.
How do you fetch a building with the 3DBAG API?
The API works without a key and sends Access-Control-Allow-Origin: *. You request a building with the BAG identifier of the building (pand), prefixed with NL.IMBAG.Pand.. The example below was run with Node 24 on 11 and 12 October 2026, with the same output, for a building near Amersfoort station.
const id = 'NL.IMBAG.Pand.0307100000308303';
const res = await fetch(`https://api.3dbag.nl/collections/pand/items/${id}`);
if (!res.ok) throw new Error('3DBAG API returned status ' + res.status);
const { feature, metadata } = await res.json();
const pand = feature.CityObjects[id];
const a = pand.attributes;
const height = a.b3_h_dak_max - a.b3_h_maaiveld;
console.log(metadata.metadata.referenceSystem);
console.log('year built', a.oorspronkelijkbouwjaar, '- roof type', a.b3_dak_type);
console.log('height (roof max - ground):', height.toFixed(1), 'm');
console.log('volume LoD2.2:', a.b3_volume_lod22.toFixed(0), 'm3');
const part = feature.CityObjects[id + '-0'];
console.log(part.geometry.map((g) => g.type + ' LoD ' + g.lod).join(', '));
Output:
https://www.opengis.net/def/crs/EPSG/0/7415
year built 1986 - roof type slanted
height (roof max - ground): 10.8 m
volume LoD2.2: 2252 m3
Solid LoD 1.2, Solid LoD 1.3, Solid LoD 2.2
The response is a CityJSONFeature. The building (Building) carries the attributes, the building part (BuildingPart, id ending in -0) carries the geometry in three LoDs. The heights are in NAP, the Dutch ordnance datum. The coordinates are stored as integers in vertices; you convert them with transform.scale and transform.translate from the metadata. The calculated height of 10.8 metres is the difference between the highest roof height and the ground level, not a published building height.
How do you request buildings in a map window?
For a window you use bbox in RD. The example fetches the buildings around Amersfoort station and calculates the height per building.
const url = 'https://api.3dbag.nl/collections/pand/items?bbox=154150,462680,154250,462760&limit=100';
const res = await fetch(url);
if (!res.ok) throw new Error('3DBAG API returned status ' + res.status);
const { features, numberMatched } = await res.json();
// numberMatched counts CityObjects (building + building part), not buildings
console.log(numberMatched, 'CityObjects,', features.length, 'buildings');
for (const f of features) {
const a = f.CityObjects[f.id].attributes;
const height = a.b3_h_dak_max - a.b3_h_maaiveld;
console.log(f.id.split('.').pop(), a.b3_dak_type, height.toFixed(1) + ' m');
}
10 CityObjects, 5 buildings
0307100000308303 slanted 10.8 m
0307100000311531 slanted 12.2 m
0307100000338918 slanted 19.5 m
0307100000341963 slanted 25.5 m
0307100000347585 slanted 52.2 m
Watch the counting. numberMatched and limit count CityObjects, and every building has two. With limit=4 we got two buildings back. Paging works with offset; limit=4&offset=4 gave the next two buildings. In the BGT the window contains six current buildings and here five.
How do you load the 3D BAG as 3D Tiles?
3D Tiles are for streaming to the browser. The 3D BAG delivers the three LoDs as separate tilesets. The LoD2.2 tileset is at https://data.3dbag.nl/v20250903/cesium3dtiles/lod22/tileset.json. On 11 October 2026 that file returned status 200 with Access-Control-Allow-Origin: * and the property asset.version with value 1.1.
The documentation describes the content. The tiles use glTF files (.glb) with metadata per building according to the extensions EXT_mesh_features and EXT_structural_metadata, in EPSG:4978 and with uniform colour. The documentation mentions an example with CesiumJS. That example requires your own Cesium ion token. Credit is mandatory on use. The volume is not limited, but the documentation warns that this may change. So do not hang a production viewer on one external path without a cache or your own copy.
A custom map viewer with 3D buildings belongs under GIS and digital map solutions. For a 2D base layer without 3D use the MapLibre library (page in Dutch) with vector tiles.
What pitfalls does the 3D BAG have?
- An unknown building gives status 502. The API answers a non-existent identifier, and also the new 2024 building at Amersfoort station (
0307100000595635), with 502 and an empty body, not with 404. Handle this explicitly. - New buildings are missing. The dataset lags behind the BAG. For 2025.09.03 the release overview mentions a known issue, 397,512 BAG objects without a 3D model, usually because of missing height data.
- Documentation and API name attributes differently. The attribute overview has
b3_h_maxandb3_h_50p. The API response hasb3_h_dak_maxandb3_h_dak_50p. The collection metadata reports versionv2023.10.08, while attributes such asb3_h_nokcome from a later release. Which release the API serves cannot be derived from the response. Read the fields from the response itself. - Only EPSG:7415. The API does not support WGS84. Convert coordinates yourself, for example with the RD to WGS84 tool or GDAL (page in Dutch).
- Roof height is a calculation. The heights follow from the AHN point cloud and are a model, not a measurement on the building. The dataset reports the deviation in
b3_rmse_lod22and a reliability flag inb3_kwaliteitsindicator. - Glass roofs and greenhouses. The documentation states that the AHN point cloud is unreliable for glass roofs, especially greenhouses. For those buildings the dataset falls back to a simple model.
When is the 3D BAG not the right source?
The 3D BAG is a derived model, not a land survey. For a permit, a building height check or a claim about a specific roof, a measurement or the source holder is needed. For the precise position of the facade edge use the BGT, for addresses the BAG. For ground level, trees and terrain the AHN is the source itself.
The 3D BAG does fit a map or policy application, such as solar potential, noise or wind nuisance. If you want to publish the results alongside your own data, see the open data platform. For other sources see the hub Dutch open data.
Frequently asked questions
Is the 3D BAG free to use, also commercially?
Yes. The 3D BAG is under CC BY 4.0. You may copy, distribute and adapt the data, provided that you include the credit "© 3DBAG by tudelft3d and 3DGI", link to the licence and indicate whether you made changes. In digital media a link to the copyright page belongs with it.
What is the difference between the 3D BAG and PDOK's 3D Basisvoorziening?
The 3D BAG comes from TU Delft and 3DGI and uses CC BY 4.0 with mandatory credit. The 3D Basisvoorziening is a separate PDOK dataset with eight collections of height information, based among other things on the BGT, BAG, aerial photographs and AHN. It is a different dataset with its own structure. Read the attribution per dataset before you combine them.
Can I also use the 3D BAG as an ordinary map layer?
Yes, as 2D. The 3D BAG offers WFS and WMS with the two-dimensional layers and a tile index, and the documentation names the layers lod12, lod13, lod22 and tiles. For 3D display in the browser use the 3D Tiles or the API.
How current is the 3D BAG?
The documentation gives 2025.09.03 as the latest release. Newer buildings are missing until the next release. In our test a 2024 building that is in the BAG was missing. For current buildings use the BAG itself, and for 3D use the dataset as an approximation.
Sources
- 3DBAG — Documentation, overview (accessed )
- 3DBAG — Copyright and licence (accessed )
- 3DBAG — Web services, 3DBAG API and 3D Tiles (accessed )
- 3DBAG — General concepts, LoD and Solid (accessed )
- 3DBAG — Release notes (accessed )
- 3DBAG — Data attributes (accessed )
- 3DBAG — CityJSON (accessed )
- 3DBAG API — landing page and collection pand (accessed )
- PDOK — 3D Basisvoorziening (OGC API) (accessed )
More about TechinFlow
A new company in Haarlem building custom software, GIS and data platforms on open standards.
A question or project?
Tell us briefly what is going on and for which organisation. We reply by email.
Send a message