| Title: | Access Open Geodata from the Dutch 'PDOK' Platform |
| Version: | 0.1.0 |
| Description: | Tools to discover, download, and spatially filter open geographic data from 'PDOK' (Publieke Dienstverlening Op de Kaart), the national geodata platform of the Netherlands. Datasets and their layers are searched and loaded as vector simple feature ('sf') objects through 'OGC' API Features endpoints, with automatic pagination and explicit coordinate reference system handling. Loaded layers can be filtered by any polygon area, and addresses or place names can be geocoded through the 'PDOK' location server. The focus is on vector feature data; raster, tile, and coverage services are out of scope. See https://www.pdok.nl/ for more information about the platform and its services. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 8.0.0 |
| Imports: | cli, httr2, rlang, sf, tibble |
| Suggests: | httptest2, knitr, rmarkdown, testthat (≥ 3.0.0), withr |
| Config/testthat/edition: | 3 |
| URL: | https://github.com/coeneisma/pdokr, https://coeneisma.github.io/pdokr/ |
| BugReports: | https://github.com/coeneisma/pdokr/issues |
| Language: | en-US |
| Config/Needs/website: | rmarkdown, tmap, dplyr, mapgl, leaflet |
| NeedsCompilation: | no |
| Packaged: | 2026-07-14 13:58:20 UTC; coeneisma |
| Author: | Coen Eisma |
| Maintainer: | Coen Eisma <coeneisma@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-22 08:30:09 UTC |
pdokr: Access Open Geodata from the Dutch 'PDOK' Platform
Description
Tools to discover, download, and spatially filter open geographic data from 'PDOK' (Publieke Dienstverlening Op de Kaart), the national geodata platform of the Netherlands. Datasets and their layers are searched and loaded as vector simple feature ('sf') objects through 'OGC' API Features endpoints, with automatic pagination and explicit coordinate reference system handling. Loaded layers can be filtered by any polygon area, and addresses or place names can be geocoded through the 'PDOK' location server. The focus is on vector feature data; raster, tile, and coverage services are out of scope. See https://www.pdok.nl/ for more information about the platform and its services.
Details
pdokr is a client for PDOK's OGC API Features services. It reads
vector feature data — points, lines, and polygons — and returns it as
sf objects. Raster, tile, and coverage services (such as
elevation grids or map-tile backgrounds) are out of scope: pdok_read()
loads features only. A handful of datasets listed by
pdok_list_datasets() serve tiles or coverages rather than features;
those cannot be read as sf, and pdok_read() reports this clearly. For
the official PDOK map background, use pdok_basemap().
Author(s)
Maintainer: Coen Eisma coeneisma@gmail.com (ORCID) [copyright holder]
Authors:
Coen Eisma coeneisma@gmail.com (ORCID) [copyright holder]
See Also
Useful links:
Report bugs at https://github.com/coeneisma/pdokr/issues
A PDOK basemap to use as a map background
Description
Returns the URL of the official PDOK 'BRT Achtergrondkaart' (or aerial
imagery) for use as the background of a map. Nothing is downloaded — the
function only constructs the URL, so it works offline and instantly. Hand the
result to any mapping package: tmap and leaflet take the raster tile URL,
maplibre/mapgl take the vector style URL.
Usage
pdok_basemap(style = "standaard", format = c("raster", "vector"))
Arguments
style |
The basemap style. For |
format |
|
Value
A single string: a raster tile-URL template, or a vector style URL.
Attribution
The map data is © Kadaster / PDOK. Show this attribution on any map that uses the basemap.
Examples
# Raster tile URL (tmap / leaflet)
pdok_basemap()
pdok_basemap("grijs")
# Vector style URL (maplibre / mapgl)
pdok_basemap("standaard", format = "vector")
Spatially filter an sf layer by any polygon
Description
Keeps the features of data that relate to filter_geometry under a spatial
predicate. It does what sf::st_filter() does, and additionally reconciles
coordinate reference systems for you: filter_geometry is transformed to the
CRS of data before filtering.
Usage
pdok_filter_by(data, filter_geometry, predicate = "intersects")
Arguments
data |
An sf object to filter (for example a layer loaded
with |
filter_geometry |
An |
predicate |
The spatial relationship to test, one of |
Details
filter_geometry can be any polygon: a municipality from
pdok_read() on the CBS administrative boundaries, a nature reserve, a
water-authority area, a hand-drawn polygon, or another PDOK layer.
The plain-sf equivalent is data[filter_geometry, , op = sf::st_intersects]
(after matching CRS); use that if you prefer to drop down to sf.
Value
An sf object: the subset of data whose features satisfy
predicate with respect to filter_geometry. A zero-row sf is returned
(silently) when no feature matches.
Spatial predicates
The predicate selects how a feature must relate to filter_geometry to be
kept. Each value calls the matching sf predicate function sf::st_<predicate>()
(so "within" uses sf::st_within(), "intersects" uses sf::st_intersects(),
and so on). The common choices:
-
"intersects"(default) — the feature touchesfilter_geometryin any way (overlaps, is inside, or shares a boundary). The most permissive; the usual choice for "everything in this area". -
"within"— the feature lies entirely insidefilter_geometry. Use this to exclude features that only stick partly into the area. -
"contains"— the feature entirely enclosesfilter_geometry(the inverse of"within"). -
"disjoint"— the feature does not touchfilter_geometryat all (everything outside the area).
"overlaps", "touches", "crosses", "covers" and "covered_by" are the
remaining, more specialized DE-9IM relationships. For the precise definition
of each, see the sf help page sf::geos_binary_pred (the topic that
documents st_intersects(), st_within(), and the rest).
See Also
sf::geos_binary_pred for the definition of each spatial predicate;
sf::st_filter(), the sf filter this wraps; and pdok_read(), whose
filter_by argument applies this filter while loading.
Examples
# All national parks that intersect the province of Utrecht
utrecht <- pdok_read(
"cbs/gebiedsindelingen", "provincie_gegeneraliseerd",
datetime = 2024
)
utrecht <- utrecht[utrecht$statnaam == "Utrecht", ]
parks <- pdok_read("rvo/nationale-parken-geharmoniseerd", "protectedsite")
pdok_filter_by(parks, utrecht)
Geocode addresses or place names with the PDOK Locatieserver
Description
Looks up addresses, place names, postcodes, municipalities, provinces and
more through the 'PDOK' Locatieserver, returning the results as a simple
feature collection. Point geometry is returned for addresses and places, and
boundary polygons for administrative areas such as municipalities — so a
result drops straight into the filter_by argument of pdok_read().
Usage
pdok_geocode(query, type = NULL, crs = NULL, limit = 1)
Arguments
query |
A character vector of one or more non-empty search strings, e.g.
|
type |
Optional result type to restrict to, one of |
crs |
Optional output CRS as an EPSG code (e.g. |
limit |
Maximum number of results to return per query (default 1). |
Details
query may be a vector, geocoding many locations in one call (for example a
column of addresses). Each result row carries a query column with the input
it came from, so the output maps back to the input even when a query returns
several candidates or none.
Value
An sf object with one row per match and a query column
identifying the input each row came from. All non-geometry fields the
service returns are kept as columns (with query, weergavenaam, type,
score, and the administrative names first); the geometry is a point for
addresses and places and a polygon for administrative areas. Queries that
match nothing are dropped (with a warning), so the result can have fewer
rows than query has elements; a zero-row sf is returned when nothing
matches at all.
See Also
pdok_reverse_geocode() for the reverse lookup (coordinates to the
nearest address), and pdok_read(), whose filter_by argument accepts the
result.
Examples
# An address: a point
pdok_geocode("Park Arenberg 88, De Bilt")
# A municipality: a boundary polygon
pdok_geocode("De Bilt", type = "gemeente")
# Several addresses in one call; the `query` column maps rows to inputs
pdok_geocode(c("Domplein 1, Utrecht", "Coolsingel 40, Rotterdam"))
List PDOK datasets
Description
Returns the full table of contents of datasets offered through the 'PDOK' OGC API Features platform, fetched live from https://api.pdok.nl/index.json.
Usage
pdok_list_datasets()
Value
A tibble with one row per dataset and the columns
id (the identifier passed to pdok_list_layers() and pdok_read()),
name, description, keywords (a list-column of character vectors),
services, owner, and ogc_url.
See Also
pdok_search_datasets() to filter this list.
Examples
pdok_list_datasets()
List the layers within a PDOK dataset
Description
Lists the layers (OGC API Features collections) offered by a dataset.
Usage
pdok_list_layers(dataset)
Arguments
dataset |
A dataset id from |
Value
A tibble with one row per layer and the columns
dataset (the dataset id, echoing the input so each row works directly
with pdok_read()), layer (the layer identifier), title,
description, start_date and end_date (the temporal extent the layer
covers, as Dates; end_date is NA when the layer is ongoing), crs (a
list-column of available EPSG codes), storage_crs (the EPSG code the data
is stored in), and bbox (a list-column of named numeric extents
c(xmin, ymin, xmax, ymax) in CRS84).
See Also
pdok_search_layers() to filter this list,
pdok_list_datasets() for the datasets.
Examples
pdok_list_layers("cbs/gebiedsindelingen")
Read a PDOK layer as an sf object
Description
Loads a layer from PDOK as a simple feature collection over the OGC API Features service, handling pagination automatically.
Usage
pdok_read(
dataset,
layer,
bbox = NULL,
filter_by = NULL,
predicate = "intersects",
datetime = NULL,
crs = NULL,
max_features = NULL
)
Arguments
dataset |
A dataset id from |
layer |
A layer id from |
bbox |
Optional server-side bounding-box pre-filter: a numeric vector
|
filter_by |
Optional |
predicate |
Spatial predicate for |
datetime |
Optional temporal filter: a single year (e.g. |
crs |
Optional output CRS as an EPSG code (e.g. |
max_features |
Optional cap on the number of features returned. |
Details
By default the data is returned in the coordinate reference system the
service provides (lon/lat, CRS84, for the OGC path). Set crs to receive the
data in another CRS; the transformation is done client-side with
sf::st_transform().
Value
An sf object with one row per feature, the layer's
attribute columns, and a geometry column. A zero-row sf is returned (with
a warning) when nothing matches.
See Also
pdok_list_layers() to find layer ids.
Examples
# A whole layer: the Dutch national parks
parks <- pdok_read("rvo/nationale-parken-geharmoniseerd", "protectedsite")
# Municipalities for 2024, in RD New (EPSG:28992)
pdok_read(
"cbs/gebiedsindelingen", "gemeente_gegeneraliseerd",
datetime = 2024, crs = 28992, max_features = 5
)
# One-call area filter: national parks within the province of Utrecht
provinces <- pdok_read(
"cbs/gebiedsindelingen", "provincie_gegeneraliseerd", datetime = 2024
)
utrecht <- provinces[provinces$statnaam == "Utrecht", ]
parks_utrecht <- pdok_read(
"rvo/nationale-parken-geharmoniseerd", "protectedsite",
filter_by = utrecht
)
Reverse geocode coordinates to the nearest address with the PDOK Locatieserver
Description
Finds the address, road or place nearest to each point, through the 'PDOK'
Locatieserver reverse service — the inverse of pdok_geocode(). Give it sf
points (in any CRS); it returns the nearest match(es) as an sf, including an
afstand column with the distance in meters.
Usage
pdok_reverse_geocode(points, type = NULL, crs = NULL, limit = 1)
Arguments
points |
An sf or |
type |
Optional result type to restrict to (see |
crs |
Optional output CRS as an EPSG code (e.g. |
limit |
Maximum number of results to return per point (default 1, the single nearest match). |
Value
An sf object with one row per match and a point_id
column giving the row index of the input point each match came from. The
afstand column holds the distance in meters; all other non-geometry
fields the service returns are kept too. Points that match nothing are
dropped (with a warning); a zero-row sf is returned when nothing matches
at all.
See Also
pdok_geocode() for the forward lookup (address to coordinates).
Examples
# A point in the center of Utrecht: the nearest address
pt <- sf::st_sfc(sf::st_point(c(5.121, 52.090)), crs = 4326)
pdok_reverse_geocode(pt)
Search PDOK datasets
Description
Filters the dataset registry from pdok_list_datasets() by a
case-insensitive partial match. The query is matched against each dataset's
identifier, name, description, and keywords.
Usage
pdok_search_datasets(query)
Arguments
query |
A single non-empty string to search for, e.g. |
Value
A tibble with the same columns as
pdok_list_datasets(), containing only the matching rows (zero rows when
nothing matches).
See Also
pdok_list_datasets() for the full list.
Examples
pdok_search_datasets("gemeente")
Search the layers within a PDOK dataset
Description
Filters the layers from pdok_list_layers() by a case-insensitive partial
match against each layer's identifier, title, and description.
Usage
pdok_search_layers(dataset, query)
Arguments
dataset |
A dataset id from |
query |
A single non-empty string to search for, e.g. |
Value
A tibble with the same columns as
pdok_list_layers(), containing only the matching rows (zero rows when
nothing matches).
See Also
pdok_list_layers() for the full list.
Examples
pdok_search_layers("cbs/gebiedsindelingen", "gemeente")