# Traffic signs and accessibility map (NDW)

The National Road Traffic Data Portal keeps a national file of traffic signs: per sign the RVV code (A1 for a speed limit, C22a for a low-emission zone …), additional panels, side of the road, the NWB road section, municipality, traffic order and since when the sign has been seen. Amsterdam alone had 97,175 signs on 16 October 2026. The traffic sign API v4 returns the current state (updated daily) and all changes; the whole file can also be downloaded. Plus an accessibility map that computes per municipality which roads are open to a vehicle of given dimensions, still in beta.

- Publisher: Nationaal Dataportaal Wegverkeer
- Area: Netherlands · Finest detail: traffic sign
- Period: actueel beeld, plus alle gepubliceerde wijzigingen (events) · Refreshed: daily
- Access: Open · Licence: CC0 volgens de copyrightpagina van NDW ("tenzij anders vermeld"); de API noemt zelf geen licentie
- Join keys: rvvCode, countyCode (GM…), roadSectionId (NWB-wegvak), trafficOrderUrl (verkeersbesluit)
- Status: ok (2026-10-16)
- URL: https://docs.ndw.nu/data-uitwisseling/interface-beschrijvingen/verkeersborden-api/

## What can you do with it?
- **Where does the low-emission zone start?.** There are 615 C22a signs (low-emission zone) in 64 municipalities; Amsterdam has 91, Rotterdam and Arnhem 73 each. Map them and you see the edge of every zone.
- **How many signs are in your municipality?.** Request the current state with countyCode (e.g. GM0599 for Rotterdam) and count per RVV code.
- **From sign to traffic order.** Some signs have a trafficOrderUrl such as gmb-2024-403036: the traffic order in the municipal gazette. That lets you check whether every sign has a decision behind it.
- **What changes on the street?.** The events service returns every published change with a timestamp, including signs that were removed (status REMOVED). Use it to follow a municipality switching to 30 km per hour.

## How to process it
1. **Always filter.** current-state without a filter returns the whole country. rvvCode=A1 alone is 97 MB, Amsterdam 56 MB. Filter on rvvCode, countyCode, roadAuthorityType (R, P, G, W, T), status or bbox. An unknown parameter is silently ignored.
   `https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/current-state?rvvCode=C22a&countyCode=GM0363`
2. **Keep track of changes.** events returns at most 100 changes at a time, oldest first. offset is a timestamp: pass the time of the last change you received to continue.
   `https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/events?limit=100&countyCode=GM0363`
3. **The whole file.** The current state as CSV (246 MB zipped) or GeoJSON in RD and in degrees, on opendata.ndw.nu.
   `https://opendata.ndw.nu/verkeersborden_actueel_beeld.csv.gz`
4. **Accessibility map (beta).** GET municipalities returns the 342 municipalities with their bounds; POST accessibility.geojson with vehicle characteristics and a municipality returns the accessible and inaccessible road sections. According to the description, intended for road authorities only.
   `https://data.ndw.nu/api/rest/static-road-data/accessibility-map/v2/municipalities`

## Interesting combinations
- Which speed applies to which road section? → [rws-nwb](https://www.opendataindex.nl/en/bron/rws-nwb.md) via roadSectionId = wvk_id (let op nwbVersion). Join the A1 signs (speed limit) via roadSectionId to the NWB road sections and colour the network by limit.
- Signs per resident → [cbs-kwb](https://www.opendataindex.nl/en/bron/cbs-kwb.md) via countyCode (gemeentecode). Count signs per municipality and divide by the population from the CBS figures. Large differences also say something about how completely a municipality has been surveyed.

## Similar sources
- [openstreetmap](https://www.opendataindex.nl/en/bron/openstreetmap.md): OSM has speed limits and access rules as road attributes, entered by volunteers; NDW has the signs themselves, with photo and traffic order.
- [rws-nwb](https://www.opendataindex.nl/en/bron/rws-nwb.md): The road network itself; WEGGEG only has speed limits for national roads. The traffic signs cover all roads.
- [ndw-verkeer](https://www.opendataindex.nl/en/bron/ndw-verkeer.md): Live speeds and volumes from the same portal; this is the static side of the road.

## What to watch out for
- **Beta and without rights.** The accessibility map is, by its own description, in beta, intended only for road authorities, and no rights can be derived from it. The situation on the road always takes precedence.
- **Not validated.** All 615 low-emission zone signs had validated = n. The signs come from surveys and reports; a sign can be missing or already gone.
- **Old addresses no longer work.** The old addresses data.ndw.nu/api/rest/static-road-data/traffic-signs/v1/… return 404. Use v4 on wegkenmerken.ndw.nu.
- **Large responses.** There is no paging in current-state: a municipality or a common code returns tens of MB. For the whole country the download file is better.

## API (REST (GeoJSON, JSON, CSV))

- Base: https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4
- Access: No key or account; all calls worked anonymously. (tested)
- Formats: geojson, json, csv
- Size: 615 low-emission zone signs C22a in the current state, in 62 municipalities (16 Oct 2026); the whole file is 235 MB zipped (tested)
- Filtering: Each condition is its own query parameter; combinations act as AND. Exact match, no wildcards.; =, komma = OF binnen rvvCode en roadSectionId

### Endpoints
- `GET /current-state`: The current state: every sign as a GeoJSON feature (or CSV), updated daily. With a filter it is filtered live, including today's changes. Without a status filter only placed signs (PLACED).
- `GET /events`: All published changes, oldest first, at most 100 at a time; read on with offset (timestamp).
- `GET /collections`: The supported coordinate reference systems (CRS84 and RD, EPSG 28992).
- `GET https://wegkenmerken.ndw.nu/api/images/{id}`: Photo of the sign (JPEG, ~14 kB); the address is in imageUrl.
- `GET https://opendata.ndw.nu/verkeersborden_actueel_beeld.csv.gz`: The whole current state as a file: CSV (235 MB zipped) or GeoJSON in RD (_rd.geojson.gz, 228 MB) and in degrees (_wgs84.geojson.gz, 236 MB). Once a day around 12:05.

### Parameters
- `countyCode`: Municipality code, e.g. GM0363 (Amsterdam). Other format (GM363) returns 400 with the rule ^GM\d{4}$. Also on /events. (tested)
- `rvvCode`: RVV code of the sign (A1, C22a …); several separated by commas (C22a,C22c). (tested)
- `roadSectionId`: NWB road section ids; no limit on the number. (from the description)
- `status`: Status of the sign. Without this parameter you got only PLACED; status=REMOVED returned 407 removed low-emission zone signs. (tested)
- `roadAuthorityType`: Type of road authority as a letter from the specification (which does not explain the letters). With G, 72 of the 73 C22a signs in Rotterdam remained. (tested)
- `roadAuthorityCode`: Code of a single road authority. (from the description)
- `bbox`: Bounding box; 4.88,52.36,4.92,52.38 with rvvCode=C22a returned 2 signs. (tested)
- `bbox-crs / crs`: CRS of the bbox and of the response: http://www.opengis.net/def/crs/OGC/1.3/CRS84 (default) or http://www.opengis.net/def/crs/EPSG/9.9.1/28992 (RD). (tested)
- `contentType`: contentType=csv (or the Accept header text/csv) returns a flat CSV with 36 columns. (tested)
- `offset`: Only /events: publication time to read from (yyyy-MM-ddTHH:mm:ss.SSSZ); default 1970. (from the description)
- `limit`: Only /events: block size, default and maximum 100 (101 returns 400). (tested)

### Fields per sign (current-state, GeoJSON properties) (15)
`id` uuid, `rvvCode` tekst, `blackCode` tekst, `zoneCode` tekst, `status` tekst, `validated` j/n, `textSigns` lijst, `placement / side / bearing` tekst / graden, `fraction` getal, `drivingDirection` tekst, `roadName / roadNumber / roadSectionId / nwbVersion` tekst / getal / datum, `countyCode / countyName / townName` tekst, `imageUrl` url, `firstSeenOn / lastSeenOn / placedOn / removedOn` datum, `trafficOrderUrl` tekst

### Limits and pitfalls
- current-state has no paging: without a filter you get the whole country. rvvCode=A1 alone is 97 MB, Amsterdam 56 MB. Always filter, or use the download file. (experience)
- events: at most 100 per call (limit=101 returns 400). (tested)
- No key and no documented rate limit; filtered requests answered within 0.1 seconds. (tested)
- The documentation still mentions data.ndw.nu and the parameter names rvv-code and road-section-ids. The OpenAPI specification and the working API use wegkenmerken.ndw.nu/api with rvvCode and roadSectionId. The old v1 addresses on data.ndw.nu return 404. (tested)
- An unknown parameter is silently ignored (foo=bar simply returned 73 signs). A typo in a filter name therefore quietly returns the unfiltered, much larger response. (tested)
- events has no publication timestamp in the response, even though offset works on it. Keep the time of your last call yourself and read on from there; an event may then arrive twice. (tested)
- In events the structure differs from current-state: location.wgs84.latitude, location.road.roadSectionId, location.county.code, details.imageUrl. current-state is flat. (tested)
- Join roadSectionId to the NWB (wvk_id), but mind nwbVersion: road sections change between NWB versions. (experience)
- wegkenmerken.ndw.nu has no robots.txt (the web app returns its start page for every path); data.ndw.nu redirects robots.txt to a page with Disallow: /. That is why we did not call the accessibility map. (tested)

### Example
```
https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/current-state?rvvCode=C22a&countyCode=GM0363
```

## How to fetch it

### curl
```bash
curl "https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/current-state?rvvCode=C22a"
```

### python
```python
import requests, collections

url = "https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/current-state"
borden = requests.get(url, params={"rvvCode": "C22a"}).json()["features"]
print(collections.Counter(b["properties"]["countyName"] for b in borden).most_common(10))
```

## What you can build with it
- [Dashboard of traffic jams, speeds and roadworks](https://www.opendataindex.nl/en/bouwen/files-en-wegwerkzaamheden.md): A dashboard showing every minute how fast traffic moves on the motorways, where it is at a standstill and which roads are closed, from NDW's open files, with the speed limit from the signs on site.


## Examples with real figures (1)

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

- **C22a traffic signs (low-emission zone) per municipality: most Amsterdam (91 signs), then Rotterdam and Arnhem** (oktober 2026). Table traffic-signs v4 current-state, rvvCode C22a. [Example](https://www.opendataindex.nl/en/voorbeeld/ndw-milieuzoneborden-gemeenten)
  - `https://wegkenmerken.ndw.nu/api/rest/static-road-data/traffic-signs/v4/current-state?rvvCode=C22a`
