# HelloWork France Job Listings & Salary Filter Scraper (`vexaloom-labs/hellowork-france-job-listings-and-salary-filter`) Actor

Search HelloWork.com by keyword, region, city, sector or job function, and filter by contract type, remote-work frequency, experience level, company type and disclosed salary range.

- **URL**: https://apify.com/vexaloom-labs/hellowork-france-job-listings-and-salary-filter.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## HelloWork France Jobs & Salary Details Scraper

Scrape **HelloWork** — one of France's largest job boards — with full job details, not just listing cards. Search by keyword, browse by region or city, browse by sector or job function, or paste search and job URLs. Every live HelloWork filter is exposed, and each record can include the full description, required skills, structured salary, exact posting and expiry dates, and a structured location. No login, cookies or API key required.

### What this actor does

- **Four modes:** `search` (one or more keywords), `byLocation` (region or city), `bySector` (sector or job function), and `byUrls` (pasted search-result and job URLs, mixed)
- **Full detail enrichment:** description HTML/text, skills, qualifications, education and experience requirements, industry, occupational category, company profile URL, exact posted/expiry dates, and structured salary/location
- **Every live filter:** contract type, remote-work frequency, full-time/part-time, experience level (including beginner-friendly `deb`), company type, CSR label, posted-within window, minimum salary, salary disclosed only, super-recruiter only, search radius and exact-match only
- **Structured output:** parsed salary min/max/period/currency, department, postal code, region and country, plus exact-vs-similar match flagging and multi-query provenance
- **Optional extras:** company profile enrichment and incremental runs that emit only new, updated or reappeared jobs
- **Empty fields are omitted** at every depth — no `null`, `""`, `[]` or `{}`

### Output per job

- `offerId` — HelloWork offer ID
- `title`, `company`, `companyLogoUrl`
- `location` — listing-card location text (e.g. `Lyon - 69`)
- `department` — French department code when derivable (`69`, `2A`, …)
- `city`, `postalCode`, `region`, `country` — structured detail-page location
- `contractType`, `workTime`, `remoteWork`, `contractDuration`, `companyType`
- `salary` — disclosed salary display text
- `salaryMin`, `salaryMax`, `salaryPeriod` (`yearly`/`monthly`/`hourly`/`daily`/`weekly`), `salaryCurrency`
- `postedDate` — exact UTC posting timestamp when the detail page exposes it; otherwise the approximate value derived from the listing text
- `postedDateRelative` — HelloWork's original relative text (e.g. `il y a 3 jours`)
- `validThrough` — UTC expiry timestamp when published
- `descriptionHtml`, `descriptionText` — full job description
- `skills[]`, `qualifications`, `qualificationsHtml`
- `educationLevel`, `experienceMonths`, `experienceLabel`
- `industry[]`, `occupationalCategory`, `employmentTypes[]`
- `companyUrl` — employer profile page
- `companyProfile` — optional nested object: `name`, `headquarters`, `foundedYear`, `employeeRange`, `revenue`, `teleworkPolicy`, `averageAge`, `genderSplit`, `genderEqualityIndex`, `description`
- `directApply` — true when HelloWork marks direct application as available
- `hasApplicationTracking`, `isSuperRecruiter`
- `isExactMatch` — false for HelloWork's similar-result cards; true for exact keyword matches
- `searchQuery`, `listPageUrl` — provenance for search runs
- `changeType`, `firstSeenAt`, `lastSeenAt` — only in incremental mode (`NEW`, `UPDATED`, `REAPPEARED`)
- `url`, `applyUrl` — canonical job page and HelloWork application landing URL
- `recordType: "job"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byLocation` / `bySector` / `byUrls` |
| `searchQueries` | array | – | One or more keywords (mode=search); duplicates are removed across queries |
| `region` | string | – | French region (mode=byLocation unless `city` is set; optional filter elsewhere) |
| `city` | string | – | French city/commune (mode=byLocation unless `region` is set; optional filter elsewhere) |
| `sectors` | array | – | Industry sectors (mode=bySector; optional filter elsewhere) |
| `jobFunctions` | array | – | Job functions / métiers (mode=bySector; optional filter elsewhere) |
| `contractTypes` | array | – | CDI, CDD, Intérim, Stage, Alternance and more |
| `remoteWork` | array | – | Fully remote / hybrid / occasional / no remote work |
| `employmentType` | array | – | Full-time / part-time / unspecified |
| `experienceLevels` | array | – | Beginner-friendly (`deb`), 0-1y, 2-3y, 4-5y, 6-10y, 10+ years, unspecified |
| `companyTypes` | array | – | Direct employer, recruitment agency, ESN, temp agency, training center |
| `csrLabels` | array | – | CSR / sustainability certifications |
| `minSalary` | int | `0` | Minimum disclosed annual salary in EUR (0–100,000) |
| `radiusKm` | string | `20` | Radius around `city` in km (0/5/10/20/50); ignored without a city |
| `postedWithin` | string | `all` | Any time / last 24h / last 3 days / last week / last month |
| `sortBy` | string | `relevance` | Relevance or newest first |
| `salaryOnly` | boolean | `false` | Only jobs that disclose a salary |
| `superRecruiterOnly` | boolean | `false` | Only HelloWork-verified "super recruiter" employers |
| `exactMatchesOnly` | boolean | `false` | Drop HelloWork's similar-result cards |
| `includeDetails` | boolean | `true` | Fetch each job's full detail page |
| `includeCompanyProfile` | boolean | `false` | Add employer profile facts when available (requires `includeDetails`) |
| `incrementalMode` | boolean | `false` | Emit only new, updated or reappeared jobs |
| `stateKey` | string | – | State key required for incremental mode; reuse it across runs |
| `startUrls` | array | – | HelloWork search-result and/or job URLs as `{"url": ...}` objects (mode=byUrls) |
| `maxItems` | int | `50` | Hard cap on emitted jobs (1–10,000) |

#### Example: multiple keyword searches with full details

```json
{
  "mode": "search",
  "searchQueries": ["developpeur python", "data engineer"],
  "city": "Lyon",
  "contractTypes": ["CDI"],
  "exactMatchesOnly": true,
  "includeDetails": true,
  "maxItems": 100
}
```

#### Example: recent jobs in a region

```json
{
  "mode": "byLocation",
  "region": "Bretagne",
  "postedWithin": "w",
  "salaryOnly": true,
  "sortBy": "date",
  "maxItems": 100
}
```

#### Example: sector + function browse with a salary floor

```json
{
  "mode": "bySector",
  "sectors": ["Inform_SSII"],
  "jobFunctions": ["Informatique_dev"],
  "minSalary": 45000,
  "includeDetails": true,
  "maxItems": 200
}
```

#### Example: paste a job URL and a saved search URL

```json
{
  "mode": "byUrls",
  "startUrls": [
    {"url": "https://www.hellowork.com/fr-fr/emplois/83761250.html"},
    {"url": "https://www.hellowork.com/fr-fr/emploi/recherche.html?k=comptable&l=Bordeaux"}
  ],
  "includeDetails": true,
  "maxItems": 50
}
```

#### Example: incremental daily feed

```json
{
  "mode": "search",
  "searchQueries": ["infirmier"],
  "city": "Paris",
  "incrementalMode": true,
  "stateKey": "paris-nurses-daily",
  "includeDetails": true,
  "maxItems": 500
}
```

### Use cases

- **Recruitment agencies** — monitor new listings and full requirements in a target city or sector
- **Labor-market research** — track posting volume, salary disclosure, education and experience requirements
- **Job aggregators / HR tech** — enrich existing listings with descriptions, skills and structured salary
- **Salary benchmarking** — analyse disclosed ranges by sector, function, experience and region
- **Remote-work and ESG sourcing** — combine remote-work frequency and CSR certifications
- **Incremental alerting** — feed only new or changed jobs into a CRM, ATS or notification pipeline

### FAQ

**What is HelloWork?** One of France's largest job boards, aggregating listings from employers and recruitment agencies. This is an independent third-party actor, not affiliated with HelloWork.

**Do I need a login, cookies or a proxy?** No. The actor reads public job pages and needs no account, cookie, API key or proxy setup. Enter your search and run it.

**What is the difference between the four modes?** `search` runs one or more keyword queries; `byLocation` browses a region or city without a keyword; `bySector` browses a sector or job function; `byUrls` accepts pasted HelloWork search-result and job URLs, mixed in one list.

**Why are some fields missing on some jobs?** HelloWork only publishes certain details on some listings: foreign or interim pages that have no structured job data may lack an expiry date, structured city/postal code or skills, and many employers do not disclose a salary. Missing fields are omitted rather than filled with placeholder values.

**What does `isExactMatch` mean?** For narrow queries HelloWork can append similar results after the exact matches. `isExactMatch: false` marks those similar cards; set `exactMatchesOnly: true` to remove them.

**Why is a salary missing when HelloWork shows an estimate?** Only employer-disclosed salaries are emitted. HelloWork's own "Estimation Hellowork" hint is not treated as a disclosed salary, so it is omitted and `salaryOnly` will not return that job.

**How does incremental mode work?** It stores a content hash per job under your `stateKey` and emits only `NEW`, `UPDATED` or `REAPPEARED` records. Reuse the same key across scheduled runs; the run stops after a run of pages with no new or changed jobs.

**Does `maxItems` guarantee that many results?** No — it is a cap. If fewer jobs match your filters, you get fewer records. The actor supports up to 10,000 records per run.

**How fresh is the data?** HelloWork updates its listings continuously; every run reads the current live search and detail pages.

**Can I get an external ATS application URL?** No. Anonymous pages only expose HelloWork's own application flow, so `applyUrl` points to the HelloWork landing page and `directApply` reflects whether HelloWork marks direct application as available.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

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

One or more free-text keyword searches (mode=search). Each query runs with the same filters; duplicate jobs are removed.

## `region` (type: `string`):

French administrative region. Required for mode=byLocation unless `city` is set; also usable as a filter on other modes.

## `city` (type: `string`):

French city or commune (e.g. `Lyon`, `Bordeaux`). Takes priority over `region`; also usable as a filter on other modes.

## `sectors` (type: `array`):

One or more industry sectors (mode=bySector, optional filter elsewhere).

## `jobFunctions` (type: `array`):

One or more job functions (mode=bySector, optional filter elsewhere).

## `contractTypes` (type: `array`):

Filter by one or more contract types (optional, all modes).

## `remoteWork` (type: `array`):

Filter by disclosed remote-work (télétravail) frequency (optional, all modes).

## `employmentType` (type: `array`):

Filter by employment schedule -- full-time vs part-time (optional, all modes).

## `experienceLevels` (type: `array`):

Filter by the years of experience the employer asks for (optional, all modes).

## `companyTypes` (type: `array`):

Filter by the type of hiring organization (optional, all modes).

## `csrLabels` (type: `array`):

Filter to employers holding a specific CSR (corporate social responsibility) certification (optional, all modes).

## `minSalary` (type: `integer`):

Only include jobs whose disclosed salary meets this yearly gross EUR floor (optional, all modes). Matches HelloWork's own "Salaire minimum" slider (0-100,000, steps of 1,000).

## `radiusKm` (type: `string`):

Widen or narrow the search radius around `city` (ignored when only `region` is set -- HelloWork's radius filter only applies to a specific city/commune).

## `postedWithin` (type: `string`):

Only include jobs posted within this time window (optional, all modes).

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

Result ordering.

## `salaryOnly` (type: `boolean`):

Only include job listings that disclose a salary range (optional, all modes).

## `superRecruiterOnly` (type: `boolean`):

Only include job listings from HelloWork-verified "super recruiter" companies (optional, all modes).

## `exactMatchesOnly` (type: `boolean`):

Drop HelloWork similar-result cards ("LO-Moteur-Approchant"). Useful for narrow technical queries.

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

Open each job page for description, skills, structured salary, exact dates and location. Adds one request per job.

## `includeCompanyProfile` (type: `boolean`):

Add headquarters, founding year, employee range, revenue and telework policy when the employer page exposes them. Requires includeDetails. Adds one request per unique company.

## `incrementalMode` (type: `boolean`):

Keep state per `stateKey` and emit only new, updated or reappeared jobs. Unchanged jobs are updated in state and skipped.

## `stateKey` (type: `string`):

Required when `incrementalMode` is on. Reuse the same key across scheduled runs.

## `startUrls` (type: `array`):

HelloWork search-result URLs and/or job detail URLs. Mixed lists are allowed; duplicates are removed. Enter one URL per row in the Console (the request-list editor wraps it as `{"url": "..."}`); via the API, send `{"url": "..."}` objects.

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

Hard cap on emitted job listings (1–10,000).

## Actor input object example

```json
{
  "mode": "search",
  "searchQueries": [
    "developpeur"
  ],
  "region": "",
  "city": "",
  "sectors": [],
  "jobFunctions": [],
  "contractTypes": [],
  "remoteWork": [],
  "employmentType": [],
  "experienceLevels": [],
  "companyTypes": [],
  "csrLabels": [],
  "minSalary": 0,
  "radiusKm": "20",
  "postedWithin": "all",
  "sortBy": "relevance",
  "salaryOnly": false,
  "superRecruiterOnly": false,
  "exactMatchesOnly": false,
  "includeDetails": true,
  "includeCompanyProfile": false,
  "incrementalMode": false,
  "stateKey": "",
  "startUrls": [],
  "maxItems": 3
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset containing all scraped HelloWork job listings.

# 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 = {
    "mode": "search",
    "searchQueries": [
        "developpeur"
    ],
    "region": "",
    "city": "",
    "sectors": [],
    "jobFunctions": [],
    "contractTypes": [],
    "remoteWork": [],
    "employmentType": [],
    "experienceLevels": [],
    "companyTypes": [],
    "csrLabels": [],
    "minSalary": 0,
    "radiusKm": "20",
    "postedWithin": "all",
    "sortBy": "relevance",
    "salaryOnly": false,
    "superRecruiterOnly": false,
    "exactMatchesOnly": false,
    "includeDetails": false,
    "includeCompanyProfile": false,
    "incrementalMode": false,
    "stateKey": "",
    "startUrls": [],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/hellowork-france-job-listings-and-salary-filter").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 = {
    "mode": "search",
    "searchQueries": ["developpeur"],
    "region": "",
    "city": "",
    "sectors": [],
    "jobFunctions": [],
    "contractTypes": [],
    "remoteWork": [],
    "employmentType": [],
    "experienceLevels": [],
    "companyTypes": [],
    "csrLabels": [],
    "minSalary": 0,
    "radiusKm": "20",
    "postedWithin": "all",
    "sortBy": "relevance",
    "salaryOnly": False,
    "superRecruiterOnly": False,
    "exactMatchesOnly": False,
    "includeDetails": False,
    "includeCompanyProfile": False,
    "incrementalMode": False,
    "stateKey": "",
    "startUrls": [],
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/hellowork-france-job-listings-and-salary-filter").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 '{
  "mode": "search",
  "searchQueries": [
    "developpeur"
  ],
  "region": "",
  "city": "",
  "sectors": [],
  "jobFunctions": [],
  "contractTypes": [],
  "remoteWork": [],
  "employmentType": [],
  "experienceLevels": [],
  "companyTypes": [],
  "csrLabels": [],
  "minSalary": 0,
  "radiusKm": "20",
  "postedWithin": "all",
  "sortBy": "relevance",
  "salaryOnly": false,
  "superRecruiterOnly": false,
  "exactMatchesOnly": false,
  "includeDetails": false,
  "includeCompanyProfile": false,
  "incrementalMode": false,
  "stateKey": "",
  "startUrls": [],
  "maxItems": 3
}' |
apify call vexaloom-labs/hellowork-france-job-listings-and-salary-filter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/hellowork-france-job-listings-and-salary-filter"
        }
    }
}
```

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/jF1yrs5ZIMS6aoRcZ/builds/ttW7DK9FHDnNc0eEf/openapi.json
