# Werk.nl Scraper - UWV Dutch Job Vacancies (`studio-amba/werk-nl-scraper`) Actor

Scrape job vacancies from werk.nl, the Dutch public employment service (UWV) job board. Extract job titles, employers, cities, hours, contract types, and study levels by keyword and location. No login or cookies required.

- **URL**: https://apify.com/studio-amba/werk-nl-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result 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/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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

### What does Werk.nl Scraper do?

**Werk.nl Scraper** extracts job vacancies from [werk.nl](https://www.werk.nl), the official job board of UWV -- the Dutch public employment service. Give it a keyword and (optionally) a Dutch city, and it returns structured data for every matching vacancy: job title, standardized profession, employer, work location, weekly hours, contract type, required study level, and a direct link to the listing. It reads the site's own internal vacancy search API, so there is no login, no cookies, and no browser automation required.

Run it on the Apify platform to get Dutch labour market data via API, schedule recurring scrapes, and pipe results into tools like Zapier, Make, Google Sheets, Airtable, and Slack.

### How to scrape werk.nl data

1. Go to the Werk.nl Scraper on the Apify Store.
2. Click **Try for free** to open the actor in the Apify Console.
3. Enter a search query (e.g. "monteur", "verpleegkundige", "administratief medewerker", "chauffeur").
4. Optionally enter a Dutch city or place (e.g. "Amsterdam", "Rotterdam", "Utrecht"). Leave it empty to search the whole Netherlands.
5. Set the maximum number of results you want (default: 50).
6. Leave the proxy configuration on Netherlands residential (the default) -- werk.nl blocks non-Dutch traffic at the network edge.
7. Click **Start** and wait for the run to finish.
8. Download your data as JSON, CSV, Excel, or HTML from the Output tab, or pull it via the Apify API.

### Why use Werk.nl Scraper?

- **Dutch labour market analysis** -- understand vacancy demand across professions, sectors, and cities. Which regions have the most openings? Which occupations are in shortest supply?
- **Recruitment intelligence** -- see which employers and staffing agencies are actively hiring, for what roles, and where.
- **Public sector benchmarking** -- werk.nl aggregates vacancies employers are legally required to report to UWV alongside their own postings, giving broader market coverage than most commercial job boards.
- **Job aggregation** -- feed structured Dutch listings into your own job board, career site, or candidate-alert system.
- **Academic and policy research** -- clean, structured data for labour economics, skills-gap studies, and regional workforce reports.
- **Lead generation** -- identify companies actively hiring in a sector or region to target with B2B services, recruitment tools, or staffing solutions.

### About werk.nl

werk.nl is run by UWV (Uitvoeringsinstituut Werknemersverzekeringen), the Dutch government agency responsible for employee insurance and public employment services. Key characteristics:

- **Coverage**: Nationwide Netherlands, from Amsterdam and Rotterdam to smaller towns and rural regions.
- **Volume**: Well over 100,000 live vacancies at any time, spanning every sector -- technical trades, healthcare, logistics, administration, retail, and more.
- **Sectors**: Strong coverage of technical/trade professions (monteurs, technici), healthcare (verpleegkundigen, verzorgenden), and entry-level/apprenticeship roles alongside white-collar positions.
- **Apprenticeships and internships**: werk.nl explicitly flags apprenticeship (`leerbaan`) and internship (`stageplaats`) positions, useful for education- and youth-labour-market research.
- **Study level**: Most vacancies list a required education level (MBO, HBO, WO, or "Niet opgegeven" when unspecified), which most commercial Dutch job boards don't expose consistently.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `searchQuery` | string | No | Job keyword to search for. Defaults to `monteur` if empty. |
| `location` | string | No | Dutch city or place to search near (e.g. `Amsterdam`). Leave empty to search the whole Netherlands. |
| `maxResults` | integer | No | Maximum number of vacancies to scrape. Default `50`. |
| `proxyConfiguration` | object | No | Apify proxy settings. Defaults to NL residential proxies -- required, as werk.nl blocks non-Dutch IPs. |

#### Example input

```json
{
  "searchQuery": "verpleegkundige",
  "location": "Rotterdam",
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "NL"
  }
}
````

### Output

Each vacancy is a flat JSON object with the following fields:

| Field | Type | Example |
|-------|------|---------|
| `referenceNumber` | number | `70522654` |
| `jobTitle` | string | `Verpleegkundige Niveau 4 VPT` |
| `profession` | string | `Verpleegkundige` |
| `company` | string | `Stichting Zorggroep Florence` |
| `location` | string | `Rijswijk Zh` |
| `locationType` | string | `Vaste werklocatie` |
| `foreignCountry` | string | `null` |
| `minHours` | number | `36` |
| `maxHours` | number | `36` |
| `contractType` | string | `Vast` |
| `studyLevel` | string | `MBO` |
| `isApprenticeship` | boolean | `false` |
| `isInternship` | boolean | `false` |
| `modifiedDate` | string | `2026-07-26T00:00:00.000Z` |
| `url` | string | `https://www.werk.nl/nl/vacatures/70522654` |
| `scrapedAt` | string | `2026-07-26T14:18:45.217Z` |

#### Example output

```json
{
  "referenceNumber": 70522654,
  "jobTitle": "Verpleegkundige Niveau 4 VPT",
  "profession": "Verpleegkundige",
  "company": "Stichting Zorggroep Florence",
  "location": "Rijswijk Zh",
  "locationType": "Vaste werklocatie",
  "foreignCountry": null,
  "minHours": 36,
  "maxHours": 36,
  "contractType": "Vast",
  "studyLevel": "MBO",
  "isApprenticeship": false,
  "isInternship": false,
  "modifiedDate": "2026-07-26T00:00:00.000Z",
  "url": "https://www.werk.nl/nl/vacatures/70522654",
  "scrapedAt": "2026-07-26T14:18:45.217Z"
}
```

### Cost estimate

This actor is billed on Apify's Pay Per Result model. The search API returns 20 vacancies per page, so scraping is fast -- a typical run of a few hundred listings finishes in well under a minute of compute. You pay per vacancy returned plus a small per-run start fee, so a run that returns 500 vacancies costs roughly the price of 500 results. Check the actor's pricing tab for the exact current rate.

### Limitations and known issues

- **Search results only** -- the actor reads the listing data from werk.nl's search API (title, employer, location, hours, contract type, study level). It does not fetch the full job description text from the vacancy detail page.
- **Employer name as advertised** -- some vacancies are posted by staffing agencies on behalf of an end client, so `company` reflects who published the listing, not necessarily who you'd work for day to day.
- **Location is free text** -- the `location` input is a keyword-style filter, not a strict radius search. For precise geographic filtering, scrape without a location and filter the `location` field in your own pipeline.
- **Netherlands only** -- werk.nl blocks non-Dutch traffic at the network edge (an Imperva/Incapsula WAF), so this actor requires NL residential proxies. These are configured by default; do not switch to datacenter or other-country proxies.
- **Result ceiling** -- deep result sets are paginated; very large `maxResults` values will walk many pages. Keep `maxResults` reasonable for the query you actually need.

### Related scrapers

- **VDAB Scraper** -- Flanders' public employment service job board, the Belgian counterpart to werk.nl.
- **Jobsite Scraper** -- UK job listings on the StepStone platform.
- **Ejobs Scraper** -- Romanian public job listings.
- Browse the Studio AMBA profile on the Apify Store for more European job and public-sector data scrapers.

### FAQ

**Do I need a werk.nl account or API key?**
No. This actor reads the public vacancy search results. There is no login, no DigiD, and no API key required.

**Can I filter by contract type, hours, or study level?**
The current version filters by keyword and location. Contract type, hours, and study level are returned on every result so you can filter them yourself after scraping.

**Why does werk.nl need residential proxies specifically?**
werk.nl runs a network-edge firewall that returns "Access Denied" to traffic that doesn't originate from a Dutch IP address, regardless of browser fingerprint. This is independent from the site's login system -- the public vacancy search itself needs no account, but the network layer in front of it is Netherlands-only.

**Is scraping werk.nl legal?**
This actor collects publicly available vacancy data published by UWV, a Dutch government agency. You are responsible for using the data in line with werk.nl's terms and applicable law. Do not use it to send unsolicited communications in breach of regulations.

# Actor input Schema

## `searchQuery` (type: `string`):

Job keyword to search for (e.g. 'monteur', 'verpleegkundige', 'administratief medewerker', 'chauffeur'). Defaults to 'monteur' if empty.

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

Dutch city or place to search near (e.g. 'Amsterdam', 'Rotterdam', 'Utrecht'). Leave empty to search across the whole Netherlands.

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

Maximum number of vacancies to scrape.

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

Proxy settings. werk.nl sits behind a WAF that blocks non-Dutch IPs outright -- NL residential proxies are required and set by default.

## Actor input object example

```json
{
  "searchQuery": "monteur",
  "location": "Amsterdam",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}
```

# 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 = {
    "searchQuery": "monteur",
    "location": "Amsterdam",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "NL"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/werk-nl-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 = {
    "searchQuery": "monteur",
    "location": "Amsterdam",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "NL",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/werk-nl-scraper").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 '{
  "searchQuery": "monteur",
  "location": "Amsterdam",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}' |
apify call studio-amba/werk-nl-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Werk.nl Scraper - UWV Dutch Job Vacancies",
        "description": "Scrape job vacancies from werk.nl, the Dutch public employment service (UWV) job board. Extract job titles, employers, cities, hours, contract types, and study levels by keyword and location. No login or cookies required.",
        "version": "0.1",
        "x-build-id": "054vjBWrZz8k32M6k"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/studio-amba~werk-nl-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-studio-amba-werk-nl-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/studio-amba~werk-nl-scraper/runs": {
            "post": {
                "operationId": "runs-sync-studio-amba-werk-nl-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/studio-amba~werk-nl-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-studio-amba-werk-nl-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQuery": {
                        "title": "Search Query",
                        "type": "string",
                        "description": "Job keyword to search for (e.g. 'monteur', 'verpleegkundige', 'administratief medewerker', 'chauffeur'). Defaults to 'monteur' if empty."
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "Dutch city or place to search near (e.g. 'Amsterdam', 'Rotterdam', 'Utrecht'). Leave empty to search across the whole Netherlands."
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of vacancies to scrape.",
                        "default": 50
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings. werk.nl sits behind a WAF that blocks non-Dutch IPs outright -- NL residential proxies are required and set by default."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
