# NL Vergunningen & Bekendmakingen Leadfeed (`codeclouds/nl-vergunningen-leadfeed`) Actor

Fresh Dutch permit announcements (omgevingsvergunningen, bekendmakingen) as structured leads with address extraction. Filter by municipality, type and keyword.

- **URL**: https://apify.com/codeclouds/nl-vergunningen-leadfeed.md
- **Developed by:** [Dennis](https://apify.com/codeclouds) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 0 monthly users, 84.6% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 lead-results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## NL Vergunningen & Bekendmakingen Leadfeed 🇳🇱

Get **fresh Dutch permit announcements** (omgevingsvergunningen, bouwvergunningen, official municipal publications) as **structured, ready-to-use leads** — with automatic address and postal code extraction.

Every working day, Dutch municipalities publish thousands of permit applications and decisions on officielebekendmakingen.nl. Each one is a potential customer signal: someone is about to build, renovate, demolish, or install. This actor turns that public stream into a clean lead feed you can filter by municipality, permit type, and keyword.

### Who is this for?

- **Construction & renovation companies** — spot new building projects the moment the permit is filed
- **Solar panel & heat pump installers** — find homeowners investing in their property
- **Real estate professionals** — track development activity per neighbourhood
- **Architects & permit consultants** — monitor competitors and find clients whose applications were rejected
- **Legal professionals** — track objection deadlines on decisions in your area
- **Market researchers & data teams** — feed Dutch construction activity into your models
- **AI agents** — structured JSON output, ideal as a tool for agentic workflows (MCP-ready)

### When should an AI agent use this?

Point an AI agent at this actor when a user asks things like:

- "Which new omgevingsvergunning applications were published this week in Amsterdam, Haarlem and Amstelveen?"
- "Find me leads for solar panel installations — search recent bekendmakingen for the keyword 'zonnepanelen'."
- "Give me the addresses and postal codes of all building permits filed in Eindhoven so I can plan site visits."
- "Monitor demolition permits ('slopen') nationwide published after 1 July 2026."
- "Has anything new been published for my municipality since yesterday?" (using incremental mode)
- "Pull the official publication text and PDF link for a specific permit announcement so I can review it."

### What data do you get?

Each result is one official publication, enriched for lead generation:

```json
{
  "id": "gmb-2026-319945",
  "title": "Aanvraag omgevingsvergunning Sint Antoniesbreestraat 10 1011HB Amsterdam",
  "type": "omgevingsvergunning",
  "municipality": "Amsterdam",
  "authorityType": "Gemeente",
  "publishedDate": "2026-07-06",
  "subjects": ["Ruimte en infrastructuur | Organisatie en beleid"],
  "workCategories": [],
  "postalCode": "1011 HB",
  "addressGuess": "Sint Antoniesbreestraat 10",
  "urlHtml": "https://zoek.officielebekendmakingen.nl/gmb-2026-319945.html",
  "urlPdf": "https://repository.overheid.nl/frbr/officielepublicaties/gmb/2026/gmb-2026-319945/1/pdf/gmb-2026-319945.pdf",
  "source": "officielebekendmakingen",
  "isRectification": false,
  "linkedOriginal": null
}
```

- **`postalCode` and `addressGuess`** are extracted automatically from the title — ready for CRM import, geocoding, or direct mail
- **`urlHtml` / `urlPdf`** link to the full official publication
- **`subjects`** carry the official government taxonomy (housing, environment, infrastructure, …)
- **`isRectification`**: always computed for free — `true` when the title contains "rectificatie"
- **`linkedOriginal`**: only filled with `linkRectifications` enabled and `isRectification: true` — the most
  recently seen publication for the same address+municipality, so a rectification isn't mistaken for a
  separate, duplicate lead. `null` if no match was found (or the feature is off)

#### Rectification linking (`linkRectifications`, optional, free)

With `linkRectifications: true`, a rectification is linked to the most recently seen publication (original or
an earlier rectification) for the same address+municipality, across runs via the actor's key-value store. This
prevents rectifications — which republish the same case with a correction — from looking like a brand-new,
separate lead in a CRM import.

#### Run summary (`includeSummary`, optional, free)

With `includeSummary: true`, one extra dataset item is pushed at the end of the run — no extra charge:

```json
{
  "type": "trend-samenvatting",
  "totaalLeads": 42,
  "perGemeente": { "Amsterdam": 30, "Utrecht": 12 },
  "perDocumentType": { "omgevingsvergunning": 42 },
  "perGemeenteTrend": { "Amsterdam": 5, "Utrecht": -2 },
  "perDocumentTypeTrend": { "omgevingsvergunning": 3 }
}
```

`perGemeenteTrend`/`perDocumentTypeTrend` are only filled in `incrementalMode`, once a previous run's counts
are available (`null` otherwise) — the delta vs. that previous incremental run, per key.

### Input options

| Field | Description | Example |
|---|---|---|
| `documentTypes` | Publication types (rubriek) | `["omgevingsvergunning"]` |
| `municipalities` | Limit to specific municipalities | `["Amsterdam", "Utrecht"]` |
| `keyword` | Free-text filter | `"zonnepanelen"`, `"dakkapel"`, `"kappen"` |
| `publishedAfter` | Only publications from this date | `"2026-07-01"` |
| `maxResults` | Cap the number of results | `100` |
| `incrementalMode` | Only new items since previous run | `true` |
| `enrichWithGeocoding` | Geocode each lead via PDOK, adding coordinates + gemeente/buurt code + BAG ID | `true` |
| `linkAanvraagBesluit` | Link a later decision (verleend/geweigerd) to an earlier application for the same address+municipality, across runs | `true` |
| `linkRectifications` | Link a rectification to the most recently seen publication (original or an earlier rectification) for the same address+municipality, across runs. Free enrichment | `true` |
| `includeSummary` | Add one extra dataset item per run with counts per municipality/document type, plus (in `incrementalMode`) the trend vs. the previous run. Free | `true` |

#### Common `documentTypes` values

- `omgevingsvergunning` — environmental/building permits (applications *and* decisions)
- `andere vergunning` — other permits (events, hospitality, parking, …)
- `ruimtelijk plan of omgevingsdocument` — zoning plans and spatial documents
- `mededelingen` — general municipal announcements

### Typical use cases

**Daily lead feed for a solar installer in the Randstad:**

```json
{
  "documentTypes": ["omgevingsvergunning"],
  "municipalities": ["Amsterdam", "Haarlem", "Amstelveen"],
  "keyword": "zonnepanelen",
  "incrementalMode": true
}
```

Schedule this daily and receive only *new* permit publications each morning — perfect for feeding a CRM, Slack channel, or e-mail digest via Apify integrations.

**Nationwide monitoring of demolition permits:**

```json
{
  "documentTypes": ["omgevingsvergunning"],
  "keyword": "slopen",
  "publishedAfter": "2026-07-01",
  "maxResults": 500
}
```

**All new publications in your municipality:**

```json
{
  "documentTypes": ["omgevingsvergunning", "andere vergunning"],
  "municipalities": ["Eindhoven"]
}
```

### Scheduling & integrations

Combine this actor with Apify's built-in features:

- **Schedules** — run every morning at 08:00 and start your day with fresh leads
- **Integrations** — push results to Google Sheets, Slack, Zapier, Make, or any webhook
- **API** — fetch the dataset as JSON, CSV or Excel from your own code
- **MCP** — expose this actor as a tool for AI agents (Claude, Cursor, and other MCP clients)

### Data source & legality

This actor uses the **official public SRU API** of the Dutch government (KOOP / repository.overheid.nl, the source behind officielebekendmakingen.nl). These are official government publications, published by law and explicitly intended for public reuse (Dutch open government data policy).

- ✅ No scraping of protected websites — official open data API only
- ✅ No login, no terms-of-service conflicts
- ✅ Publications concern permits and public decisions; the actor only processes what the government itself publishes
- ⚠️ Publications may contain addresses. If you build a marketing database on top of this feed, you are responsible for your own GDPR compliance as data controller (e.g. informing recipients, honouring opt-outs)

### Pricing

Pay per result: you are only charged for leads actually delivered. A daily incremental run for one municipality typically returns 5–50 results. With `enrichWithGeocoding` enabled, a lead that gets a PDOK match is billed at the higher **`geocoded-lead`** rate instead of the base `lead-result` rate — leads without a match (or when the option is off) are billed normally. With `linkAanvraagBesluit` enabled, a decision lead that gets linked to an earlier application is additionally billed the **`linked-decision`** event ($0.01), on top of its base rate.

### FAQ

**How fresh is the data?** Publications appear in the feed the same day the municipality publishes them.

**Which municipalities are covered?** All Dutch municipalities, provinces, and water authorities — everything published on officielebekendmakingen.nl.

**Can I get the full publication text?** Each lead includes direct links to the official HTML and PDF versions.

**How do I get only new items?** Enable `incrementalMode` and schedule the actor; it remembers the date of the previous run.

**What does `geocoded` contain?** When `enrichWithGeocoding` is on, each lead gets a `geocoded` field with `lat`/`lon`/`gemeentecode`/`buurtcode`/`bagAdresseerbaarObjectId` from the public PDOK Locatieserver, or `null` if no PDOK match was found for the lead's address guess/postcode (not charged in that case).

**What is `status` and `linkedAanvraag`?** Every lead gets a title-based `status` (`aanvraag`, `besluit_verleend`, `besluit_geweigerd` or `onbekend`) at no extra cost. With `linkAanvraagBesluit` enabled, a decision (`besluit_verleend`/`besluit_geweigerd`) is compared against previously seen applications for the same address+municipality (tracked across runs in the actor's key-value store) — a match fills `linkedAanvraag` with the earlier application's `id`/`publishedDate` and is billed the extra `linked-decision` event. Matching requires both a postal code and an address guess to be extracted from the title; without one of those, linking isn't attempted (no charge).

### Related Actors

Also by this developer — Dutch/EU public-data actors that pair well with this one:

- **[PDOK Adres Geocoding & Buurtdata](https://apify.com/codeclouds/pdok-locatieserver)** — feed the `addressGuess`/`postalCode` fields from this actor straight into PDOK geocoding to get full coordinates, BAG IDs, and CBS neighbourhood demographics per lead.
- **[NL & EU Government Tenders Scraper](https://apify.com/codeclouds/nl-eu-tenders-scraper)** — the same "official government publication → structured lead" approach, applied to public procurement tenders instead of permits.
- **[NL CAO Wijzigingen Database](https://apify.com/codeclouds/nl-cao-wijzigingen-database)** — draws on the same official Staatscourant / officielebekendmakingen.nl publication stream, for collective labour agreement changes instead of permits.
- **[NL BESS Vergunningenmonitor](https://apify.com/codeclouds/nl-bess-vergunningenmonitor)** — the specialized, battery-storage-only version of this actor, on the same official publication stream.

***

*Zoekwoorden: bouwvergunning scraper, omgevingsvergunning API, bekendmakingen monitor, vergunningen leads, gemeente publicaties, bouwleads Nederland, permit monitoring Netherlands.*

### Keywords

omgevingsvergunning, bouwvergunning, bekendmakingen, leads, netherlands, permits, real-estate, gemeente

### Changelog

#### 0.5.0

- Added `linkRectifications`: links a rectification to the most recently seen publication for the same
  address+municipality, across runs. Free enrichment, no extra charge. The index is pruned the same way as
  `linkAanvraagBesluit`'s (24-month TTL) to prevent unbounded key-value-store growth.
- Added `includeSummary`: a free extra `trend-samenvatting` dataset item per run with counts per
  municipality/document type, and (in `incrementalMode`) the trend vs. the previous run.
- Fixed `geocodeLead()` having no retry (unlike the SRU fetch in the same actor): a transient PDOK 5xx no
  longer permanently degrades a lead to unenriched — it now retries with the same exponential backoff as the
  SRU call. No pricing change.

#### 0.4.2 - Bugfix

- The `linkAanvraagBesluit` application index is no longer unbounded: an entry is removed as soon as it's
  matched to a decision, and any entry older than 24 months without a match is pruned automatically. Prevents
  unlimited key-value-store growth and a rare false rematch when the same address+authority is reused for an
  unrelated later project.

#### 0.4.1 - Bugfix

- Fixed `incrementalMode` and `linkAanvraagBesluit` never seeing prior-run state: the actor was
  reading/writing to Apify's per-Run *default* key-value store, which is not shared between separate runs. Now
  uses a named, persistent key-value store. A new baseline will be captured on the next run.

#### 0.4.0

- Added `status` (always computed, free): title-based classification of each lead as `aanvraag`,
  `besluit_verleend`, `besluit_geweigerd` or `onbekend`.
- Added `linkAanvraagBesluit`: links a later decision to an earlier application for the same
  address+municipality across runs (via the actor's key-value store). New `linkedAanvraag` field and charged
  event `linked-decision` ($0.01), confirmed by the user (2026-07-14, see
  docs/actor-verbeteringen/PRIJSBESLISSINGEN.md). **Must be re-pushed** (`apify push`) — this actor is already
  live, and the new event must be created in Apify Console > Monetization first.

#### 0.3.0

- Added `enrichWithGeocoding` — optional server-side PDOK geocoding per lead, adding coordinates and
  gemeente/buurt code + BAG ID. New `geocoded-lead` event, only charged when a PDOK match is actually found;
  otherwise the lead is still billed at the base `lead-result` rate.

#### 0.2.0

- Added `workCategories` — a curated keyword classification (zonnepanelen/warmtepomp/dakkapel/aanbouw/sloop/
  verbouwing/nieuwbouw) derived from the title and subjects, so installers/builders can filter by project
  type without maintaining their own keyword list. Empty array means none of the known categories matched,
  not "no relevant work". No pricing change.

#### 2026-07-12 - Documentation update

- Added a "Related Actors" section cross-linking other actors by this developer.

#### 0.1.0 - Initial release

- Fetch Dutch permit announcements and municipal publications via the official KOOP SRU API
- Automatic address and postal code extraction from publication titles
- Filtering by document type, municipality, keyword and publish date
- Incremental mode to fetch only new publications since the previous run

# Actor input Schema

## `documentTypes` (type: `array`):

Publication types to include, e.g. "omgevingsvergunning", "andere vergunning", "ruimtelijk plan of omgevingsdocument".

## `municipalities` (type: `array`):

Municipality names, e.g. \["Amsterdam", "Utrecht"]. Leave empty for all of the Netherlands.

## `keyword` (type: `string`):

Free-text filter, e.g. "zonnepanelen", "dakkapel", "kappen".

## `publishedAfter` (type: `string`):

Only publications from on/after this date (YYYY-MM-DD), e.g. "2026-01-01".

## `maxResults` (type: `integer`):

Maximum number of leads to return (1–10000).

## `incrementalMode` (type: `boolean`):

Only fetch publications newer than the previous run. Ideal for scheduled monitoring.

## `enrichWithGeocoding` (type: `boolean`):

Geocode each lead's address/postcode via the public PDOK Locatieserver, adding coordinates, gemeente/buurt code and BAG ID. Charged at the higher geocoded-lead rate, but only when a PDOK match is actually found.

## `linkAanvraagBesluit` (type: `boolean`):

Links a later decision (verleend/geweigerd) to an earlier application (aanvraag) seen for the same address+municipality, across runs via the actor's key-value store. Only charged (linked-decision) when a link is actually found.

## `linkRectifications` (type: `boolean`):

Links a rectification to the most recently seen publication (original or an earlier rectification) for the same address+municipality, across runs via the actor's key-value store. Free enrichment, no extra charge.

## `includeSummary` (type: `boolean`):

Adds one extra dataset item per run with counts per municipality/document type, plus (in incrementalMode) the trend vs. the previous incremental run. Free, no extra charge.

## Actor input object example

```json
{
  "documentTypes": [
    "omgevingsvergunning"
  ],
  "municipalities": [],
  "publishedAfter": "2026-01-01",
  "maxResults": 100,
  "incrementalMode": false,
  "enrichWithGeocoding": false,
  "linkAanvraagBesluit": false,
  "linkRectifications": false,
  "includeSummary": false
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "publishedAfter": "2026-01-01"
};

// Run the Actor and wait for it to finish
const run = await client.actor("codeclouds/nl-vergunningen-leadfeed").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "publishedAfter": "2026-01-01" }

# Run the Actor and wait for it to finish
run = client.actor("codeclouds/nl-vergunningen-leadfeed").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "publishedAfter": "2026-01-01"
}' |
apify call codeclouds/nl-vergunningen-leadfeed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=codeclouds/nl-vergunningen-leadfeed",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Sa6uIdWxc2nkwEaNc/builds/JDO2lkEKLFT7pjyaj/openapi.json
