# Election results from the Electoral Council

The official results of all elections: House of Representatives, municipal council, provincial, water board, European Parliament and referendums. The results database goes back to 1848 and has a CSV per municipality for each election. For recent elections data.overheid.nl also has the count files (EML) with votes per polling station and per candidate.

- Publisher: Kiesraad
- Area: Netherlands · Finest detail: polling station
- Period: 1848 – 2026 · Refreshed: yearly
- Access: Open · Licence: CC0 1.0 (Kiesraad)
- Join keys: gemeentecode (G0518), partijnaam, kandidaatnummer
- Status: ok (2026-03-18) · nieuwste verkiezing in de databank: GR20260318
- URL: https://www.verkiezingsuitslagen.nl

## What can you do with it?
- **Where did each party win?.** Download the results per municipality of the 29 October 2025 general election and colour a map by largest party. Nationally D66 and PVV each won 26 seats.
- **Turnout over the years.** The database has eligible voters and turnout per election. In 2025, 78.3% of the 13,589,128 eligible voters turned out. Put the general elections side by side.
- **Preference votes per candidate.** The 2026 municipal election CSV shows per municipality how many votes each candidate received. Find candidates who overtook higher-placed names with preference votes.
- **Votes per polling station next to the neighbourhood.** Take the votes per polling station from the EML count files, find where each polling station is, and compare with CBS neighbourhood figures. Note: voters may vote anywhere in their municipality.

## How to process it
1. **Pick the election in the database.** Each election has a code: type plus date, for example TK20251029 or GR20260318. You find them on the database home page.
   `https://www.verkiezingsuitslagen.nl/verkiezingen`
2. **Download the results per municipality.** A semicolon CSV: municipality, code, party, number of votes. The 2025 general election is 359 kB.
   `https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten`
3. **For polling stations and candidates, go to data.overheid.nl.** There you find a dataset per election with EML files (XML) and often a CSV. Search for 'verkiezingsuitslag' with the Kiesraad as owner.
   `https://data.overheid.nl/data/api/3/action/package_search?q=verkiezingsuitslag&fq=authority:%22http://standaarden.overheid.nl/owms/terms/Kiesraad%22&rows=50`
4. **Read the long format.** The 2026 municipal CSV has one value per row: the VeldType column says what it is (Kiesgerechtigden, Opkomst, KandidaatAantalStemmen …), the Waarde column holds the number. Pivot the table before calculating.
   `https://data.overheid.nl/sites/default/files/dataset/09cf04e7-11ac-4b53-a2cc-baccf95e82fd/resources/GR2026.csv`

## Interesting combinations
- Do higher-income municipalities vote differently? → [cbs-kwb](https://www.opendataindex.nl/en/bron/cbs-kwb.md) via gemeentecode (GM). Turn G0518 into the CBS code GM0518 and join to average income. Use the municipal boundaries of the election year.
- Do parties in the House vote the way their voters in your municipality would expect? → [tweedekamer-opendata](https://www.opendataindex.nl/en/bron/tweedekamer-opendata.md) via partijnaam en fractie. Party names differ between the sources ('PVV (Partij voor de Vrijheid)' in the results). Build your own lookup table first.

## Similar sources
- [tweedekamer-opendata](https://www.opendataindex.nl/en/bron/tweedekamer-opendata.md): What happens after the election: parties with their seats, motions and votes in the House.
- [openraadsinformatie](https://www.opendataindex.nl/en/bron/openraadsinformatie.md): What elected municipal councils decide afterwards, from council information systems.

## What to watch out for
- **Every election has a different format.** The 2025 general election CSV has one row per party per municipality; the 2026 municipal one is long (VeldType and Waarde) and includes candidates. Older datasets mix EML, Excel and other municipal files. Write a separate reader per election.
- **Polling station CSV without municipality.** Where the database has polling stations (some elections since 2012), the CSV lacks the municipality: code SB25 occurs in many municipalities. Use the EML files per municipality for polling stations. For the 2025 general election the polling station CSV is empty.
- **EML is XML without support.** The Electoral Council itself says it offers no support for the EML format. The files come in large zips, for the 2025 general election in three parts.
- **Provisional or final.** The 2026 municipal dataset calls its own data provisional. Re-votes (Gorinchem, 29 April 2026) and merger elections are listed separately. Read the notes of each dataset.
- **Municipal boundaries shift.** Because of mergers, municipalities from an old election may no longer exist. Next to the municipality code the database gives an 'AmsterdamseCode' (historical code). Compare series only on the same boundaries.

## API (Bestanden (CSV) + JSON van de website)

- Base: https://www.verkiezingsuitslagen.nl
- Access: No key or account needed (tested)
- Formats: csv, json, eml/xml
- Size: 176 elections in the database, 1848 to 2026 (list pages, 16 Oct 2026) (experience)
- Filtering: No filters: one file per election. Filter yourself on the Code (municipality) or Partij column.; 

### Endpoints
- `GET /uitslag/verkiezing/{code}/gemeenten`: CSV with the result per municipality and party (semicolon, UTF-8 without BOM). TK2025: 359 kB, 8,150 lines, 343 codes, 27 parties.
- `GET /uitslag/verkiezing/{code}/stembureaus`: CSV per polling station and party. Only filled for some elections (GR2022: 8.7 MB); for TK2025, PS2023, EP2024 only the header line.
- `GET /verkiezingen/detailJson/{code}`: JSON the site uses for the detail page: Info (name, date, remark), Stemregio (electorate, turnout, valid, blank and invalid votes), PieChart (votes and percentage per party), Regios (provinces, electoral districts). Undocumented.
- `GET /verkiezingen/detail/{code}`: Detail page (HTML); the national result with seats is JSON inside <textarea id="UitslagData">.
- `GET /Verkiezingen/index/{pagina}?v=1800&t=2027`: List of elections (HTML, 10 per page) with codes, turnout and votes cast. This is where you find the codes.

### Parameters
- `code`: Election code = type + date YYYYMMDD: TK (House of Representatives), EK, EP, PS, WS, GR (municipal council), ER, NR/RR (referendum). E.g. TK20251029, GR20220316. (tested)

### Columns in the CSV per municipality (and per polling station) (7)
`Gemeente` tekst, `Code` tekst, `AmsterdamseCode` tekst, `Partij` tekst, `AantalStemmen` getal, `AantalZetels` getal, `Stembureau` tekst

### Limits and pitfalls
- No key and no documented limit. One file per election, usually a few hundred kB. (tested)
- The Azure firewall rejects the default Python requests User-Agent (HTTP 403). Always set your own User-Agent; curl and an honest UA work. (tested)
- An unknown election code returns HTTP 500 with an empty body, not 404. (tested)
- The polling-station CSV has no municipality column: codes like SB25 occur in many municipalities. For polling stations use the per-municipality EML files from data.overheid.nl. (tested)
- In detailJson, counts in Stemregio are Dutch-formatted text ("13.589.128", "78,3%"); in PieChart they are numbers. (tested)
- Skip codes from G9000 when counting municipalities; join on code, not name (Bergen NH G0373 and Bergen L G0893). (experience)
- Formats on data.overheid.nl differ per election (EML zips, wide or long CSV, Excel). Its CKAN API (/data/api/…) falls under Disallow: /data/ in robots.txt; the files themselves (/sites/default/files/…) do not. (tested)

### Example
```
https://www.verkiezingsuitslagen.nl/verkiezingen/detailJson/TK20251029
```

## How to fetch it

### curl
```bash
curl -o tk2025-gemeenten.csv "https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten"
```

### python
```python
import csv, io, requests

# Zonder eigen User-Agent geeft de site 403 (de standaard van requests wordt geweigerd).
kop = {"User-Agent": "mijn-onderzoek/1.0 (+jij@voorbeeld.nl)"}
r = requests.get("https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten", headers=kop)
rijen = csv.DictReader(io.StringIO(r.content.decode("utf-8-sig")), delimiter=";")
utrecht = [x for x in rijen if x["Code"] == "G0344"]
for x in sorted(utrecht, key=lambda x: -int(x["AantalStemmen"]))[:5]:
    print(x["Partij"], x["AantalStemmen"])
```

## What you can build with it
- [Election map: result, shift and turnout per municipality](https://www.opendataindex.nl/en/bouwen/verkiezingskaart.md): A map of all 342 municipalities with the largest party, the gain or loss since the previous election and the turnout, next to income per resident.


## What is in it: 176 elections

All elections in the Kiesraad's election results database, by type and decade, fetched every night. Every election has its own page with the CSV per municipality and per polling station.

- Kinds: verkiezing 176
- With an API call on the dataset page: 176
- Search: https://www.opendataindex.nl/api/catalogus/kiesraad?q=… or the MCP function zoek_datasets with herkomst=kiesraad
- Every row has its own page: https://www.opendataindex.nl/en/dataset/kiesraad/<key>

### Folders
- Tweede Kamer (64): 2020–2029 (3), 2010–2019 (3), 2000–2009 (3), 1990–1999 (2), 1980–1989 (4), 1970–1979 (3), 1960–1969 (2), 1950–1959 (3) …
- Eerste Kamer (6): 2020–2029 (1), 2010–2019 (3), 2000–2009 (2)
- Europees Parlement (10): 2020–2029 (1), 2010–2019 (2), 2000–2009 (2), 1990–1999 (2), 1980–1989 (2), 1970–1979 (1)
- Provinciale Staten (23): 2020–2029 (1), 2010–2019 (3), 2000–2009 (2), 1990–1999 (3), 1980–1989 (2), 1970–1979 (3), 1960–1969 (2), 1950–1959 (3) …
- Waterschap (3): 2020–2029 (1), 2010–2019 (2)
- Gemeenteraad (60): 2020–2029 (5), 2010–2019 (12), 2000–2009 (3), 1990–1999 (3), 1980–1989 (8), 1970–1979 (8), 1960–1969 (6), 1950–1959 (10) …
- Eilandsraad (5): 2020–2029 (2), 2010–2019 (3)
- Kiescollege (2): 2020–2029 (1), 2010–2019 (1)
- Nationaal referendum (3): 2010–2019 (2), 2000–2009 (1)

## Examples with real figures (3)

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

- **Votes for D66, 2025 general election: highest in Heemstede (29.5%), lowest in Urk (0.7%)** (oktober 2025). Table TK20251029. [Example](https://www.opendataindex.nl/en/voorbeeld/kiesraad-tk2025-d66-gemeente)
  - `https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten`
  - `https://www.verkiezingsuitslagen.nl/verkiezingen/detail/TK20251029`
- **Votes for the PVV, 2025 general election: highest in Rucphen (46.2%), lowest in Rozendaal (5.1%)** (oktober 2025). Table TK20251029. [Example](https://www.opendataindex.nl/en/voorbeeld/kiesraad-tk2025-pvv-gemeente)
  - `https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten`
  - `https://www.verkiezingsuitslagen.nl/verkiezingen/detail/TK20251029`
- **Votes per party in the 2025 House of Representatives election: most D66 (1,790,634 votes), then PVV (Partij voor de Vrijheid) and VVD** (oktober 2025). Table TK20251029. [Example](https://www.opendataindex.nl/en/voorbeeld/kiesraad-tk2025-stemmen)
  - `https://www.verkiezingsuitslagen.nl/verkiezingen/detail/TK20251029`
  - `https://www.verkiezingsuitslagen.nl/uitslag/verkiezing/TK20251029/gemeenten`
