# Gelderland Province geoportal (ArcGIS REST)

The ArcGIS Enterprise server of the province of Gelderland, with 23 open folders by theme (Infra, Natuur, Milieu_Stikstof, Omgevingsverordening …). On 16 October 2026 our index held 1,027 map layers, from trees along provincial roads and road accidents (BRON, 2017 to 2024) to nitrogen deposition per hexagon. The accompanying Portal (geoportaal.gelderland.nl/portaal) searches 1,011 public services with readable titles and a modification date; the newest item was from 13 October 2026.

- Publisher: Provincie Gelderland
- Area: Netherlands · Finest detail: feature (province of Gelderland)
- Period: actuele stand; Portal-items gewijzigd tot 13 okt 2026 · Refreshed: monthly
- Access: Open · Licence: niet vastgesteld
- Join keys: map/dienst + laagnaam, objectid, wegnummer en kilometrering (wegenlagen), RD-coördinaten (EPSG:28992)
- Status: ok (2026-10-13) · 261 diensten in 24 mappen (4 mappen dicht) · ArcGIS 11.3
- URL: https://geoportaal.gelderland.nl/portaal/home/

## What can you do with it?
- **Accidents on your road.** The layer Ongevallen registratie (folder Infra) has 119,275 accidents from BRON, 2017 to 2024, with street name, town and road authority. Filter on a street or road number and map them.
- **Search the Portal, fetch from the server.** Layer names on the server are technical; the Portal has titles such as 'Recreatie- Fietspad langs provinciale wegen' with a link to the layer. Search there, then query the REST server for the data.
- **Oak processionary moth along the roads.** Bestrijding eikenprocessierups nesten 2020 - 2024 (folder Infra) tracks per oak along provincial roads whether nests were found. In 2020 10,648 oaks were marked 'EPR aanwezig', in 2023 2,204. Note: in 2024 the layer only says 'inspection carried out'.
- **Nitrogen per hexagon.** The Milieu_Stikstof folder has deposition, critical deposition value and exceedance per hexagon (100,771 cells). Combine with the Natura 2000 areas to see where exceedance is largest.

## How to process it
1. **Find a layer in the Portal.** The Portal search API returns title, tags, modification date (modified, in milliseconds) and the layer url.
   `https://geoportaal.gelderland.nl/portaal/sharing/rest/search?q=ongevallen&f=json`
2. **Fetch GeoJSON.** With f=geojson and outSR=4326 you get a file that fits a web map directly. maxRecordCount differs per layer (usually 2,000, for this layer 20,000).
   `https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=jaar%3D%272024%27&outFields=jaar,ong_tot,ong_let,stt_naam,wpsnaamnen&outSR=4326&resultOffset=0&resultRecordCount=5&f=geojson`
3. **Let the server count.** outStatistics with groupByFieldsForStatistics counts or sums per category in a single call. Here: accidents per year.
   `https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22ong_tot%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=jaar&f=json`
4. **Skip the tile services.** Besides queryable layers, the Hosted folder holds tile services (capabilities TilesOnly): you cannot query those, only display map tiles.
   `https://geoportaal.gelderland.nl/gisserver/rest/services/Hosted?f=json`

## Interesting combinations
- Are busy provincial roads also the unsafe ones? → [ndw-verkeer](https://www.opendataindex.nl/en/bron/ndw-verkeer.md) via wegnummer en kilometrering. Count accidents per road number and set them next to NDW traffic volumes on the same road sections.
- Where is the critical deposition value exceeded most? → [natura2000](https://www.opendataindex.nl/en/bron/natura2000.md) via geometrie (overlap). Overlay the hexagons with exceedance on the Natura 2000 sites and aggregate per site.

## Similar sources
- [data-overheid](https://www.opendataindex.nl/en/bron/data-overheid.md): Gelderland lists 201 datasets on data.overheid.nl, most under a public domain mark, with titles in the same 'Theme- Name' pattern as the Portal.
- [geoportaal-overijssel](https://www.opendataindex.nl/en/bron/geoportaal-overijssel.md): Also a provincial ArcGIS server, but without a Portal, without dates and with a proxy that does not allow statistics.

## What to watch out for
- **Licence not established.** Server and Portal say nothing about reuse (licenseInfo empty on 100 items checked). Gelderland itself publishes on data.overheid.nl mostly under a public domain mark.
- **Folders behind a token.** IMGEO, Intern, Klimaat and Test require a token (499). We skip those; the rest is open.
- **Dates only in the Portal.** The REST server gives no modification date per layer. The Portal does (modified per item), but not every layer has an item.
- **Accident data becomes less complete.** According to the accident layer's description, 'in recent years fewer details have been available because of the GDPR'. Compare years with care.
- **Weak descriptions.** Many services only say 'Geen metadata'. copyrightText is a 32-character code, not a name or licence.

## API (ArcGIS REST)

- Base: https://geoportaal.gelderland.nl/gisserver/rest/services
- Access: No key for the public folders. Five folders (IMGEO, Intern, Klimaat, Test, Utilities) return 'Token Required' (code 499). (tested)
- Formats: json, geojson, pbf, png (export)
- Size: 779 leaf layers in 100 queryable services (605 unique names), plus 161 tile services in the Hosted folder (tested)
- Filtering: SQL-like where clause on the layer's fields, plus an optional spatial filter (geometry). Group and count with outStatistics.; =, <>, >, >=, <, <=, LIKE, IN, IS NULL, BETWEEN, AND, OR, NOT

### Endpoints
- `GET ?f=json`: Directory: version, folders and services (name + type).
- `GET /{map}?f=json`: Services in one folder.
- `GET /{dienst}/MapServer?f=json`: Service: layers and tables (id, name, group layer or not), maxRecordCount, capabilities, projection, description.
- `GET /{dienst}/MapServer/{laag}?f=json`: Layer: fields (name, type, alias, length), geometry type, maxRecordCount, supportedQueryFormats and advancedQueryCapabilities (pagination, statistics, orderBy, distinct).
- `GET /{dienst}/MapServer/{laag}/query`: Query features with a where clause or spatial filter; also count (returnCountOnly) and group (outStatistics). Response in JSON, GeoJSON or PBF.
- `GET /{dienst}/MapServer/legend?f=json`: Legend per layer: labels and symbols (PNG as base64).
- `GET /{dienst}/MapServer/export?bbox=…&bboxSR=4326&size=600,400&format=png&f=image`: Map image as PNG for a rectangle; with f=json you get a link to the image. Without bbox: error 'bbox must be specified'.

### Parameters
- `where`: Condition in SQL-92 style: 1=1 for everything, text in single quotes (GEMEENTE='Zwolle'), LIKE with %, AND/OR, dates as DATE 'YYYY-MM-DD'. Required when there is no other filter. (tested)
- `outFields`: Fields in the response, comma-separated, or * for all fields. (tested)
- `returnGeometry`: false = attributes only (much smaller response). (tested)
- `outSR`: Projection of the geometry in the response; 4326 = degrees (WGS84). Default is the layer's projection, here RD (28992). (tested)
- `f`: Format: json (Esri JSON), geojson, pbf (protobuf), pjson (indented) or html (browse in the browser). (tested)
- `resultOffset`: Pagination: number of features to skip (from 0). Use together with orderByFields for a stable order. (tested)
- `resultRecordCount`: Maximum number of features in this response (capped at the layer's maxRecordCount). (tested)
- `orderByFields`: Sort order, e.g. 'OBJECTID' or 'n DESC' (also on a statistics field). (tested)
- `returnCountOnly`: true = only the number of features matching where: {"count": …}. (tested)
- `outStatistics`: Server-side statistics: list of {statisticType, onStatisticField, outStatisticFieldName}; statisticType count, sum, min, max, avg, stddev or var. URL-encode it. (tested)
- `groupByFieldsForStatistics`: Fields to group by with outStatistics (like GROUP BY). (tested)
- `returnDistinctValues`: true with outFields and returnGeometry=false: the unique values of those fields. (tested)
- `geometry`: Spatial filter: a point 'x,y' or envelope 'xmin,ymin,xmax,ymax', with geometryType (esriGeometryPoint, esriGeometryEnvelope), inSR (input projection), spatialRel (esriSpatialRelIntersects) and optionally distance + units (esriSRUnit_Meter) for a radius. (platform)

### Fields of the example layer (14)
`objectid` OID, `jaar` String, `ong_tot` Integer, `ong_ums` Integer, `ong_let` Integer, `ong_dod` Integer, `sla` Integer, `dod` Integer, `wegbehsrt` String, `wegbehnaam` String, `stt_naam` String, `wpsnaamnen` String, `latitude` Double, `longitude` Double

### Limits and pitfalls
- At most 20.000 (deze laag; elders meestal 2.000, soms 1.000 of meer) features per response (the layer's maxRecordCount; varies per layer, see /{layer}?f=json). If there are more, the response has exceededTransferLimit: true: fetch the rest with resultOffset and resultRecordCount. (tested)
- No key and no documented rate limit. Take it easy (a few requests per second) and prefer statistics or counts over fetching all features. (experience)
- Errors come back with HTTP 200 and a JSON object {"error": {"code": 400, …}} ('Failed to execute query.' for an unknown field in where). Always check for an error field, not just the status code. (tested)
- The MapServers here have no WMS extension (supportedExtensions empty; /WMSServer returns HTTP 400). Map images only via export. (tested)
- 161 services in the Hosted folder are tile services (TilesOnly): no fields and no query. (experience)
- The REST server gives no dates. The Gelderland Portal does: /portaal/sharing/rest/search gives per item a title ('Infra- Ongevallen registratie'), description, modified (newest 13 Oct 2026) and the layer url. (tested)
- Field names are short (ong_let, wpsnaamnen), but the aliases in /{layer}?f=json are readable ('Aantal ongevallen met letsel'). (tested)
- Connections to this server sometimes failed in earlier harvests with a timeout or SSL error; retry. (experience)
- Group layers (with subLayerIds) have no query; query the leaf layers below them. Raster layers have no fields and no count. (platform)

### Example
```
https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22ong_tot%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=jaar&orderByFields=jaar&f=json
```

## How to fetch it

### curl
```bash
curl "https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=wpsnaamnen%3D%27Arnhem%27&outFields=jaar,ong_tot,stt_naam&outSR=4326&resultRecordCount=100&f=geojson"
```

### python
```python
import requests

laag = "https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query"
stat = '[{"statisticType":"sum","onStatisticField":"ong_tot","outStatisticFieldName":"n"}]'
r = requests.get(laag, params={"where": "1=1", "outStatistics": stat,
                               "groupByFieldsForStatistics": "jaar", "f": "json"})
for f in sorted(r.json()["features"], key=lambda f: f["attributes"]["jaar"]):
    print(f["attributes"]["jaar"], f["attributes"]["n"])
```

## Who uses it
- [Geoportaal Gelderland](https://geoportaal.gelderland.nl/portaal/home/): The province's own Portal, with map viewers and apps built on these services


## What is in it: 1,041 map layers

All services and layers on this ArcGIS server, fetched every night. Every layer has its own page with fields, geometry and a query call.

- Kinds: kaartlaag 1,029, tabel 7, raster 5
- With an API call on the dataset page: 1,041
- Search: https://www.opendataindex.nl/api/catalogus/arcgis-gelderland?q=… or the MCP function zoek_datasets with herkomst=arcgis-gelderland
- Every row has its own page: https://www.opendataindex.nl/en/dataset/arcgis-gelderland/<key>

### Folders
- AardkundeBodem (4): Map (4)
- Cultuurhistorie (26): Map (26)
- Economie (3): map (3)
- Grenzen (18): Map (18)
- Hosted (330): Aanvullend beoordeelde zoekgebieden (1), Alle ruimte grote turbine (1), Alle ruimte kleine turbine (1), Aquathermie WFL1 (17), Basisscholen met leerlingprognoses (1), Beschikbaarheid van algemeen hitte protocol (1), Bufferzone windturbines (1), Eerbeek Loenen 2030 projectlocaties (1) …
- Infra (126): Infra (122), Infra FCDtelvakken ochtend avond (4)
- Landbouw (6): Map2 (6)
- Landschap (6): Thema Landschap (6)
- Milieu (26): Map (26)
- Milieu Stikstof (4): Map (4)
- Natura2000 Leefgebieden (72): Map (72)
- Natuur (40): Map (40)
- Natuurbeheerplan (101): Map (8), Map (9), Map (9), Map (75)
- Omgevingsverordening (42): Map (42)
- Omgevingsvisie (80): Map (1), Map (7), Map (40), Map (1), Map (3), Map (9), Map (19)
- Ontgronding (2): Ontgronding (2)
- Overig (103): Asbestdaken (1), imgeo wfs (10), Map (2), Map (1), P8 viewer lagen (72), Wegen_verkeer_vlakken (16), zoeken hectometrering (1)
- Projecten (17): Map (4), P2104 1813 Meetnet grondwaterkwantiteit (13)
- Recreatie (5): Map (5)
- Topografie (2): Map (2)
- Water (7): Water (7)
- Waterprogramma (20): Map (20)
- Welzijn (1): Map (1)

## Examples with real figures (2)

For each example the finding, the reference date and the call that fetches exactly these figures.

- **Registered road accidents in Gelderland (BRON, provincial layer): 15,728 accidents in 2025, 1% less than in 2017** (2025). Table https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229. [Example](https://www.opendataindex.nl/en/voorbeeld/geoportaal-gelderland-ongevallen)
  - `https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22ong_tot%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=jaar&orderByFields=n%20DESC&f=json`
  - `https://geoportaal.gelderland.nl/gisserver/rest/services/Infra/Infra/MapServer/229/query?where=1%3D1&returnCountOnly=true&f=json`
- **Map layers on the Gelderland ArcGIS server by folder: most Hosted (324 layers), then Infra and Overig** (november 2026). Table https://geoportaal.gelderland.nl/gisserver/rest/services. [Example](https://www.opendataindex.nl/en/voorbeeld/geoportaal-gelderland-lagen)
  - `https://geoportaal.gelderland.nl/gisserver/rest/services?f=json`
  - `https://geoportaal.gelderland.nl/gisserver/rest/services/AardkundeBodem/AardkundenBodem/MapServer?f=json`
