# Zorgkaartnederland Healthcare Provider Review Scraper (`jungle_synthesizer/zorgkaartnederland-healthcare-provider-review-scraper`) Actor

Extracts the Netherlands' national care-quality directory: care organisations, named care professionals, and patient ratings with per-dimension subscores, free-text reviews, and provider replies. Includes BIG registration and AGB codes where published. Covers the full published sitemap corpus.

- **URL**: https://apify.com/jungle\_synthesizer/zorgkaartnederland-healthcare-provider-review-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 record scrapeds

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?

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

## ZorgkaartNederland Healthcare Provider & Review Scraper

Extracts the Netherlands' national care-quality directory from [ZorgkaartNederland](https://www.zorgkaartnederland.nl) — care organisations, named care professionals, and the patient ratings behind their scores. Returns three joined record types: organisations, professionals, and individual ratings with per-dimension subscores, free-text review bodies, and the provider's own reply.

***

### Features

- Covers ZorgkaartNederland's full published directory by default — care organisations, named care professionals, and patient ratings, no category or region filter required to get started.
- Returns the review corpus, not just provider listings — individual patient ratings with per-dimension subscores (appointments, treatment effect, staff interaction, information, listening, accommodation), free-text review body, treatment context, and the provider's own reply where published.
- Emits all three record types the site models separately — organisation, professional, and rating — each carrying an `entity_id` so they join, rather than flattening professionals into their practice.
- Captures Dutch BIG registration numbers and AGB care-provider codes where published — the national identifiers that let you join this to other Dutch healthcare and insurer datasets.
- Every Dutch-language field (`care_type`, `professional_role`) ships with an English translation alongside it (`care_type_en`, `professional_role_en`), so the dataset is usable without a Dutch speaker on staff.
- Optional `recordTypes` filter to scope a run to just organisations, just professionals, or just ratings.

***

### Who Uses This Data?

- **Health insurers** (Zilveren Kruis, VGZ, CZ and peers) — benchmarking provider quality and patient sentiment for contracting and network decisions.
- **Hospital and care-group marketing teams** — tracking their own review position and per-dimension scores against competitors.
- **Care-comparison and patient-routing platforms** — building or refreshing a provider directory backed by real patient ratings.
- **B2B vendors selling into Dutch practices** — using the directory as a complete, contactable list of care organisations by care type and location.
- **Researchers and market analysts** — studying patient-reported quality across the Dutch healthcare system at scale.

***

### How It Works

1. Leave `recordTypes` empty (or set `maxItems`) to walk ZorgkaartNederland's full published directory — care organisations, named care professionals, and patient ratings.
2. Set `recordTypes` to `["organisation"]`, `["professional"]`, `["rating"]`, or any combination to scope a run to just the record types you want.
3. Set `maxItems` to cap the total number of records returned across all selected types. Leave it at `0` for a full crawl.
4. Records land in your dataset as they're found. Stop the run early and you keep everything collected so far.

***

### Input

```json
{
  "recordTypes": ["organisation", "professional", "rating"],
  "maxItems": 500
}
```

| Field         | Type            | Default                                    | Description |
|---------------|-----------------|---------------------------------------------|-------------|
| `recordTypes` | array of string | `["organisation", "professional", "rating"]` | Which record types to include: `organisation`, `professional`, `rating`. Leave empty for all three. |
| `maxItems`    | integer          | 10                                            | Maximum number of records to save across all selected record types. Set to `0` for a full crawl. |

***

### Output Fields

#### Organisation rows (`record_type: "organisation"`)

```json
{
  "record_type": "organisation",
  "url": "https://www.zorgkaartnederland.nl/zorginstelling/tandartsenpraktijk-tandartspraktijk-dentoart-huizen-3042722",
  "entity_id": "3042722",
  "name": "Tandartspraktijk DentoArt",
  "care_type": "tandartsenpraktijk",
  "care_type_en": "dental practice",
  "specialisms": [],
  "street": "Golfstroom 16",
  "postal_code": "1271 CP",
  "city": "Huizen",
  "province": "Noord-Holland",
  "latitude": 52.3091952,
  "longitude": 5.2481257,
  "phone": "035-5262175",
  "website": "http://www.dentoart.nl",
  "score_average": 9.8,
  "score_count": 4,
  "agb_code": null,
  "big_registration": null,
  "accepts_new_patients": null,
  "insurers_contracted": [],
  "opening_hours": {}
}
```

| Field                   | Type    | Description |
|--------------------------|---------|-------------|
| `record_type`             | string  | Always `"organisation"` on this row shape. |
| `url`                    | string  | Canonical ZorgkaartNederland URL for the organisation. |
| `entity_id`               | string  | Numeric id, unique per organisation — the join key for related professional/rating rows. |
| `name`                   | string  | Organisation display name. |
| `care_type` / `care_type_en` | string | Dutch care-type code and its English translation (e.g. `tandartsenpraktijk` / `dental practice`). |
| `specialisms`             | array   | Specialisms as published, where listed. |
| `street` / `postal_code` / `city` | string | Address components. |
| `province`                | string  | Derived from `postal_code` (Dutch province). |
| `latitude` / `longitude`  | number  | Map coordinates, where published. |
| `phone` / `website`       | string  | Contact details, where published. |
| `score_average`           | number  | Composite average patient score. |
| `score_count`              | integer | Number of ratings behind `score_average`. |
| `agb_code` / `big_registration` | string | Dutch national provider identifiers, where published. |
| `accepts_new_patients`     | boolean | Whether the organisation is accepting new patients, where published. |
| `insurers_contracted`      | array   | Contracted health insurers, where published. |
| `opening_hours`            | object  | Opening hours by day, where published. |

#### Professional rows (`record_type: "professional"`)

```json
{
  "record_type": "professional",
  "url": "https://www.zorgkaartnederland.nl/zorgverlener/tandarts-abdullah-a-350090",
  "entity_id": "350090",
  "name": "Tandarts Abdullah, A.",
  "professional_role": "tandarts",
  "professional_role_en": "dentist",
  "specialisms": [],
  "organisation_name": "Dental Clinics Krommenie, Krommenie",
  "score_average": null,
  "score_count": null,
  "agb_code": null,
  "big_registration": null
}
```

| Field                              | Type   | Description |
|-------------------------------------|--------|-------------|
| `record_type`                        | string | Always `"professional"` on this row shape. |
| `url`                               | string | Canonical ZorgkaartNederland URL for the professional. |
| `entity_id`                          | string | Numeric id, unique per professional. |
| `name`                              | string | Professional display name. |
| `professional_role` / `professional_role_en` | string | Dutch role code and its English translation (e.g. `tandarts` / `dentist`). |
| `specialisms`                        | array  | Specialisms as published, where listed. |
| `organisation_name`                  | string | The practice/organisation the professional works at, where published. |
| `score_average` / `score_count`      | number/integer | Composite score and rating count, where the professional has ratings. |
| `agb_code` / `big_registration`      | string | Dutch national provider identifiers, where published. |

#### Rating rows (`record_type: "rating"`)

```json
{
  "record_type": "rating",
  "url": "https://www.zorgkaartnederland.nl/zorginstelling/tandartsenpraktijk-tandartspraktijk-dentoart-huizen-3042722/waardering/na-jarenlang-bij-een-andere-73eb679a95bb33759c96020b401da237",
  "entity_id": "3042722",
  "rating_id": "73eb679a95bb33759c96020b401da237",
  "rating_score": 9.3,
  "rating_title": "Waardering van Tandartspraktijk DentoArt - Huizen op 4 september 2024",
  "rating_text": "Na jarenlang bij een andere tandarts geholpen te zijn is Dentoart een verademing...",
  "rating_date": "2024-09-04",
  "rating_author_role": "editorial",
  "rating_treatment": "Gebitsaandoeningen",
  "provider_response": null,
  "subscores": {
    "appointments": 9,
    "treatment_effect": 10,
    "staff_interaction": 10,
    "information": 9,
    "listening": 9,
    "accommodation": 8
  }
}
```

| Field                | Type   | Description |
|-----------------------|--------|-------------|
| `record_type`          | string | Always `"rating"` on this row shape. |
| `url`                 | string | Canonical ZorgkaartNederland URL for this individual rating. |
| `entity_id`            | string | Numeric id of the organisation or professional this rating belongs to — the join key. |
| `rating_id`            | string | Unique id for this individual rating. |
| `rating_score`         | number | Overall score given in this rating. |
| `rating_title`         | string | Rating headline as shown on the page. |
| `rating_text`          | string | The reviewer's free-text review body. |
| `rating_date`          | string | Publication date (ISO `YYYY-MM-DD` where parseable). |
| `rating_author_role`   | string | `patient`, `family member`, `editorial`, or the raw author label where none of those match. |
| `rating_treatment`     | string | Treatment or condition context, where published. |
| `provider_response`    | string | The provider's own reply to the rating, where published. |
| `subscores`            | object | Per-dimension scores (0-10): `appointments`, `treatment_effect`, `staff_interaction`, `information`, `listening`, `accommodation`. |

Every record also carries a `scraped_at` timestamp.

***

### Resuming a large crawl

Every run emits a `resumeCursor` in its Output. If a large crawl stops before it finishes — because it hit `maxItems`, your spend cap (`maxTotalChargeUsd`), or was aborted — start a new run with **the same input** plus that `resumeCursor` to continue from where it left off. The crawl resumes from the queued work the previous run didn't reach.

- You are **not re-charged** for records the earlier run already delivered.
- Resume within your account's run-retention window — on the free tier, roughly your 10 most recent runs. Once the source run is pruned, its `resumeCursor` is no longer valid.
- `resumeCursor` is opaque — supply it unmodified.

***

### FAQ

#### How do I scrape ZorgkaartNederland data?

Set `maxItems` (and optionally `recordTypes`) and run. The scraper walks ZorgkaartNederland's full published directory by default — no category, care type, or region filter required to get started.

#### What data can I get?

Care organisation listings, named care professional profiles, and individual patient ratings with per-dimension subscores, free-text review bodies, and provider replies — all three record types land in the same dataset, joined by `entity_id`.

#### Is this scoped to one care type or region?

No. The scraper covers every care type and region ZorgkaartNederland publishes — dental practices, GP practices, hospitals, nursing homes, physiotherapy practices, and more — with no filter required.

#### Do I need an account or API key?

No. This works from pages that are publicly visible on ZorgkaartNederland — no login required.

#### Why are some fields empty on a given record?

Not every provider or rating publishes every field — BIG registration, AGB codes, opening hours, and insurer lists are only shown where the source itself publishes them. The scraper never fabricates a value for a field the source doesn't show.

***

### Need More Features?

Need a different field, a filtered subset, or another data point from ZorgkaartNederland? [File an issue](https://console.apify.com/actors/issues) or get in touch.

### Why Use This Scraper?

- **The review corpus, not just the directory** — per-dimension subscores, free-text reviews, and provider replies, not just provider contact details.
- **Three record types, joined** — organisation, professional, and rating rows all carry `entity_id`, so you're not reconciling separate exports.
- **National identifiers included** — BIG registration and AGB codes, where published, for joining against other Dutch healthcare datasets.
- **English translations included** — Dutch care types and professional roles ship with an English label alongside the original.

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

## `recordTypes` (type: `array`):

Which record types to include. Leave empty to crawl all three: care organisations, named care professionals, and patient ratings.

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

Maximum number of records to scrape across all selected record types. Leave at 0 for a full crawl.

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "recordTypes": [
    "organisation",
    "professional",
    "rating"
  ],
  "maxItems": 10
}
```

# Actor output Schema

## `results` (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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "recordTypes": [
        "organisation",
        "professional",
        "rating"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/zorgkaartnederland-healthcare-provider-review-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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "recordTypes": [
        "organisation",
        "professional",
        "rating",
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/zorgkaartnederland-healthcare-provider-review-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 '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "recordTypes": [
    "organisation",
    "professional",
    "rating"
  ],
  "maxItems": 10
}' |
apify call jungle_synthesizer/zorgkaartnederland-healthcare-provider-review-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jungle_synthesizer/zorgkaartnederland-healthcare-provider-review-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/9nBRIu08WKcfS7imK/builds/MdVL4BPgLVPJxotCH/openapi.json
