# KVK Scraper - Dutch Company Register (Handelsregister) (`scrapewise/kvk-scraper`) Actor

Search the Dutch KVK Handelsregister by name, keyword, city or KVK number: KVK and establishment numbers, legal form, trade and former names, registration date, activity, visit and postal address, active status. No login, no API key. Error rows are free.

- **URL**: https://apify.com/scrapewise/kvk-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.66 / 1,000 company record delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## KVK Scraper: Dutch company register data by name, keyword, city or KVK number

KVK Scraper searches the **Dutch Chamber of Commerce register (KVK Handelsregister)** the same way the public search
box on kvk.nl does, and returns every matching company, establishment and legal entity as one clean row. No KVK
account, no paid API key: you type company names, keywords or 8-digit KVK numbers and get back the KVK
number, establishment number, legal form, trade names (current and former), statutory name, registration date,
activity description, visit and postal address and whether the business is still registered.

It is used to build B2B lead lists of Dutch companies by sector and city, to verify a supplier or customer before
onboarding (KYB), to enrich a CRM with KVK numbers and official addresses, to monitor new registrations in a niche
with a schedule, and to feed market research and AI agents with official register data.

### At a glance

| What | Price |
|---|---|
| Company record delivered | **US$ 4.30 per 1,000 records** (US$ 0.0043 each) |
| Run start | US$ 0.005 per run |

- 3 searches with 100 records each = 300 records = **US$ 1.30** plus US$ 0.005 per run.
- Error rows and duplicates are never charged. `maxItems` is a hard cap, and a spending limit set on the run stops it
  cleanly with everything delivered so far.
- Proxy costs are included in the price.

### What you get

- **Search like kvk.nl:** company or trade name, a keyword such as `bakkerij` or `software`, a street or a city.
- **Lookup by KVK number:** one 8-digit number returns the head office, every branch and the legal entity record.
- **Filters:** city, legal form (BV, NV, eenmanszaak, VOF, stichting...), head offices only, include deregistered.
- **Official identifiers:** KVK number and 12-digit establishment number (vestigingsnummer) on every row.
- **Names:** current trade names, former names and the statutory name of the legal entity.
- **Addresses:** visit address and postal address split into street, house number, addition, postal code and city,
  plus a ready-to-print `full` line.
- **Schedules:** `onlyNew` remembers what earlier runs delivered and returns only new records.

### Quick start

Software companies in Amsterdam:

```json
{
  "searchQueries": ["software Amsterdam"],
  "maxItems": 100
}
```

Bakeries in Rotterdam that are a BV, head offices only:

```json
{
  "searchQueries": ["bakkerij"],
  "location": "Rotterdam",
  "legalForms": ["BV"],
  "mainEstablishmentOnly": true,
  "maxItems": 200
}
```

Check a list of KVK numbers (KYB / CRM enrichment):

```json
{
  "kvkNumbers": ["59130547", "17139191"],
  "includeInactive": true
}
```

Daily alert for new registrations matching a keyword:

```json
{
  "searchQueries": ["vegan"],
  "onlyNew": true,
  "maxItems": 0
}
```

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Company names, trade names or keywords, one per line, as typed in the kvk.nl search box. Each line is one search. |
| `kvkNumbers` | 8-digit KVK numbers. Each returns all register records under that number. |
| `location` | Keep only records whose visit or postal address is in this city. The city is also added to the search text so the register returns matches from that place first. |
| `legalForms` | Keep only these legal forms: `BV`, `NV`, `EMZ` (eenmanszaak), `VOF`, `CV`, `MTS` (maatschap), `ST` (stichting), `VER` (vereniging), `COOP`, `OWM`, `BRV` (foreign). |
| `mainEstablishmentOnly` | Only head offices (hoofdvestiging), without branches and separate legal entity rows (default off). |
| `includeInactive` | Also return records that are no longer registered, including legacy ones (default off). |
| `startUrls` | Links from the kvk.nl search (`https://www.kvk.nl/zoeken/?q=...`); the search text in the link is used. |
| `maxItems` | Cap for the whole run, across all searches (default 50; 0 = no cap). |
| `onlyNew` | Deliver only records not delivered by earlier runs of the same search (for schedules). |
| `proxyConfiguration` | Apify datacenter proxy by default. |

`query`, `keyword`, `companyNames`, `kvkNumber`, `city`, `legalForm`, `urls` and `maxResults` are accepted too, so inputs
written for other KVK tools keep working.

### Output

| Field | What it is |
|---|---|
| `kvkNumber` | 8-digit KVK registration number |
| `establishmentNumber` | 12-digit establishment number (vestigingsnummer); null on the legal entity row |
| `name` | Name shown in the register for this record |
| `tradeNames`, `formerNames` | Current trade names and names used before |
| `statutoryName` | Statutory name of the legal entity, when it differs from the trade name |
| `legalForm`, `legalFormCode` | Legal form in Dutch (Besloten Vennootschap, Eenmanszaak...) and its code (BV, EMZ...) |
| `registrationType` | `Hoofdvestiging` (head office), `Nevenvestiging` (branch) or `Rechtspersoon` (legal entity) |
| `isMainEstablishment` | true for the head office |
| `isActive` | false when the record is deregistered |
| `registrationDate` | Date the establishment was registered (YYYY-MM-DD) |
| `activityDescription` | Activity as registered, in the company's own words |
| `visitAddress`, `postalAddress` | street, houseNumber, houseNumberAddition, poBox, postalCode, city, country, full |
| `city`, `postalCode` | Shortcut to the visit address (or postal address when there is no visit address) |
| `recordSource` | `current` register or `legacy` record kept from the old register |
| `kvkUrl` | kvk.nl search link for this KVK number |
| `recordId`, `sourceQuery`, `scrapedAt` | Register record id, the search that found it, and when |

One real row:

```json
{
  "type": "company",
  "kvkNumber": "59130547",
  "establishmentNumber": "000028448480",
  "name": "Software House Amsterdam",
  "tradeNames": ["Software House Amsterdam"],
  "formerNames": [],
  "statutoryName": null,
  "legalForm": "Eenmanszaak",
  "legalFormCode": "EMZ",
  "registrationType": "Hoofdvestiging",
  "isMainEstablishment": true,
  "isActive": true,
  "registrationDate": "2013-11-01",
  "activityDescription": "Het ontwikkelen en produceren van maatwerksoftware",
  "visitAddress": {
    "street": "Thérèse Schwartzeplein",
    "houseNumber": "27",
    "houseNumberAddition": "B",
    "postalCode": "1073JL",
    "city": "Amsterdam",
    "country": "Nederland",
    "full": "Thérèse Schwartzeplein 27 B, 1073JL Amsterdam"
  },
  "postalAddress": null,
  "city": "Amsterdam",
  "postalCode": "1073JL",
  "recordSource": "current",
  "kvkUrl": "https://www.kvk.nl/zoeken/?source=all&q=59130547",
  "sourceQuery": "software Amsterdam"
}
```

### How the search works

The register search matches the text you send against names, trade names, KVK numbers, streets and places, exactly as
the kvk.nl search box does, and returns the best matches first. A keyword such as `bakkerij amsterdam` therefore finds
bakeries in Amsterdam and companies with Amsterdam in the name. Use `location` when you want the city to be a strict
filter on the address. kvk.nl shows up to about 5,000 records per search; split very broad searches by city or legal
form to go further.

One company can have several rows: the legal entity (`Rechtspersoon`), the head office (`Hoofdvestiging`) and each
branch (`Nevenvestiging`). Turn on `mainEstablishmentOnly` for one row per company.

### Errors you may see

Every error is a row with `errorCode` and is never charged:

| errorCode | Meaning |
|---|---|
| `INVALID_INPUT` | A field has a wrong value, for example a KVK number without 8 digits or an unknown legal form |
| `INVALID_URL` | Not a kvk.nl search link with a query or a KVK number |
| `NO_RESULTS` | The register has no record for this search and filters |
| `BLOCKED` | kvk.nl refused every attempt for this search; run it again in a few minutes |
| `UNEXPECTED` | Something else stopped the run; nothing more was charged |

### Integrations, scheduling and AI agents

- **Schedule** a search daily or weekly in [Apify schedules](https://docs.apify.com/platform/schedules) with
  `onlyNew` on, and get only the companies registered since the last run.
- **Export** as JSON, CSV, Excel or XML, or read the dataset from the [Apify API](https://docs.apify.com/api/v2).
- **Connect** it to Make, n8n, Zapier, HubSpot or Google Sheets through
  [Apify integrations](https://docs.apify.com/platform/integrations).
- **AI agents:** call it as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp)
  in Claude, ChatGPT, Cursor or any MCP client, for example "find every BV with software in the name in Utrecht and
  give me their KVK numbers and addresses".

### FAQ

**Do I need a KVK account or API key?** No. The Actor uses the same public search as kvk.nl, without login.

**Why not the official KVK API?** The official API needs a paid subscription and a key per user. This Actor needs
neither, charges only for records delivered, and returns the same search fields the public site shows.

**Does it return directors, shareholders or UBOs?** No. Only company data shown in the public search: identifiers,
names, legal form, activity, addresses and status. Officers, UBO data, extracts and annual accounts are sold by KVK
itself and are not collected.

**Does it return phone numbers, emails or websites?** No. The public register search does not show them.

**What is the difference between the KVK number and the establishment number?** The KVK number identifies the
company (or legal entity). The establishment number identifies one location of it; a company with three branches has
one KVK number and up to four establishment numbers.

**Can I look up thousands of KVK numbers?** Yes, put them in `kvkNumbers`.

**Is it legal?** The Actor reads the public register search only and returns company data, no personal contact data.
You are responsible for how you use the data under the laws that apply to you, including the GDPR when a sole
proprietorship carries a person's name.

**Something broke or a field is missing?** Open an issue on the Actor page; issues are answered within a day.

### Limitations

- About 5,000 records per search, the same depth as the kvk.nl search. Split broad searches.
- SBI codes, number of employees, officers and UBOs are not in the public search and are not returned.
- `registrationDate` is missing on a few legal entity rows, as on kvk.nl.
- Data is the register as of the moment of the run.

### Changelog

- **16 Oct 2026:** first version: keyword, city and KVK number search, legal form and head office filters,
  deregistered records, visit and postal addresses, onlyNew for schedules.

# Actor input Schema

## `searchQueries` (type: `array`):

Company names, trade names or keywords, one per line, as you would type them in the kvk.nl search box (for example software Amsterdam, Coolblue or bakkerij). Each line is one search.

## `kvkNumbers` (type: `array`):

8-digit KVK numbers to look up, one per line. Each number returns its main establishment, branches and legal entity record.

## `location` (type: `string`):

Keep only records whose visit or postal address is in this city, for example Rotterdam or Utrecht. Empty = the whole country.

## `legalForms` (type: `array`):

Keep only these legal forms. Empty = all.

## `mainEstablishmentOnly` (type: `boolean`):

On: only the head office (hoofdvestiging) of each company, without branches and separate legal entity records.

## `includeInactive` (type: `boolean`):

On: also returns records that are no longer registered (isActive false), including legacy records.

## `startUrls` (type: `array`):

Optional: links copied from the kvk.nl search (https://www.kvk.nl/zoeken/?q=...). The search text in the link is used.

## `maxItems` (type: `integer`):

Hard cap for the whole run, across all searches. 0 = no cap (kvk.nl shows up to about 5,000 records per search).

## `onlyNew` (type: `boolean`):

On: remembers the records delivered in earlier runs of the same search (in your account) and delivers only records not seen before. Skipped records are free.

## `proxyConfiguration` (type: `object`):

Apify Proxy by default. Change it only if you know you need to.

## Actor input object example

```json
{
  "searchQueries": [
    "software Amsterdam"
  ],
  "mainEstablishmentOnly": false,
  "includeInactive": false,
  "maxItems": 50,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (type: `string`):

No description

# 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 = {
    "searchQueries": [
        "software Amsterdam"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/kvk-scraper").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 = {
    "searchQueries": ["software Amsterdam"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/kvk-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "software Amsterdam"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/kvk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapewise/kvk-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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