# Le Forem Scraper: Belgium Wallonia Jobs and Offres d'Emploi (`santamaria-automations/forem-be-scraper`) Actor

Extract job listings from Le Forem (leforem.be), Belgium's Wallonia French-speaking public employment service. Returns title, company, Walloon province, employment type, salary, full description and contact details. Covers Wallonia and Brussels.

- **URL**: https://apify.com/santamaria-automations/forem-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

## Le Forem Scraper: Belgium Wallonia Jobs, Offres d'Emploi and Employers

Extract job listings from **Le Forem** (leforem.be), Belgium's official Wallonia French-speaking
public employment service (Service public wallon de l'Emploi et de la Formation professionnelle).
Returns structured job data including title, company, Walloon province, employment type, salary
and full description.

Covers **Wallonia and Brussels Capital Region** - the French-speaking half of Belgium, home to
major employers in Charleroi, Liège, Namur, Mons, Wavre and the Walloon economic corridor.
Flanders uses a separate PES (VDAB - see Related Actors).

***

### What It Does

- Searches Le Forem for any keyword in French (or English)
- Uses the official Forem public JSON API - no browser, no JavaScript required
- Extracts job cards: title, company, location, Walloon province, contract type, posted date
- Fetches full job detail: salary, complete description, contact details, skills required
- Maps Belgian employment types: CDI/CDD, interim, stage, apprentissage, etudiant, independant
- Maps locations to Walloon provinces: Brabant wallon, Hainaut, Liège, Luxembourg, Namur
- Resolves city names to the Forem GUFID location registry for accurate geographic filtering
- Returns data instantly - plain HTTP, 128 MB RAM, sub-second response per record

***

### Sample Output

```json
{
  "_type": "job",
  "id": "2029707",
  "title": "Chef d'Atelier - Menuiserie Bois (H/F/X)",
  "job_url": "https://www.leforem.be/recherche-offres/offre-detail/2029707",
  "source_url": "https://www.leforem.be/recherche-offres/offre-detail/2029707",
  "source_platform": "leforem.be",
  "company_name": "BOIS ET DESIGN",
  "company_website": null,
  "company_logo_url": null,
  "location": "Liège",
  "country": "BE",
  "region": "Liège",
  "posted_at_text": "12/08/2026",
  "posted_at_datetime": "2026-08-12T00:00:00Z",
  "listing_expires_at": "2026-09-30T00:00:00Z",
  "employment_type": "permanent",
  "workplace_type": "on-site",
  "open_positions": 1,
  "occupation": "Menuisier / Menuisière",
  "employer_sector": "Fabrication de menuiseries et parquets en bois",
  "salary_min": 2850,
  "salary_max": null,
  "salary_currency": "EUR",
  "salary_period": "month",
  "salary_text": "2850 EUR/mois",
  "description": "Vous gérez et animez une équipe de menuisiers. Vous organisez le travail en atelier, contrôlez la qualité des productions et veillez au respect des délais et des normes de sécurité.",
  "description_full": "Vous gérez et animez une équipe de menuisiers.\nVous organisez le travail en atelier...",
  "description_html": "<p>Vous gérez et animez une équipe de menuisiers.</p>...",
  "description_md": "Vous gérez et animez une équipe de menuisiers.\n\nVous organisez...",
  "contact_emails": ["candidature@boisetdesign.be"],
  "contact_phones": ["+32472456789"],
  "contact_urls": [],
  "contact_person_name": "Marie Dupont",
  "apply_url": "https://www.leforem.be/recherche-offres/offre-detail/2029707",
  "apply_redirect_url": null,
  "partner_board": null,
  "partner_ref": null,
  "languages_required": [],
  "experience_required": [
    { "occupation": "Menuisier d'atelier", "level": "5 ans ou plus" }
  ],
  "driving_licence": null,
  "benefits_other": ["Cheque-repas", "13eme mois"],
  "competencies": [
    { "code": "1234", "label": "Effectuer le montage d'equipements industriels", "required": true }
  ],
  "soft_skills": [
    { "code": "5678", "label": "Esprit d'equipe", "required": true },
    { "code": "5679", "label": "Autonomie", "required": false }
  ],
  "education_required": [
    { "level": "Enseignement secondaire superieur (CESS)", "field_of_study": "Menuiserie" }
  ],
  "position_start_date": "2026-10-01T00:00:00Z",
  "position_end_date": null,
  "search_query": "chef atelier in Liège",
  "scraped_at": "2026-09-14T09: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

***

### Input Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `searchQueries` | array | - | Keywords in French (e.g. "developpeur", "infirmier", "comptable", "ingenieur"). Each runs as a separate search. |
| `location` | string | - | Walloon city or province filter (e.g. "Liege", "Namur", "Charleroi", "Mons", "Wavre"). Applied to all keyword searches. |
| `searchUrls` | array | - | Paste Le Forem search URLs directly. Filters are preserved. |
| `maxResults` | integer | 100 | Total result cap across all queries |
| `maxResultsPerQuery` | integer | 100 | Cap per keyword or URL |
| `includeJobDetails` | boolean | true | Fetch full job detail (salary, description, contacts) via the Forem detail API |
| `maxConcurrency` | integer | 5 | Concurrent API requests (1-20). Higher values speed up detail fetches; Le Forem's public API tolerates bursts well. |
| `sortBy` | string | `"newest"` | Result order. Le Forem's public API only exposes native newest-first ordering with no sort dropdown or URL parameter; enum is `["newest"]` for fleet consistency. |

***

### Output Fields

| Field | Type | Description |
|-------|------|-------------|
| `_type` | string | Always "job" |
| `id` | string | Le Forem offer ID |
| `title` | string | Job title |
| `job_url` | string | Canonical vacancy URL on leforem.be |
| `source_url` | string | Same as job\_url |
| `source_platform` | string | Always "leforem.be" |
| `company_name` | string|null | Employer name |
| `company_logo_url` | string|null | Employer logo (when available) |
| `company_website` | string|null | Employer website (when extractable from description) |
| `location` | string | City or municipality (joined when multiple) |
| `country` | string | Always "BE" |
| `region` | string|null | Walloon province: Brabant wallon / Hainaut / Liège / Luxembourg / Namur / Bruxelles-Capitale |
| `posted_at_text` | string|null | French date text: "Publié aujourd'hui" or "DD/MM/YYYY" |
| `posted_at_datetime` | string|null | ISO 8601 UTC date |
| `listing_expires_at` | string|null | ISO 8601 UTC date the listing closes (from dateFinDiffusion) |
| `employment_type` | string|null | permanent / fixed-term / temporary / internship / apprenticeship / student / freelance |
| `workplace_type` | string|null | on-site / hybrid / remote (when mentioned in description) |
| `open_positions` | integer|null | Number of open positions for this vacancy (nombrePostes) |
| `occupation` | string|null | Forem occupation label (metier) for this role |
| `employer_sector` | string|null | NACE sector of the employing company (secteurActiviteEmployeur) |
| `salary_min` | number|null | Minimum salary in EUR (from benefits.basePay - monthly brut) |
| `salary_max` | number|null | Maximum salary in EUR |
| `salary_currency` | string|null | Always "EUR" |
| `salary_period` | string|null | month / year / hour / week / day |
| `salary_text` | string|null | Salary as displayed or "a discuter" (negotiable) |
| `description` | string|null | Job description snippet (first 500 chars) |
| `description_full` | string|null | Full plain-text description with line breaks preserved |
| `description_html` | string|null | Full HTML description |
| `description_md` | string|null | Full Markdown description |
| `contact_emails` | array | Email addresses extracted from howToApply and all description fields |
| `contact_phones` | array | Belgian phone numbers from howToApply and description |
| `contact_urls` | array | External URLs found in description |
| `contact_person_name` | string|null | Contact person full name (from howToApply.formattedName) |
| `apply_url` | string|null | Canonical Le Forem vacancy URL |
| `apply_redirect_url` | string|null | Partner board direct apply URL (e.g. Jobat, Stepstone) when listing is syndicated |
| `partner_board` | string|null | Name of the partner job board that syndicated this listing (e.g. "Jobat") |
| `partner_ref` | string|null | Partner board reference ID for the listing |
| `languages_required` | array | Language requirements: `[{"language","code","required","proficiency"}]` |
| `experience_required` | array | Experience requirements: `[{"occupation","level"}]` |
| `driving_licence` | string|null | Driving licence requirement (e.g. "Permis de conduire validé pour une catégorie C1") |
| `benefits_other` | array | Additional benefits beyond base salary (e.g. \["Cheque-repas","13eme mois"]) |
| `competencies` | array | Technical competencies from the Forem skills taxonomy: `[{"code","label","required"}]` (e.g. "Effectuer le montage d'equipements industriels") |
| `soft_skills` | array | Soft skills / personality traits from the Forem taxonomy: `[{"code","label","required"}]` (e.g. "Esprit d'equipe", "Autonomie", "Sens des responsabilites") |
| `education_required` | array | Required education/diploma levels: `[{"level","field_of_study?"}]` (e.g. level="Formation superieure initiale de type court (Baccalaureat)", field\_of\_study="Informatique") |
| `position_start_date` | string|null | Fixed position start date in ISO 8601 UTC (from positionDateInfo.startDate) |
| `position_end_date` | string|null | Expected contract end date in ISO 8601 UTC (from positionDateInfo.expectedEndDate; present on CDD/interim roles) |
| `search_query` | string|null | Query that returned this result |
| `scraped_at` | string | ISO 8601 UTC scrape timestamp |

***

### 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 Le Forem for developpeur jobs in Liege and return the results as JSON."

***

### Why This Scraper

- **Official public API**: Le Forem exposes a clean JSON API powering their search interface. All data is publicly accessible without authentication.
- **HTTP-only Go**: No browser, no Playwright, no Puppeteer. Fast, cheap, reliable - 128 MB RAM per run.
- **Wallonia market coverage**: Le Forem is the primary job board for French-speaking workers in Belgium, covering all 5 Walloon provinces and Brussels.
- **French-language optimized**: Correct parsing of French employment type labels (CDI, CDD, Interim, Stage, Apprentissage) and date formats.
- **Province mapping**: Automatically maps Walloon municipalities to their province using the official Forem location registry (GUFID lookup).
- **Rich data from API**: Salary (basePay), contact person (name, email, phone), skills, languages and soft skills are all available from the detail endpoint.
- **Apprenticeship and training paths**: Forem specifically lists alternance, apprentissage and CIP (Cellule d'Insertion Professionnelle) pathways not found on commercial boards.
- **German-speaking community**: Eastern cantons around Eupen and Malmedy (Deutschsprachige Gemeinschaft) are included - Forem covers all of Wallonia.

***

### Common Use Cases

- **Market research**: Track job postings across Walloon provinces and sectors
- **Salary benchmarking**: Extract monthly brut salaries for Belgian roles (Forem basePay field)
- **Talent pipeline**: Monitor which companies are hiring in Wallonia
- **Public sector jobs**: Le Forem lists Belgian government, CPAS, commune, education and healthcare vacancies
- **Apprenticeship tracking**: Monitor alternance and formation-professionnelle openings
- **French-language job market**: Monitor the Walloon economy, distinct from the Flemish VDAB ecosystem
- **Labour market analytics**: Analyze employment trends in the French-speaking Belgian economy
- **German-community coverage**: The Ostkantone (Eupen area) listings are included

***

### Notes and Limits

- **Coverage**: Wallonia and Brussels Capital Region only. Flanders (Dutch-speaking) uses VDAB (see Related Actors).
- **Language**: Most listings are in French (fr-BE). Some Brussels listings may be bilingual (French/Dutch) or in English.
- **Results per query**: Le Forem returns up to 25 results per API page. Pagination is handled automatically up to your maxResults cap.
- **Salary data**: Belgian salaries from Forem are typically gross monthly (brut par mois). "a discuter" means negotiable.
- **Employment types**: CDI (permanent), CDD (fixed-term), interim, stage (internship), apprentissage (apprenticeship dual training), etudiant (student job), independant (freelance).
- **Location resolution**: City names are resolved against the Forem GUFID location registry (4500+ entries) for accurate filtering. Partial matches are supported.
- **Update frequency**: Forem listings refresh continuously. Run daily for fresh data.

***

### Related Actors

Working across the Belgian job market? These complement Le Forem:

- [VDAB.be Scraper](https://apify.com/santamaria-automations/vdab-be-scraper) - Belgium Flanders public employment service (Dutch-speaking regional peer to this Walloon gov portal). Together, VDAB + Forem cover both Belgian language regions.

Broader coverage:

- [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.
- [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/forem-be-scraper/issues) or email contact@nanoscrape.com.

# Actor input Schema

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

One or more keyword queries in French (for example 'developpeur', 'infirmier', 'comptable', 'ingenieur'). Each runs as a separate search. Results are deduplicated.

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

Walloon city or province to filter by (for example 'Liege', 'Namur', 'Charleroi', 'Mons', 'Wavre'). Applied to all keyword searches.

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

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

## `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, fetches the full job detail from the Forem API for salary, complete description and contact details. Returns richer data at a slightly higher cost.

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

Maximum concurrent API requests. Higher values speed up detail fetches; Le Forem's public API tolerates up to 20.

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

How to order results. Le Forem's public search API only exposes a single native order (newest publications first) with no sort dropdown or sort URL parameter on the site. This field is present for fleet consistency; the sole supported value is 'newest'.

## Actor input object example

```json
{
  "searchQueries": [
    "developpeur"
  ],
  "location": "Liege",
  "maxResults": 100,
  "maxResultsPerQuery": 100,
  "includeJobDetails": true,
  "maxConcurrency": 5,
  "sortBy": "newest"
}
```

# Actor output Schema

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

Dataset of Belgian job listings from Le Forem. Each row has: id, title, company\_name, company\_logo\_url, company\_website, location, country (BE), region (Walloon province or Bruxelles-Capitale), salary\_min, salary\_max, salary\_currency, salary\_period, salary\_text, employment\_type, workplace\_type (on-site/hybrid/remote), open\_positions, occupation (Forem metier label), employer\_sector (NACE), listing\_expires\_at (ISO date), description, description\_full, description\_html, description\_md, job\_url, apply\_url, apply\_redirect\_url (partner board direct URL), partner\_board, partner\_ref, contact\_emails, contact\_phones, contact\_urls, contact\_person\_name, languages\_required (array with language/code/required/proficiency), experience\_required (array with occupation/level), driving\_licence, benefits\_other (array), competencies (array with code/label/required — technical task requirements from the Forem skills taxonomy), soft\_skills (array with code/label/required — personality and behavioural traits), education\_required (array with level/field\_of\_study — required diploma levels), position\_start\_date (ISO date — fixed start date when specified), position\_end\_date (ISO date — contract end date for CDD/interim roles), 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 = {
    "searchQueries": [
        "developpeur"
    ],
    "maxResults": 100,
    "maxResultsPerQuery": 100,
    "includeJobDetails": true,
    "maxConcurrency": 5,
    "sortBy": "newest"
};

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

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

```

## MCP server setup

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