# VDAB.be Scraper: Belgium Flanders Jobs, Vacatures & Employers (`santamaria-automations/vdab-be-scraper`) Actor

Extract job listings from VDAB.be, Belgium's Flemish public employment service. Returns title, company, location, Flemish province, employment type, salary, full description and contact details. Covers Flanders and Brussels.

- **URL**: https://apify.com/santamaria-automations/vdab-be-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/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

## VDAB.be Scraper: Belgium Flanders Jobs, Vacatures and Employers

Extract job listings from **VDAB.be**, Belgium's official Flemish public employment service
(Vlaamse Dienst voor Arbeidsbemiddeling en Beroepsopleiding). Returns structured job data
including title, company, Flemish province, employment type, salary, full description,
external apply URL, company website and company social media links.

Covers **Flanders and Brussels Capital Region** — where the majority of Belgian tech,
logistics, healthcare and engineering roles are posted. Wallonia uses a separate PES (Forem).

***

### What It Does

- Searches VDAB.be for any keyword in Dutch or English
- Extracts job cards: title, company, location, Flemish province, contract type, logo, posted date
- Fetches detail pages using Googlebot pre-rendering to unlock full job data (no browser required)
- Returns full description in plain text, HTML and Markdown from JSON-LD structured data
- Extracts external apply URL (employer's ATS or jobs portal link, e.g. Jobat, StepStone)
- Extracts company website from the VDAB detail page
- Optionally fetches company profile for social media links (LinkedIn, Twitter, Facebook, Instagram)
  and company about text
- Extracts salary from JSON-LD structured data (min/max, currency, period)
- Maps Belgian employment types (voltijds, deeltijds, interim, stage, leercontract)
- Maps locations to Flemish provinces (Antwerpen, Oost-Vlaanderen, West-Vlaanderen, Vlaams-Brabant, Limburg) and Brussels
- Sorts results by newest first by default — ideal for scheduled daily scrapes

***

### Sample Output

```json
{
  "_type": "job",
  "id": "74510331",
  "title": "Junior Software Engineer",
  "job_url": "https://www.vdab.be/vindeenjob/vacatures/74510331/junior-software-engineer",
  "source_url": "https://www.vdab.be/vindeenjob/vacatures/74510331/junior-software-engineer",
  "source_platform": "vdab.be",
  "company_name": "Noel Franklin",
  "company_website": "https://www.noelfranklin.com",
  "company_logo_url": "https://cdn.app-prd-cdn.aws.vdab-prd.be/vindeenjob/templates/bedrijven/4117/logo.jpg",
  "company_social_urls": [
    "https://www.linkedin.com/company/18802263/",
    "https://www.facebook.com/DeFranklins",
    "https://www.instagram.com/noelfranklin.agency/"
  ],
  "company_about": "Bij Noël Franklin draait alles om de juiste match. Wij voorzien echte begeleiding, inside info over bedrijven en toegang tot opportuniteiten die je nergens anders vindt...",
  "location": "Roeselare",
  "postal_code": "8800",
  "country": "BE",
  "region": "West-Vlaanderen",
  "posted_at_text": "1 sep. 2026",
  "posted_at_datetime": "2026-09-01T17:15:29Z",
  "employment_type": "permanent",
  "workplace_type": null,
  "salary_min": 2800.0,
  "salary_max": 4000.0,
  "salary_currency": "EUR",
  "salary_period": "month",
  "salary_text": "EUR 2800 - 4000 per month",
  "description": "Ben jij een junior software engineer met een sterke interesse in automotive en embedded systemen?...",
  "description_full": "Ben jij een junior software engineer met een sterke interesse in automotive en embedded systemen?...",
  "description_html": "<p>Ben jij een <strong>junior software engineer</strong>...</p>",
  "description_md": "Ben jij een **junior software engineer** met een sterke interesse...",
  "contact_emails": [],
  "contact_phones": [],
  "contact_urls": [],
  "apply_url": "https://jobs.noelfranklin.com/nl/?utm_source=vdab&utm_medium=bedrijfspagina",
  "search_query": "software engineer",
  "scraped_at": "2026-09-02T10:00:00Z"
}
```

***

### Pricing

| Event | When triggered | Price |
|-------|----------------|-------|
| `actor-start` | Once per run | $0.001 |
| `job-serp-result` | Per job returned (SERP only mode) | $0.003 |
| `job-detail-result` | Per job returned (with detail fetch) | $0.005 |

**Example costs:**

- 100 jobs (SERP only): $0.001 + 100 x $0.003 = $0.31
- 100 jobs (with details): $0.001 + 100 x $0.005 = $0.51
- 1000 jobs (SERP only): $0.001 + 1000 x $0.003 = $3.00

New Apify users get **$5 free monthly credit** — enough for 1,600+ SERP-only job extractions.

***

### Input Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `searchQueries` | array | - | Keywords in Dutch or English (e.g. "programmeur", "verpleegkundige", "software engineer") |
| `location` | string | - | Flemish city or region filter (e.g. "Antwerpen", "Gent", "Brussel") |
| `searchUrls` | array | - | Paste VDAB.be search or direct vacancy URLs. Supports /vindeenjob/jobs/ SERP pages, /vindeenjob/vacatures/?trefwoord= search pages, and direct /vindeenjob/vacatures/{id}/{slug} vacancy URLs. |
| `sortBy` | string | "newest" | "newest" sorts by posting date descending (recommended for daily scraping); "relevance" uses VDAB's default ranking |
| `maxResults` | integer | 100 | Total result cap across all queries |
| `maxResultsPerQuery` | integer | 100 | Cap per keyword or URL |
| `includeJobDetails` | boolean | true | Fetch detail pages for full description, salary and apply URL |
| `includeCompanyDetails` | boolean | false | Also fetch company profile for social links and about text |
| `maxConcurrency` | integer | 5 | Concurrent requests (1-20) |

***

### Output Fields

| Field | Description |
|-------|-------------|
| `_type` | Always "job" |
| `id` | VDAB vacancy ID |
| `title` | Job title |
| `job_url` | Canonical vacancy URL on vdab.be |
| `source_url` | Same as job\_url |
| `source_platform` | Always "vdab.be" |
| `company_name` | Employer name |
| `company_logo_url` | Employer logo from VDAB CDN |
| `company_website` | Employer website URL (from detail page when includeJobDetails=true) |
| `company_social_urls` | Array of social media URLs: linkedin, twitter, facebook, instagram, youtube in that order (when includeCompanyDetails=true) |
| `company_about` | Company about/description text from VDAB company profile (when includeCompanyDetails=true) |
| `location` | City or municipality |
| `postal_code` | Belgian postal code (from JSON-LD structured data) |
| `country` | Always "BE" |
| `region` | Flemish province: Antwerpen / Oost-Vlaanderen / West-Vlaanderen / Vlaams-Brabant / Limburg / Brussel |
| `posted_at_text` | Dutch date format: "13 jul. 2026" |
| `posted_at_datetime` | ISO 8601 UTC datetime (from JSON-LD datePosted when includeJobDetails=true, date-only otherwise) |
| `employment_type` | permanent / part-time / temporary / internship / apprenticeship / flexi / freelance |
| `workplace_type` | on-site / hybrid / remote (when available in description) |
| `salary_min` | Minimum salary in EUR (from JSON-LD baseSalary when listed) |
| `salary_max` | Maximum salary in EUR |
| `salary_currency` | Always "EUR" when salary is present |
| `salary_period` | month / year / hour / week / day |
| `salary_text` | Salary summary string |
| `description` | Job description snippet (up to 500 characters) |
| `description_full` | Full plain-text description with line breaks preserved |
| `description_html` | HTML rendering of the full description |
| `description_md` | Markdown source of the description (from VDAB's CMS) |
| `contact_emails` | Email addresses found in description |
| `contact_phones` | Belgian phone numbers found in description |
| `contact_urls` | External URLs found in description |
| `apply_url` | External apply URL from employer's ATS or jobs portal (from JSON-LD hiringOrganization.sameAs). Falls back to VDAB job URL when not available. |
| `search_query` | Query that returned this result |
| `scraped_at` | ISO 8601 UTC scrape timestamp |

***

### How It Works

VDAB.be uses Angular Universal (server-side rendering for SEO). The scraper uses a two-stage fetch:

1. **SERP** — Verbolia static HTML pages at `/vindeenjob/jobs/{keyword-slug}` serve up to 28 job cards per page as plain HTML (no JS required). These contain: title, company name, location, contract type, logo URL, posted date, description snippet.

2. **Detail** — Vacancy detail pages at `/vindeenjob/vacatures/{id}/{slug}` are fetched using a Googlebot User-Agent. VDAB's Angular Universal pre-renders full content for this UA (~79KB vs 46KB SPA shell), exposing JSON-LD JobPosting data with: full description in Markdown, salary (min/max/currency/period), ISO datePosted, postal code, company info and apply URL.

3. **Company** (optional) — Company profile pages at `/vindeenjob/bedrijven/{id}` are also pre-rendered for Googlebot, exposing: company about text, social media links (Facebook, Twitter, LinkedIn, Instagram).

***

### Use with AI Agents (MCP)

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@apify/mcp-server"],
      "env": { "APIFY_TOKEN": "your_token" }
    }
  }
}
```

Then ask your AI: "Search VDAB for software engineer jobs in Antwerpen and return the results as JSON."

***

### Why This Scraper

- **Full descriptions**: Extracts complete job descriptions via Angular Universal pre-rendering — no browser, no Playwright
- **External apply URLs**: Returns the real employer ATS link, not just the VDAB page
- **Company enrichment**: Social media profiles and about text from VDAB company pages
- **Structured salary data**: Parsed from JSON-LD structured data (min/max/period)
- **Public sector data**: VDAB is the official Flemish public employment service — all listings are freely accessible
- **HTTP-only Go**: No browser, no Playwright, no Puppeteer. Fast, cheap, reliable
- **Flemish market coverage**: VDAB is the primary job board for Flemish speakers in Belgium
- **Apprenticeship coverage**: VDAB includes dual-training jobs (leercontract) not found on commercial boards
- **Province mapping**: Automatically maps Belgian municipalities to Flemish province
- **Incremental-ready**: Default sort-by-newest makes daily scheduled runs trivial

***

### Common Use Cases

- **Scheduled daily scraping**: Run on a schedule with `sortBy: "newest"` and a small `maxResults` cap (e.g. 50-100) to capture only new listings each day. Deduplicate downstream by `id` or `job_url`.
- **Market research**: Track job postings in specific Flemish provinces or sectors
- **Salary benchmarking**: Identify salary ranges for Belgian roles (structured min/max data from JSON-LD)
- **Talent pipeline**: Monitor which companies are hiring in Flanders
- **Lead generation**: Combine company\_website and company\_social\_urls for B2B outreach
- **Public sector jobs**: VDAB lists Belgian government, education and healthcare vacancies
- **Apprenticeship tracking**: Monitor dual-training (leercontract) opportunities by sector

***

### Notes and Limits

- **Coverage**: Flanders and Brussels Capital Region only. Wallonia (French-speaking) uses Forem.
- **Language**: Most listings are in Dutch (nl-BE). Some Brussels listings may be in French or English.
- **Results per query**: Up to 28 results per keyword search via the static SERP pages.
- **apply\_url**: Points to the employer's ATS homepage (e.g. `jobs.noelfranklin.com/nl/`) with VDAB tracking UTMs. The deep-link to the specific vacancy on the external ATS is only available inside the Angular SPA.
- **company\_social\_urls**: Requires `includeCompanyDetails: true`. Fetches one additional page per job.
- **company\_open\_jobs\_count**: Not available (VDAB's count API requires authentication).
- **Authentication**: VDAB's session-gated REST API is not used — all data comes from public pages.
- **Update frequency**: VDAB listings refresh daily. Run daily for fresh data.
- **Salary data**: Belgian salaries are often listed as gross monthly ("brut per maand"). "In overleg" means negotiable.
- **Employment types**: voltijds (full-time), deeltijds (part-time), interim (temp agency), stage (internship), leercontract (apprenticeship).

***

### Related Actors

- [Job Feed Aggregator](https://apify.com/santamaria-automations/job-feed) - Multi-country job aggregator including Belgium
- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper) - Scrape any company careers page
- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor) - Extract jobs from any website
- [Indeed Scraper](https://apify.com/santamaria-automations/indeed-scraper) - Global jobs including Belgium
- [CVLibrary Scraper](https://apify.com/santamaria-automations/cvlibrary-scraper) - UK job board
- [IrishJobs.ie Scraper](https://apify.com/santamaria-automations/irishjobs-ie-scraper) - Ireland jobs
- [Prospects UK Scraper](https://apify.com/santamaria-automations/prospects-uk-scraper) - UK graduate jobs

***

### Support

Issues or questions? Open a ticket on the [Issues tab](https://apify.com/santamaria-automations/vdab-be-scraper/issues) or email contact@nanoscrape.com.

# Actor input Schema

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

One or more keyword queries in Dutch or English (for example 'programmeur', 'verpleegkundige', 'software engineer', 'boekhouder'). Each runs as a separate search. Results are deduplicated.

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

Flemish city or region to filter by (for example 'Antwerpen', 'Gent', 'Brussel', 'Leuven', 'Brugge'). Applied to all keyword searches.

## `searchUrls` (type: `array`):

Paste one or more VDAB.be search URLs. Go to vdab.be, run a search, and copy the URL. Filters are preserved.

## `sortBy` (type: `string`):

Newest first uses VDAB's ?sort=datum. Relevance uses VDAB's ?sort=standaard. Newest is recommended for scheduled daily scrapes.

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

Total cap across all queries and URLs.

## `maxResultsPerQuery` (type: `integer`):

Maximum results per search URL or keyword.

## `includeJobDetails` (type: `boolean`):

When true, opens each job detail page (Googlebot pre-render) for full description, salary, external apply URL and company website. Returns richer data at a slightly higher cost.

## `includeCompanyDetails` (type: `boolean`):

Also fetch the company profile page to extract company\_about and company\_social\_urls (LinkedIn, Facebook, Twitter, Instagram). Implies includeJobDetails=true.

## `maxConcurrency` (type: `integer`):

Maximum concurrent page requests. Only used when Fetch job detail pages is on.

## Actor input object example

```json
{
  "location": "Antwerpen",
  "sortBy": "newest",
  "maxResults": 100,
  "maxResultsPerQuery": 100,
  "includeJobDetails": true,
  "includeCompanyDetails": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset of Belgian job listings from VDAB.be. Each row has: id, title, company\_name, company\_logo\_url, company\_website, company\_social\_urls (array of social URLs in order: linkedin, twitter, facebook, instagram, youtube), company\_about, location, postal\_code, country (BE), region (Flemish province or Brussel), salary\_min, salary\_max, salary\_currency, salary\_period, salary\_text, employment\_type, workplace\_type (on-site/hybrid/remote), description, description\_full, description\_html, description\_md, job\_url, apply\_url (external ATS URL from JSON-LD), contact\_emails, contact\_phones, contact\_urls, posted\_at\_text, posted\_at\_datetime, search\_query, scraped\_at.

# 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 = {
    "maxResults": 100,
    "maxResultsPerQuery": 100,
    "includeJobDetails": true,
    "maxConcurrency": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/vdab-be-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 = {
    "maxResults": 100,
    "maxResultsPerQuery": 100,
    "includeJobDetails": True,
    "maxConcurrency": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/vdab-be-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 '{
  "maxResults": 100,
  "maxResultsPerQuery": 100,
  "includeJobDetails": true,
  "maxConcurrency": 5
}' |
apify call santamaria-automations/vdab-be-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/vdab-be-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/mZzWvmD4Fkd3lCfBg/builds/gkGJqQftoBvpQNEOh/openapi.json
