# North Holland Province geoservices (ArcGIS REST)

The ArcGIS server of the province of North Holland, with nearly 200 services in the root and six subfolders. On 16 October 2026 we counted 3,843 leaf layers on the server; because the same layer recurs in many collection services, our index keeps 2,683 after deduplication. Three quarters sit in the oi_op folder (environmental information), including a time series of the provincial environmental regulation, the provincial monuments and the nature management plans per year. Almost none of this is on data.overheid.nl or in the National Georegister.

- Publisher: Provincie Noord-Holland
- Area: Netherlands · Finest detail: feature (province of North Holland)
- Period: actuele stand; enkele diensten noemen een publicatiedatum (2024, 2025) · Refreshed: yearly
- Access: Open · Licence: niet vastgesteld
- Join keys: map/dienst + laagnaam, objectid, gemeentenaam (in veel lagen), RD-coördinaten (EPSG:28992)
- Status: grijs · 196 diensten in 7 mappen · ArcGIS 11.5
- URL: https://geoapps.noord-holland.nl/app/dataportaal

## What can you do with it?
- **Provincial monuments on the map.** The layer Provinciale monumenten INSPIRE has 761 features: 275 small objects, 224 parts of the Defence Line of Amsterdam, 150 flood defence elements and 102 hydraulic works. Fetch them as GeoJSON and plan a walk.
- **A map image without code.** Every MapServer also has a WMS. Paste the GetCapabilities url into QGIS and you have the layers as a map.
- **How did the environmental regulation change?.** The service oi_povnh_tijdreeks holds versions of the provincial environmental regulation side by side. Compare two versions of the same layer to see which areas were added or removed.

## How to process it
1. **Browse by folder.** Mind the path: /ags/rest/services, not /arcgis/. The oi_op folder has most services; ondergronden holds aerial photos (rasters, not queryable).
   `https://geoservices.noord-holland.nl/ags/rest/services/oi_op?f=json`
2. **Fetch a layer as GeoJSON.** Filter with where and request degrees with outSR=4326. maxRecordCount differs per service (usually 1,000 or 2,000); check the layer JSON and page with resultOffset.
   `https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query?where=srt_monume%3D%27Stelling+van+Amsterdam%27&outFields=element,plaats,gemeente&outSR=4326&resultRecordCount=5&f=geojson`
3. **Count per category.** Statistics work: a single call returns the number of monument features per type.
   `https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22count%22%2C%22onStatisticField%22%3A%22objectid%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=srt_monume&f=json`
4. **Or as WMS.** The same service as WMS 1.3.0 for QGIS or a web map.
   `https://geoservices.noord-holland.nl/ags/services/oi_dataservice_alg/MapServer/WMSServer?request=GetCapabilities&service=WMS`

## Interesting combinations
- Which provincial monuments lie next to national monuments? → [rijksmonumenten](https://www.opendataindex.nl/en/bron/rijksmonumenten.md) via coördinaten of adres. Put the provincial monuments next to the RCE national monuments; together they give a fuller picture of heritage per municipality.
- Monuments per municipality, with current boundaries → [pdok-wijkenbuurten](https://www.opendataindex.nl/en/bron/pdok-wijkenbuurten.md) via geometrie (ligging in gemeente). Municipality names in the monument layer are partly outdated (Zeevang, Graft-De Rijp). Re-derive the municipality with the CBS boundaries via PDOK.

## Similar sources
- [data-overheid](https://www.opendataindex.nl/en/bron/data-overheid.md): North Holland lists 94 datasets on data.overheid.nl (mostly public domain); only a few layers of this server appear there too.
- [Dataportaal Noord-Holland](https://geoapps.noord-holland.nl/app/dataportaal): The province's own viewer on the same services, to browse and download without an API.

## What to watch out for
- **Licence not established, partly Geo Gedeeld.** The server says nothing about reuse. In the NGR, 50 of North Holland's 61 records carry the Geo Gedeeld licence, which is not open. Check per layer.
- **Many duplicate layers.** The same layer sits in several collection services (oi_dataportaal_geoweb, oi_ilc, oi_gezonde_leefomgeving …). Deduplicate on layer name plus fields: 3,843 leaf layers become 2,683.
- **Dates only in the description.** Layers carry no modification date. A few services state in their description that they were 'published by script on 07-07-2025'; that is the publication, not the content.
- **Outdated municipality names.** The monument layer lists municipalities that no longer exist (Zeevang, Graft-De Rijp), and the municipality is blank for 382 features.

## API (ArcGIS REST)

- Base: https://geoservices.noord-holland.nl/ags/rest/services
- Access: No key or token: the directory and all calls below worked anonymously. (tested)
- Formats: json, geojson, pbf, png (export, WMS), xml/geojson (WFS)
- Size: 3852 leaf layers in 194 queryable services; about 2,140 unique layer names (the same layer sits in several services) (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'.
- `GET https://geoservices.noord-holland.nl/ags/services/{map}/{dienst}/MapServer/WMSServer?request=GetCapabilities&service=WMS`: WMS 1.3.0 of the same MapServer: path without /rest/ and with /WMSServer. Only for services whose supportedExtensions lists WMSServer.
- `GET https://geoservices.noord-holland.nl/ags/services/{map}/{dienst}/MapServer/WFSServer?service=WFS&request=GetCapabilities`: WFS 2.0 of the same MapServer (only if supportedExtensions lists WFSServer); GetFeature with outputFormat=GEOJSON.

### 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 (10)
`objectid` OID, `naam` String, `categorie` String, `gemeentenaam` String, `ingebruikname_jaar` Integer, `netto_opp_park_ha` String, `geschatte_vermogen_mw` String, `geschatte_opbrengst_gwh_jr` String, `sde_vermogen_mw` String, `peildatum` String

### Limits and pitfalls
- At most 1.000 tot 2.000.000 (oi_dataportaal_geoweb: 2.000.000; per laag nakijken) 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)
- Note /ags/ in the address (not /arcgis/). WMS and WFS are at /ags/services/…/MapServer/WMSServer and /WFSServer, only for services whose supportedExtensions list them (oi_dataservice_alg: both; oi_dataportaal_geoweb: WFS only). (tested)
- On 16 Oct 2026 around 23:30 every query on oi_dataservice_alg returned 'Underlying DBMS error [no connection to the server]' (with HTTP 200), while other services worked. Individual services can be down temporarily. (tested)
- 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)
- Numbers are sometimes stored as text (Zonneparken: geschatte_vermogen_mw '0.08'): sum in outStatistics then fails. Count or group on text fields, do the arithmetic yourself. (tested)
- The same layer appears in several collection services (oi_dataportaal_geoweb, oi_dataservice_alg, thematic atlas services). Deduplicate on layer name and fields. (experience)
- Dates only sometimes appear in the service description ('published by script on 07-07-2025 16:05:15'); otherwise no editingInfo. (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://geoservices.noord-holland.nl/ags/rest/services/oi_op/oi_dataportaal_geoweb/MapServer/23/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22count%22%2C%22onStatisticField%22%3A%22objectid%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=categorie&orderByFields=n%20DESC&f=json
```

## How to fetch it

### curl
```bash
curl "https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query?where=1%3D1&outFields=element,srt_monume,plaats&outSR=4326&resultRecordCount=1000&f=geojson"
```

### python
```python
import requests

laag = "https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query"
r = requests.get(laag, params={"where": "srt_monume='Stelling van Amsterdam'",
                               "outFields": "element,plaats", "outSR": 4326, "f": "geojson"})
for f in r.json()["features"][:10]:
    print(f["properties"]["element"], "|", f["properties"]["plaats"])
```

## Who uses it
- [Dataportaal Noord-Holland](https://geoapps.noord-holland.nl/app/dataportaal): The province's map viewer and data portal


## What is in it: 2,732 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 2,616, raster 96, tabel 20
- Last changed: 2025-07-07
- With an API call on the dataset page: 2,732
- Search: https://www.opendataindex.nl/api/catalogus/arcgis-noord-holland?q=… or the MCP function zoek_datasets with herkomst=arcgis-noord-holland
- Every row has its own page: https://www.opendataindex.nl/en/dataset/arcgis-noord-holland/<key>

### Folders
- F_NATUURBEHEERTYPE_110930 (55)
- igi op (133): AreaalGisib (4), id areaal (93), Map (1), Map (7), Map (3), Map (6), Map (14), Map (1) …
- oi dataservice areamanagement (5)
- oi dataservice povnh2020 (39)
- oi dataservice protected sites (5)
- oi op (1,976): Adreszoeker_17032011 (1), F_REGIOS_110930 (9), klimaatadaptatie signaleringskaart hex (1), LIANDER_TEST (1), Map (21), Map (1), Map (22), Map (35) …
- ondergronden (58): ondergrond kleur vector tiled (40), pnh hgn 1850 tegels (2), pnh hgn 1900 tegels (1), pnh hgn 1930 tegels (1), pnh luchtfoto 2000 (1), pnh luchtfoto 2003 (1), pnh luchtfoto 2006 (1), pnh luchtfoto 2009 (1) …
- P_ATLAS_LEEFOMGEVING (9)
- PGR_categorie3 (36)
- PGR_categorie3 (4)
- pnh op (1): pnh brk percelen (1)
- Publiceren (2)
- thematische services (367): F_REGIOS_110930 (8), Map (8), Map (24), Map (27), Map (2), Map (8), Map (16), Map (17) …

## Examples with real figures (1)

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

- **Provincial monuments in North Holland by type: most small objects (275 features), then Stelling van Amsterdam and flood defence elements** (november 2026). Table https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31. [Example](https://www.opendataindex.nl/en/voorbeeld/geoservices-noord-holland-monumenten)
  - `https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query?where=1%3D1&outStatistics=%5B%7B%22statisticType%22%3A%22count%22%2C%22onStatisticField%22%3A%22objectid%22%2C%22outStatisticFieldName%22%3A%22n%22%7D%5D&groupByFieldsForStatistics=srt_monume&orderByFields=n%20DESC&f=json`
  - `https://geoservices.noord-holland.nl/ags/rest/services/oi_dataservice_alg/MapServer/31/query?where=1%3D1&returnCountOnly=true&f=json`
