.claude/skills/wiewaswie/SKILL.md
Search Dutch civil registry records (births, marriages, deaths) on WieWasWie.nl via direct JSON API calls, with Open Archives API as a secondary source and Playwright browser automation as fallback. Use this skill whenever you need to look up or verify a person in Dutch civil records, check a birth/marriage/death date against official archives, or find parents/spouses from indexed Burgerlijke Stand records. Triggers on: "look up on wiewaswie", "check the birth record", "find the marriage certificate", "verify this date in the civil registry", "/wiewaswie", or any request to search Dutch genealogical records for a specific person. Also use when comparing GEDCOM data against official sources or when a Tier B verification is needed.
npx skillsauth add rdeknijf/ai-genealogy-kit wiewaswieInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Search the WieWasWie database (252M+ indexed Dutch civil registry records) using direct HTTP API calls. This returns official archive-indexed data -- Tier B confidence in the genealogy project's verification framework.
WieWasWie exposes a hidden JSON API that the Angular frontend uses. This is the same data as the browser UI but returns in ~0.2 seconds instead of ~20 seconds via Playwright.
Make a POST request to the WieWasWie search API:
curl -s -X POST "https://www.wiewaswie.nl/Umbraco/Api/nl-NL/Service/GetSearchResults" \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (compatible; genealogy-research/1.0)" \
-d '{
"SearchTerm": "",
"Page": 1,
"IsAdvancedSearch": true,
"PersonA": {
"Achternaam": "<SURNAME>",
"Tussenvoegsel": "<PREFIX_OR_EMPTY>",
"Voornaam": "<FIRSTNAME_OR_EMPTY>",
"Patroniem": "<PATRONYMIC_OR_EMPTY>",
"Beroep": "",
"Rol": "",
"VoornaamSearchType": 3,
"TussenvoegselSearchType": 3,
"AchternaamSearchType": 3,
"PatroniemSearchType": 3,
"BeroepSearchType": 3,
"WithoutTussenvoegsel": false
},
"PersonB": {
"Voornaam": "",
"Tussenvoegsel": "",
"Achternaam": "",
"Patroniem": "",
"Beroep": "",
"Rol": "",
"VoornaamSearchType": 3,
"TussenvoegselSearchType": 3,
"AchternaamSearchType": 3,
"PatroniemSearchType": 3,
"BeroepSearchType": 3,
"WithoutTussenvoegsel": false
},
"PeriodeVan": "<YEAR_FROM_OR_EMPTY>",
"PeriodeTot": "<YEAR_TO_OR_EMPTY>",
"Land": "",
"Regio": "",
"Plaats": "<PLACE_OR_EMPTY>",
"PlaatsSearchType": 3,
"DocumentType": "<DOCTYPE_OR_EMPTY>",
"SortColumn": "lastname.sort",
"SortDirection": 1,
"FacetCollectieGebied": "",
"FacetOrganisatie": "",
"FacetRol": ""
}'
SearchType values: 1 = StartsWith, 2 = Synonym, 3 = Exact
DocumentType values: "BS Geboorte", "BS Huwelijk", "BS Overlijden", or "" for all.
Response structure:
{
"Total": 5,
"Persons": [
{
"SourceDocumentId": "55972978",
"PersonId": "55972978|1",
"Voornaam": "Gijsbert",
"HasTussenvoegsel": true,
"Tussenvoegsel": "de",
"Achternaam": "Knijf",
"Patroniem": "",
"AktePlaats": "Ede",
"AkteDatum": "11-11-1848",
"DocumentType": "BS Geboorte",
"HasScan": false
}
],
"Message": "",
"Aggs": { ... }
}
The Aggs field contains facet counts for Role, Organization, Sourcetype, and
CollectionRegion, plus min/max date ranges. These help narrow searches.
Fetch the detail page using the SourceDocumentId. This requires a session
cookie from WieWasWie (the detail page returns 403 without one).
Get a session cookie first (one-time per session):
curl -s -c /tmp/wiewaswie_cookies.txt -L "https://www.wiewaswie.nl/nl/zoeken/" \
-H "User-Agent: Mozilla/5.0 (compatible; genealogy-research/1.0)" -o /dev/null
Fetch the detail page:
curl -s -b /tmp/wiewaswie_cookies.txt \
"https://www.wiewaswie.nl/nl/detail/<SourceDocumentId>" \
-H "User-Agent: Mozilla/5.0 (compatible; genealogy-research/1.0)"
Parse the HTML for <dt> / <dd> pairs. The detail page contains:
BS Geboorte (birth):
BS Huwelijk (marriage):
BS Overlijden (death):
Use Python or grep to extract <dt>/<dd> pairs from the HTML:
import re
html_content = "..." # the fetched HTML
pairs = re.findall(r'<dt[^>]*>(.*?)</dt>\s*<dd[^>]*>(.*?)</dd>', html_content, re.DOTALL)
for label, value in pairs:
label = re.sub(r'<[^>]+>', '', label).strip()
value = re.sub(r'<[^>]+>', '', value).strip()
print(f"{label}: {value}")
Also extract links from <dd> elements -- these contain links to related
records and to the original scan at the archive's website.
Open Archives (openarchieven.nl) provides a free REST API that covers many of the same records. Use it as a complement or when WieWasWie API is down. Especially useful because it provides direct URLs to archive detail pages.
Search endpoint:
GET https://api.openarchieven.nl/1.1/records/search.json?name=<query>&lang=nl&number_show=20
Parameters:
| Parameter | Description | Example | |-----------|-------------|---------| | name | Search query (supports year: "de Knijf 1848") | de Knijf | | name | Year range in name | de Knijf 1848-1900 | | eventplace | Filter by place | Ede | | sourcetype | Filter by source type | BS Geboorte | | number_show | Results per page (max 100) | 20 | | start | Pagination offset | 0 | | sort | Sort column (1-6, negative=desc) | 1 | | lang | Language (nl/en) | nl |
Rate limit: 4 requests per second per IP.
Response fields per result: personname, relationtype, eventtype, eventdate (with day/month/year), eventplace, sourcetype, archive name, archive_code, and a URL to the Open Archives detail page.
Record detail:
GET https://api.openarchieven.nl/1.1/records/show.json?archive_code=<code>&identifier=<id>&lang=nl
The show endpoint returns less detail than WieWasWie (typically just names, dates, document numbers, and scan URLs -- no parents/ages/occupations). Use it mainly for the scan links and archive references.
Match endpoint (for quick person matching):
GET https://api.openarchieven.nl/1.0/records/match.json?name=<surname>&birthyear=<year>&lang=nl
If both APIs fail (e.g., server maintenance, rate limiting, unexpected errors), fall back to the original browser workflow.
browser_navigate -> https://www.wiewaswie.nl/nl/zoeken/?advancedsearch=1
Use browser_fill_form with these fields:
| Field | Label | Type | Notes | |-------|-------|------|-------| | Surname | "Achternaam" | textbox | | | Prefix | "Tussenvoegsel" | textbox | "de", "van", etc. | | First name | "Voornaam" | textbox | | | Patronymic | "Patroniem" | textbox | | | Year from | first spinbutton | spinbutton | These are spinbuttons, not textboxes | | Year to | second spinbutton | spinbutton | Same -- spinbutton | | Place | "Plaats" | textbox | Use the municipality name |
Click the "Zoek" button, then take a snapshot. Results appear as a table: Achternaam, Voornaam, Patroniem, Plaats, Datum, Documenttype, Scan.
Click the result row. The detail view loads inside an iframe -- take a snapshot after clicking to read its content.
The iframe uses term/definition pairs (<dt>/<dd>). See the detail field
descriptions above.
Dutch civil records carry two dates, and confusing them is a common source of errors in family trees:
Births were typically registered 1-3 days after the actual birth. The search results in WieWasWie show the registration date (AkteDatum). The detail view shows both. For GEDCOM, use the gebeurtenisdatum (the actual birth date).
Dutch civil records use the municipality (gemeente), not the village. If a village name returns no results, try the municipality instead:
## WieWasWie Result -- [document type]
**Person:** [name]
**Event:** [type], [gebeurtenisdatum] in [gebeurtenisplaats]
**Registered:** [registratiedatum] in [akteplaats]
**Father:** [name], [occupation], age [age]
**Mother:** [name], [occupation]
**Archive:** [erfgoedinstelling], archief [nr], reg [nr], akte [nr]
**Collection:** [collectie]
**Scan:** [naar bron URL if available]
**Linked records:** [list any gelinkte akten]
**Confidence:** Tier B -- official civil registry record from [archive name]
Critical insight: Before ~1811, Dutch church records (DTB) used patronymics (father's first name as child's surname), not fixed family surnames. WieWasWie indexes these records under the patronymic form, so surname searches fail for people born before ~1780.
Example: Hendrik Jeths (b. 1767) is indexed as "Hendrik Aarts Jets" -- patronymic "Aarts" (son of Aart) + variant spelling "Jets". Searching for surname "Jeths" returns zero results.
Instead of searching by surname, search by first name + role + place + date range:
{
"PersonA": {
"Voornaam": "Hendrik",
"Achternaam": "",
"Rol": "kind"
},
"PeriodeVan": "1765",
"PeriodeTot": "1770",
"Plaats": "Beekbergen",
"DocumentType": "DTB Dopen"
}
This returns ALL children named Hendrik baptized in Beekbergen 1765-1770. Scan the results for patronymics matching the expected father's name.
| Indexed name | Meaning | Family surname | |-------------|---------|----------------| | Hendrik Aarts Jets | Hendrik, son of Aart Jets | Jeths | | Aart Rijkse | Aart, son of Rijk | Jeths | | Rijk Aarts | Rijk, son of Aart | Jeths | | Aert Isacks | Aert, son of Isaac | Jeths | | Jan Riksen | Jan, son of Rijk | Jeths |
The surname "Jets/Jeths/Jethsen" appears intermittently alongside patronymics. Church records may use surname, patronymic, or both depending on the minister.
This technique found 4 baptism records in the Jeths line (1666-1767) that were invisible to surname searches, enabling verification back to 1666.
For batch lookups (e.g., verifying an entire family line), use this sequence:
Each lookup takes ~0.5s total (search + detail) vs ~20s with Playwright. For a 30-person hardening run, that is ~15 seconds vs ~10 minutes.
Not all civil registry records are indexed on WieWasWie. When a lookup returns no results, it may be an indexing gap rather than a missing record. Check the patterns below before concluding a record doesn't exist.
Confirmed gap (2026-03-20): Three independent lookups for Ede deaths in 1816, 1826, and 1832 all failed, while records from the same Gelders Archief collection (0207) in neighboring municipalities (Apeldoorn, Scherpenzeel, Zutphen, Putten) for the same period ARE indexed. An Ede death from 1833 WAS found, suggesting the gap ends around 1832-1833.
Workaround: For Ede deaths before ~1833, skip WieWasWie and go directly to Gelders Archief scans via their online beeldbank or request the relevant register pages.
Death record of Aletta Bos (d. 1906, De Bilt) not found. De Bilt is in Utrecht province (Het Utrechts Archief, not Gelders Archief). These records may not be indexed yet.
Confirmed gap (2026-03-20): Apeldoorn BS Huwelijk indexing stops after December 1947. Apeldoorn BS Geboorte is not indexed at all for the 20th century. Death records continue through at least 1960. All indexed records come from Gelders Archief collection 0207A ("Burgerlijke stand Gelderland, dubbelen 1903-1980"). The scans exist in the collection, but the person index is incomplete.
Workaround: Browse Gelders Archief scans directly (requires Playwright for scan viewer navigation), or contact CODA Apeldoorn (coda-apeldoorn.nl/archief) for the original registers.
The JSON API and detail page work without CBG login for basic searches. Premium features (wildcards, PersonB searches for two people at once) are not available without login. The detail page needs a session cookie but not authentication.
development
Search the VOC Opvarenden database for Dutch East India Company crew records (1699-1794). Uses the Nationaal Archief HUB3 API — 853,785 indexed entries with rich detail: name, origin, rank, ship, fate (died/returned/deserted), service dates, VOC chamber, and links to original scans. Use this skill when: "search VOC records", "VOC crew", "VOC opvarenden", "sailed to Batavia", "Dutch East India Company", "VOC soldier", "VOC sailor", "/voc-opvarenden", or when looking for ancestors who may have sailed with the VOC. Also use when checking Daniel Pieterse Knijf (1704, Woerden) or any Knijf/Knijff VOC connections. No login required.
tools
Generate a scan verification page for the user to review AI-extracted genealogy findings against actual document scans. The user clicks through records, confirms or rejects each one, and confirmed records become Tier A evidence in FINDINGS.md. Use this skill when: "verify scans", "show me what needs verifying", "review pending scans", "scan verification", "/verify-scans", or when the user wants to upgrade research findings from Tier C/D to Tier A by visually confirming document scans. Also use after a research session that produced scan-backed findings that need human confirmation.
tools
Search indexed person records at Streekarchief Midden-Holland (samh.nl) via the Memorix Genealogy REST API. No browser automation needed — returns structured JSON in ~50ms per query. Based in Gouda, covers municipalities: Gouda, Haastrecht, Schoonhoven, Waddinxveen, Noord-Waddinxveen, Moerkapelle, Moordrecht, Ammerstol, Broek, Vlist, and surrounding areas in the Midden-Holland region of South Holland. 3M+ person records with DTB (doop/trouw/begraven), BS (geboorte/huwelijk/overlijden), and Inschrijvingaktes. 36 Knijf results found, including Gijsbert de Knijf records in Gouda and van der Knijf in Waddinxveen. Scans available for most records. Triggers on: "search Gouda archive", "Streekarchief Midden-Holland", "SAMH", "Haastrecht records", "Schoonhoven records", "/streekarchief-midden-holland", or any genealogy research in the Gouda/Midden-Holland area. No login required. Parallelizable — run multiple queries simultaneously.
testing
Create annotated genealogy narrative PDFs with Typst — engaging family stories with academic footnotes, historical images, and beautiful typography. Use this skill when: "write a story about the X line", "create a story for Y", "make a PDF about this family", "/story", "story for my parents", or any request to produce a narrative document about a family line or ancestor. Also trigger when the user wants to turn research findings into a presentable document for family members. Language defaults to Dutch unless specified otherwise.