# NL BESS Vergunningenmonitor (`codeclouds/nl-bess-vergunningenmonitor`) Actor

Signaleert nieuwe Nederlandse omgevings- en milieuvergunningen voor batterijopslagsystemen (BESS), met classificatie op locatietype en vergunningscategorie.

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

## Pricing

from $40.00 / 1,000 bess-vergunning-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 BESS Vergunningenmonitor — Battery Storage Permit Tracker 🇳🇱🔋

Get **new Dutch battery storage (BESS) permit publications** — omgevingsvergunningen and provincial/municipal
"andere vergunning" filings for Battery Energy Storage Systems — as structured, ready-to-use leads.

The Dutch BESS market is in a steep growth curve (~350 MW operational end of 2024, TenneT expects 5-6 GW by
2030\), driven by grid congestion and the "use it or lose it" rule that pushes owners to actively use their
grid connection. Every new BESS project starts with a permit filing on officielebekendmakingen.nl — this
actor turns that public stream into a filtered, classified lead feed.

### When should an AI agent use this?

- "Which new battery storage permits were filed in the Netherlands this month?"
- "Find BESS permit applications near existing solar or wind parks — I'm scouting grid-connection
  opportunities."
- "Monitor new energieopslagsysteem permits in Noord-Holland and Overijssel."
- "Has any municipality published new BESS policy or permits since last week?" (using incremental mode)
- "Give me a nationwide feed of new BESS leads, only new items since yesterday."

### What this Actor does

- Searches Dutch official government publications (officielebekendmakingen.nl / KOOP SRU API) for BESS-related
  permit filings, decisions and policy documents
- Classifies each publication into `omgevingsvergunning`, `andere_vergunning`, or `overig`
- Flags publications that mention a nearby solar or wind park (`nearRenewablePark`) — a signal for
  grid-connection-driven BESS projects
- Best-effort extraction of a capacity mention (e.g. "5 MWh") when the title states one
- Extracts postal code / address guess from the title where present
- Supports incremental mode: only new publications since the previous run
- Adds one free summary record at the end of each run (counts per permit category/authority type, near-park
  and capacity-mention totals, list of unique authorities) — not charged, no extra event

### Who is this for?

- **BESS developers & EPC companies** (Sunrock, GES, HETTA, Chint Solar, and similar) — competitive
  intelligence on where and how fast BESS activity is growing
- **Investors & financiers** — early visibility into the project pipeline before systems go operational
- **Grid operators & municipalities** — overview of upcoming grid connection requests
- **Insurers & safety regions** — early sight of fire-safety-relevant BESS projects in their area (PGS 37-1)
- **BESS component suppliers** (battery cells, EMS systems, enclosures) — leads based on newly permitted
  projects

### Input

| Field | Type | Description |
|---|---|---|
| `municipalities` | array | Limit to specific municipalities or provinces, e.g. `["Almelo", "Noord-Holland"]`. Empty = all of the Netherlands. |
| `extraKeywords` | array | Additional free-text terms alongside the built-in BESS synonyms, e.g. `["accu-opslag"]`. Widens the search, does not replace the defaults. |
| `publishedAfter` | string | Only publications from on/after this date (`YYYY-MM-DD`). |
| `maxResults` | integer | Maximum number of leads to return (1-10000). Default `200`. |
| `incrementalMode` | boolean | Only fetch publications newer than the previous run. Default `false`. |
| `linkAanvraagBesluit` | boolean | Link a later decision to an earlier application for the same address+authority, across runs. Default `false`. |
| `verrijkMetVolledigeTekst` | boolean | Fetch the full publication text and re-check `nearRenewablePark`/`capacityMentionRaw` against it. Default `false`. |
| `staleAanvraagDrempelDagen` | integer | Requires `linkAanvraagBesluit: true`. Flags applications that have been in the tracked application index longer than this many days without a linked decision — a pipeline stall/delay signal. Leave empty to disable. |

The actor always searches for the built-in BESS synonyms (`batterijopslagsysteem`, `batterijenopslagsysteem`,
`batterijopslag`, `energieopslagsysteem`, `BESS`).

### Output

```json
{
  "id": "prb-2024-6825",
  "title": "Vergunning verleend - Westfrisiaweg 1, Zwaagdijk-Oost - Windpark Westfrisia B.V. - het realiseren van een batterijopslagsysteem (BESS)",
  "documentType": "omgevingsvergunning",
  "vergunningCategorie": "omgevingsvergunning",
  "authority": "Noord-Holland",
  "authorityType": "provincie",
  "publishedDate": "2024-05-13",
  "postalCode": null,
  "addressGuess": "Westfrisiaweg 1",
  "nearRenewablePark": true,
  "capacityMentionRaw": null,
  "urlHtml": "https://zoek.officielebekendmakingen.nl/prb-2024-6825.html",
  "urlPdf": "https://repository.overheid.nl/frbr/officielepublicaties/prb/2024/prb-2024-6825/1/pdf/prb-2024-6825.pdf",
  "source": "officielebekendmakingen",
  "status": "besluit_verleend",
  "linkedAanvraag": null,
  "volledigeTekstVerrijkt": false
}
```

**`capacityMentionRaw` is often `null`** — most Dutch BESS permit titles describe the location and permit
type, not the exact kWh/MWh capacity. Treat it as a bonus signal, not a reliable filter.

**`status`** is always computed for free (title-based: `aanvraag`, `besluit_verleend`, `besluit_geweigerd`, or
`onbekend`). With `linkAanvraagBesluit: true`, a decision is compared against previously seen applications for
the same address+authority (tracked across runs) — a match fills `linkedAanvraag` with the earlier
application's `id`/`publishedDate` and is billed the extra `aanvraag-besluit-koppeling` event. With
`verrijkMetVolledigeTekst: true`, the full publication text is fetched and `nearRenewablePark`/
`capacityMentionRaw` are re-checked against it (not just the title) — `volledigeTekstVerrijkt` becomes `true`
on a successful fetch, billed the extra `bess-vergunning-verrijkt` event.

#### Stale application watchlist (`staleAanvraagDrempelDagen`, optional, separately charged)

With `linkAanvraagBesluit: true` and `staleAanvraagDrempelDagen` set (e.g. `90`), the actor builds on the same
application index used for aanvraag-besluit linking: any application that's been sitting in that index longer
than the threshold, with no linked decision yet, gets its own signal record:

```json
{
  "signalType": "stale_aanvraag",
  "id": "aanvraag-2026-01-01",
  "authority": "Hollands Kroon",
  "postalCode": "1791 AB",
  "addressGuess": "Voorstraat 1",
  "publishedDate": "2026-01-01",
  "dagenInBehandeling": 196
}
```

Useful for investors/developers who want to know which BESS projects are stalling in the permitting process.
Charged as the new `stale-aanvraag-signaal` event, only when an application actually crosses the threshold.

**Every run also adds one free summary record** (`"type": "samenvatting"`) as the last dataset item — no extra
charge, not counted towards `bess-vergunning-result`:

```json
{
  "type": "samenvatting",
  "aantalLeads": 3,
  "perVergunningCategorie": { "omgevingsvergunning": 1, "andere_vergunning": 1, "overig": 1 },
  "perAuthorityType": { "gemeente": 2, "provincie": 1, "onbekend": 0 },
  "aantalNearRenewablePark": 1,
  "aantalMetCapaciteitsvermelding": 0,
  "uniekeAuthorities": ["Hollands Kroon", "Noord-Holland", "Vlissingen"]
}
```

### Use cases

**Daily nationwide BESS lead feed:**

```json
{ "incrementalMode": true }
```

**Monitor two provinces only:**

```json
{
  "municipalities": ["Noord-Holland", "Overijssel"],
  "publishedAfter": "2026-01-01"
}
```

### Pricing

This Actor uses Apify's Pay-Per-Event (PPE) pricing model.

- **Actor Start:** $0.00005 (Apify default)
- **`bess-vergunning-result`:** $0.04 per result
- **`aanvraag-besluit-koppeling`:** $0.02 extra, only with `linkAanvraagBesluit` enabled and only when a
  decision is actually linked to an earlier application
- **`bess-vergunning-verrijkt`:** $0.01 extra, only with `verrijkMetVolledigeTekst` enabled and only on a
  successful full-text fetch
- **`stale-aanvraag-signaal`:** $0.015 extra, only with `linkAanvraagBesluit` + `staleAanvraagDrempelDagen`
  enabled and only when an application actually crosses the threshold

### Legal

This actor uses the **official public SRU API** of the Dutch government (KOOP / repository.overheid.nl, the
source behind officielebekendmakingen.nl) — the same source used by
[NL Vergunningen & Bekendmakingen Leadfeed](https://apify.com/codeclouds/nl-vergunningen-leadfeed). No
scraping of protected websites, no login, no terms-of-service conflicts.

- Publications may occasionally mention a private applicant's name. This actor does not signal or advise on
  whether a permit is legally required — it only reports that a publication was made.
- This actor does not tell you whether a project *needs* a permit, or under which legal category it falls —
  that is professional/legal advice, not a data signal.

### FAQ

**Q: How fresh is the data?**
A: Publications appear in the feed the same day the authority publishes them.

**Q: Which authorities are covered?**
A: All Dutch municipalities and provinces publishing via officielebekendmakingen.nl.

**Q: Why is `capacityMentionRaw` often null?**
A: Most Dutch BESS permit titles describe the location and permit type, not the exact kWh/MWh capacity — this
is a known limitation of the source data, not a bug.

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

### Related Actors

- **[NL Vergunningen & Bekendmakingen Leadfeed](https://apify.com/codeclouds/nl-vergunningen-leadfeed)** —
  the general-purpose version of this actor, covering all Dutch permit types, not just BESS, on the same
  official publication stream.
- **[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.
- **[NL & EU Government Tenders Scraper](https://apify.com/codeclouds/nl-eu-tenders-scraper)** — same official
  publication family, applied to public procurement tenders instead of BESS permits.
- **[NL CAO Wijzigingen Database](https://apify.com/codeclouds/nl-cao-wijzigingen-database)** — same official
  publication family, for collective labour agreement changes instead of permits.

***

*Zoekwoorden: BESS vergunning, batterijopslagsysteem monitor, energieopslag vergunningen, netcongestie
batterij, batterijopslag leads Nederland, grid battery storage permits Netherlands.*

### Keywords

bess, battery-storage, energieopslag, netcongestie, vergunningen, netherlands, permits, leads

### Changelog

#### 0.4.0

- Added `staleAanvraagDrempelDagen`: signals applications that have been in the tracked application index
  (requires `linkAanvraagBesluit`) longer than the threshold without a linked decision — a permit-pipeline
  stall/delay signal. New charged event `stale-aanvraag-signaal` ($0.015), only when actually detected.
  Confirmed by the user (2026-07-16).

#### 0.3.3 - Bugfix

- Fixed a rare missed link in `linkAanvraagBesluit`: leads were matched against the application index in the
  order the SRU API happened to return them, which is not guaranteed to be publication-date order. A wide
  historical/backfill run could therefore process a decision record before its matching application record
  within the same run and miss the link. The matching pass now sorts leads by `publishedDate` (ascending)
  before linking; the dataset output order is unchanged.

#### 0.3.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.3.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.3.0

- Added `status` (always computed, free): title-based classification as `aanvraag`, `besluit_verleend`,
  `besluit_geweigerd`, or `onbekend`.
- Added `linkAanvraagBesluit`: links a later decision to an earlier application for the same
  address+authority across runs. New `linkedAanvraag` field and charged event `aanvraag-besluit-koppeling`
  ($0.02).
- Added `verrijkMetVolledigeTekst`: fetches the full publication text and re-checks
  `nearRenewablePark`/`capacityMentionRaw` against it. New `volledigeTekstVerrijkt` field and charged event
  `bess-vergunning-verrijkt` ($0.01).
- Both confirmed by the user (2026-07-14, see docs/actor-verbeteringen/PRIJSBESLISSINGEN.md).

#### 0.2.0

- Added a free per-run summary record (`"type": "samenvatting"`) with counts per category/authority type,
  near-park and capacity-mention totals, and the list of unique authorities. No pricing change.

#### 0.1.0

- Initial release. Fetch Dutch BESS permit publications via the official KOOP SRU API, classify into
  `omgevingsvergunning` / `andere_vergunning` / `overig`, detect nearby solar/wind parks, best-effort capacity
  extraction, incremental mode.

# Actor input Schema

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

Filter on municipality or province names, e.g. \["Almelo", "Noord-Holland"]. Leave empty for all of the Netherlands.

## `extraKeywords` (type: `array`):

Additional free-text terms to OR-match alongside the built-in BESS synonyms (batterijopslag(systeem), energieopslagsysteem, BESS, accu-opslag). Use this to widen or narrow the search.

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

Only publications from on/after this date (YYYY-MM-DD).

## `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. A standalone one-off call with no prior run falls back to the 'Published After' date and returns the normal, full result set (not empty). This setting reads/writes a shared, persistent key-value-store snapshot ('lastRunDate') that scheduled monitoring runs also use as their baseline, so an ad-hoc call in between can shift what a later scheduled run considers 'new'.

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

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

## `verrijkMetVolledigeTekst` (type: `boolean`):

Fetches the full publication text and re-checks nearRenewablePark/capacityMentionRaw against it, catching signals the title alone misses. Only charged (bess-vergunning-verrijkt) on a successful fetch.

## `staleAanvraagDrempelDagen` (type: `integer`):

Requires 'Link applications to their later decisions' to be enabled. Flags applications that have been in the (already tracked) application index longer than this many days without a linked decision — a signal for permit pipeline stalls/delays. New charged event stale-aanvraag-signaal ($0.015), only when actually detected. Leave empty to disable.

## Actor input object example

```json
{
  "municipalities": [],
  "extraKeywords": [],
  "publishedAfter": "2026-01-01",
  "maxResults": 200,
  "incrementalMode": false,
  "linkAanvraagBesluit": false,
  "verrijkMetVolledigeTekst": 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-bess-vergunningenmonitor").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-bess-vergunningenmonitor").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-bess-vergunningenmonitor --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/TqH3ievf7gdjAty18/builds/8Btb0GEUAmQmz9KtL/openapi.json
