# Werk.nl Jobs Scraper Netherlands (`mrdoe/werk-nl-jobs-scraper-nl`) Actor

Extracts job listings from Werk.nl, the Dutch government (UWV) job board, including salary/hours, contract type, location, and publicly listed contact details.

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

## Pricing

from $1.50 / 1,000 results

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

![Werk.nl Jobs Scraper Netherlands hero](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/werk-nl-jobs-scraper-nl--hero.png)

**Turn Werk.nl job listings into structured data in minutes** - no coding, no manual copy-pasting. Get full descriptions, salary indications, contract type, and publicly listed contact details from Werk.nl, the Dutch government (UWV) job board.

### What does Werk.nl Jobs Scraper Netherlands do?

Werk.nl Jobs Scraper Netherlands collects job listings from [Werk.nl](https://www.werk.nl), the job board run by UWV (the Dutch Employee Insurance Agency). Search by keyword and/or location, and it pages through every matching vacancy, then visits each one's own page to pull the full description, salary indication, education/experience requirements, and the employer's publicly listed contact details.

### Why use Werk.nl Jobs Scraper Netherlands?

- **Talent sourcing** - build a feed of open vacancies across every sector Werk.nl covers, from volunteer roles to specialist positions.
- **Salary benchmarking** - collect published salary indications by role, region, or contract type.
- **Lead generation** - find employers actively hiring in a specific sector or region, with direct contact details where published.
- **Labour-market research** - track vacancy volume and requirements (education, experience, hours) over time.

### How to use Werk.nl Jobs Scraper Netherlands

![How Werk.nl Jobs Scraper Netherlands works](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/werk-nl-jobs-scraper-nl--how-it-works.png)

1. In the Input tab, set **Keywords** to a profession or search term (matching Werk.nl's own search box), and optionally **Location**.
2. Leave **Enrich with detail pages** on to collect full details per vacancy (recommended), or turn it off for a faster search-only run.
3. Set **Max items** / **Max pages** if you want to cap the run, or leave empty to collect everything matching the search.
4. Click **Start** and wait for the run to finish.
5. Open the **Dataset** tab to preview, filter, and export your results.

### Input

![Werk.nl Jobs Scraper Netherlands input options](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/werk-nl-jobs-scraper-nl--input.png)

| Field | Type | Description |
| --- | --- | --- |
| `keywords` | String | Free-text search term (profession, keyword, or vacancy reference number). Leave empty to browse all active vacancies. |
| `location` | String | City or postcode to filter by. |
| `includeDetails` | Boolean | Visit each vacancy's own page for full data (default: `true`). |
| `maxItems` | Integer | Maximum vacancies to collect (default: unlimited). |
| `maxPages` | Integer | Safety cap on result pages (default: unlimited). |
| `useCache` | Boolean | Skip vacancies already collected by a previous run (default: `true`). |
| `proxyConfiguration` | Object | Proxy settings. Residential proxy is used by default - required to clear Werk.nl's bot-check. |

Example input:

```json
{
    "keywords": "software developer",
    "location": "Utrecht",
    "maxItems": 200
}
```

### Output

![Werk.nl Jobs Scraper Netherlands dataset output](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/werk-nl-jobs-scraper-nl--output.png)

![Werk.nl Jobs Scraper Netherlands data fields](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/werk-nl-jobs-scraper-nl--fields.png)

Each vacancy is saved as one item in the dataset, for example:

```json
{
    "jobId": "70390321",
    "title": "Software Engineer",
    "companyName": "Eijsink",
    "city": "ENSCHEDE",
    "contractType": "Tijdelijk",
    "educationLevel": "Hbo/bachelor",
    "salary": "4536 bruto per maand",
    "recruiterName": "Marije Busscher",
    "recruiterEmail": "john.kolthof@eijsink.nl",
    "companyWebsite": "http://werkenbijeijsink.nl",
    "url": "https://www.werk.nl/nl/vacatures/70390321",
    "source": "werk.nl",
    "scrapedAt": "2026-08-21T00:00:00.000Z"
}
```

#### Field reference

| Field | Description |
| --- | --- |
| `jobId`, `requisitionId` | Werk.nl's vacancy reference number |
| `title`, `description` | Vacancy title and full description |
| `contractType`, `employmentType`, `hoursPerWeek`, `workSchedule` | Contract type and working hours |
| `education`, `educationLevel`, `experienceRequired` | Requirements, where published |
| `city`, `address`, `remoteType` | Work location |
| `salary` | Salary indication text as published (Werk.nl doesn't split this into a structured min/max) |
| `companyName`, `companyWebsite` | Employer |
| `postedAt`, `updatedAt`, `expiresAt` | Publication, last-modified, and closing dates |
| `recruiterName`, `recruiterEmail`, `recruiterPhone` | Contact published on the listing, where the employer includes one |
| `url`, `canonicalUrl` | The vacancy's own page on Werk.nl |
| `attributes.sections` | Every field grouped exactly as Werk.nl's own page sections show them (Arbeidsvoorwaarden, Opleiding, Werkervaring, Contactgegevens, Algemene gegevens) |

Fields with no public data for a given vacancy are returned as `null` (or `[]`/`{}` for arrays/objects) - never fabricated or guessed.

### How it works

Werk.nl's entire domain sits behind a JavaScript bot-check (an auto-submitting challenge page) that only clears inside a real browser session. This Actor uses a headless browser to clear that check once, then calls Werk.nl's own search API directly from within that page (reusing its already-cleared session and CSRF token) to page through results cheaply, without a full page load per page of results. Each vacancy's own page still needs a real navigation - same bot-check reason - which is where the full description and contact details come from.

### Pagination

The Actor pages through results (20 vacancies per page) until it reaches the last page (based on Werk.nl's own result count), `maxPages`, or `maxItems` - whichever comes first.

### Cache behavior

With `useCache` on (default), every successfully collected vacancy's reference number is stored permanently in the Actor's key-value store - no expiration, no TTL. Re-running the Actor with the same or overlapping search will skip vacancies already collected and only return new ones. Disable `useCache` to re-collect everything.

### Cost / performance

Only one browser page load is needed to clear Werk.nl's bot-check and page through search results (via cheap in-page API calls); one additional page load is needed per enriched vacancy. Combined with the permanent cache, this keeps cost per result reasonable despite the browser requirement.

### Troubleshooting

**A run returns 0 vacancies.** Make sure the default residential `proxyConfiguration` is enabled - Werk.nl blocks non-browser and datacenter traffic. Also try a broader `keywords` value; Werk.nl's search matches on exact terms rather than loose substrings.

### FAQ / Disclaimer

**Is this legal?** This Actor only collects publicly visible vacancy data. You are responsible for using the data in accordance with Werk.nl's Terms of Service and applicable law in your jurisdiction. Contact details are only included where the employer has published them on the vacancy itself.

**Found a bug or have a feature request?** Please use the Issues tab on this Actor's page - feedback directly shapes future updates.

# Actor input Schema

## `keywords` (type: `string`):

Free-text search term, matching the same search box on Werk.nl (profession, keyword, or vacancy reference number). Leave empty to browse all active vacancies.

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

City or postcode to filter by, matching Werk.nl's own location filter.

## `includeDetails` (type: `boolean`):

Visit each vacancy's own page to collect the full description, education/experience requirements, and publicly listed contact details. Turn off for a faster, cheaper run that only returns search-result data.

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

Maximum number of vacancies to scrape. Leave empty to collect every vacancy matching the search.

## `maxPages` (type: `integer`):

Safety cap on how many result pages to page through (20 vacancies per page). Leave empty to page through all results.

## `useCache` (type: `boolean`):

Skip vacancies already collected by a previous run of this Actor (matched by vacancy reference number). The cache is stored permanently and never expires. Disable to re-collect everything.

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

Werk.nl requires a real browser session to clear its bot-protection challenge. Residential proxy is strongly recommended and enabled by default.

## Actor input object example

```json
{
  "keywords": "imker",
  "includeDetails": true,
  "useCache": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `listings` (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 = {
    "keywords": "imker",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/werk-nl-jobs-scraper-nl").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 = {
    "keywords": "imker",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/werk-nl-jobs-scraper-nl").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 '{
  "keywords": "imker",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call mrdoe/werk-nl-jobs-scraper-nl --silent --output-dataset

```

## MCP server setup

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

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/EG1Kl4fbVGaC9vGig/builds/5Q0vaDVAJFIK792yD/openapi.json
