# HelloWork Jobs Scraper | France Jobs, Salaries & All Filters (`corvuslab/hellowork-scraper`) Actor

Scrape HelloWork (hellowork.com) job listings across France with every site filter: contract, remote work, job function, industry, experience, employer type, radius, min salary. 74 fields per job: salary incl. estimates, skills, education, company headcount & revenue. Incremental mode + alerts.

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

## Pricing

from $0.75 / 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.

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

### What does HelloWork Jobs Scraper do?

HelloWork Jobs Scraper extracts job listings from **HelloWork ([hellowork.com](https://www.hellowork.com/fr-fr/))**, one of France's biggest job boards, with **the site's complete filter set**. Every job comes back as a clean record of **86 structured fields**, from salary (including HelloWork's own estimate when the pay is hidden) and remote-work mode to skills, education and experience, plus an optional profile of every employer. It needs no code, and output goes to JSON, CSV, Excel, the API or an AI agent.

Give it a keyword and a location, or just press Start. You can also paste HelloWork search URLs (your filters carry over) or single job URLs.

> New to Apify? Sign up free and use the included monthly platform credit to try this Actor. No credit card needed.

**Why this scraper**

- 🎚️ **Every HelloWork filter** — 12 site filters plus keyword and location, applied on HelloWork itself, so you only pay for jobs you actually want.
- ⚡ **Fast & low-cost** — a lightweight scraper with no browser, so large runs stay cheap.
- 🧾 **Rich, typed records** — 86 structured fields per job, not raw page text.
- ♻️ **Cheap to monitor** — incremental mode returns only what changed.
- 🔔 **Notifications built in** — Telegram, Slack, Discord, WhatsApp or any webhook.
- 🤖 **AI- & API-ready** — compact output, MCP-friendly, one-click integrations.

***

### What data can you extract from HelloWork?

Every record carries **86 fields** grouped like this:

| Group | What you get |
|---|---|
| **Job & contract** | Title, URL, job ID, contract type (CDI, CDD, intérim, alternance, stage, freelance…), contract length ("6 mois", and in days) when stated, employment type, working time (full/part-time), remote-work mode plus `isRemote` / `isHybrid` flags, job function, industry, direct-apply flag, the employer's job reference, tags |
| **Salary** | Salary as displayed, numeric min and max, period, currency, plus `salaryIsEstimate` marking the site's own estimate on jobs that don't post pay, and that estimate on its own: median and 10th–90th percentiles |
| **Location** | Display location, city, département code, postal code, region, country, and the street address and latitude/longitude when the posting shows a map |
| **Requirements** | Experience in HelloWork's own label ("Exp. 5 ans min.") and in months, education levels ("Bac +5") and credentials, skills list |
| **Company** | Company name, employer type (direct employer, recruitment agency, temp agency, IT services firm, training centre), Super-recruiter badge, company page URL, logo — and with **Add company profiles**: open jobs, headcount band (with min/max), founding year, headquarters, revenue (text and €), remote-work policy, average age and tenure, gender split, gender-equality index and the benefits they list |
| **Dates, description & tracking** | Posted date in UTC plus the site's "posted … ago" text, expiry date, full description as plain text, HTML and Markdown, and change-tracking fields for monitoring (`changeType`, first/last-seen dates, expiry date, repost detection) |

***

### Key features

- 🎚️ **The full HelloWork filter set** — job function (34 options), industry (26), experience, employer type, radius, working time, Super-recruiter, minimum salary, date posted, contract type (all 11), remote work and sorting — plus **salary shown** (posted pay, or HelloWork's estimate) and **exclude keywords** filters.
- 🏭 **Company profiles** — optional employer profile on every job: headcount, revenue, benefits and more.
- 🏢 **Skip the agencies** — keep only direct employers; every record says who is hiring (company, recruitment or temp agency, IT services firm, training centre).
- 🏠 **Remote mode and working time on every job** — straight from the search results, so you get them even with details off.
- 💶 **Salary coverage beyond what's posted** — when the pay is hidden you still get HelloWork's own estimate, clearly flagged.
- 🔎 **Search or URL scraping** — several keywords × several locations in one run (merged and de-duplicated), or paste HelloWork search and job URLs.
- ♻️ **Incremental monitoring with alerts** — get only new, changed, reappeared and expired jobs, pushed to Telegram, Slack, Discord, WhatsApp or any webhook.
- 📓 **Straight into Notion** — every job becomes a page in your Notion database as the run goes, with typed, filterable columns created for you.

***

### 🚀 How to scrape HelloWork

1. Open the Actor and enter **keywords** (e.g. `développeur`) and a **location** (e.g. `Lyon`), or paste a HelloWork search URL.
2. Pick any **filters**: contract, remote work, job function, employer type, minimum salary and more.
3. Set **Max results** and choose whether to **fetch full details**.
4. (Optional) Turn on **incremental mode** and a **notification** channel, then **Schedule** it.
5. Click **Start**, watch results stream into the Output tab, and download them as **JSON, CSV or Excel** or pull them from the **API**.

No login, no cookies, no setup. Leave the input empty and you get the 25 newest jobs in France.

#### Quick-start example input

```json
{
  "query": "développeur",
  "location": "Lyon",
  "radiusKm": "20",
  "contractTypes": ["CDI"],
  "remoteWork": ["Partiel", "Complet"],
  "employerTypes": ["Entreprises"],
  "minAnnualSalary": 45000,
  "maxResults": 100
}
```

This finds up to 100 permanent (CDI) developer jobs within 20 km of Lyon that offer hybrid or full remote work, pay at least 45k a year, and are posted by the employer itself rather than a recruitment agency.

***

### Input

Configure it in the visual editor with no code, or pass JSON via the API.
**46 inputs** are available, grouped exactly as in the Actor's input form.

#### 🔎 Search

| Field | Type | What it does |
|---|---|---|
| `query` | string | Job title, skill or company, e.g. `développeur`, `comptable`, `infirmier`. Separate several with commas: each runs separately and results are merged and de-duplicated. |
| `location` | string | City, département number or region, e.g. `Lyon`, `75`, `Île-de-France`. Comma-separate several; every keyword runs in every location. Empty = all of France. |
| `radiusKm` | enum | `0` (city only), `10`, `20`, `50` or `100` km around the city. HelloWork widens to 20 km by default. |
| `startUrls` | array | HelloWork search URLs (all site filters kept) or single job URLs. |
| `maxResults` | integer | Cap on jobs returned across all searches (default 25, `0` = unlimited). |
| `ignoreUrlFailures` | boolean | Skip URLs that can't be read instead of failing the run. |

#### 🎚️ HelloWork filters

All applied on HelloWork itself except **Salary shown**, which the Actor applies, so you never pay for a filtered-out job. Multi-select filters are OR'ed within a filter.

| Field | Type | What it does |
|---|---|---|
| `contractTypes` | array | CDI, CDD, Intérim, Stage, Alternance, Freelance, Indépendant, Franchise, Associé, Fonctionnaire, Stage de lycée (11 values). |
| `remoteWork` | array | Full remote, partial remote (hybrid), occasional remote, on-site only. |
| `workingTime` | array | Full-time, part-time, not specified. |
| `experienceLevels` | array | Beginners welcome, 0–1, 2–3, 4–5, 6–10, 10+ years, not specified. |
| `postedWithin` | enum | Any time, last 24 hours, last 3 days, last week, last month. |
| `minAnnualSalary` | integer | Only jobs paying at least this much per year, e.g. `40000`. |
| `salaryFilter` | enum | `any` (default), `withSalary` (a posted salary or HelloWork's estimate) or `postedOnly` (the employer published the pay). Jobs without one are skipped and never charged. |
| `excludeKeywords` | string | Skip jobs whose title contains any of these words, e.g. `stage, alternance, senior` (case and accents ignored). Skipped jobs are never charged. |
| `jobFunctions` | array | The site's "Fonction" filter, 34 values: IT & software development, sales, accounting & finance, healthcare, logistics, HR, engineering and more. |
| `industries` | array | The site's "Secteur" filter, 26 values: banking & insurance, construction, IT services, public hospitals, retail and more. |
| `employerTypes` | array | Direct employers, recruitment agencies, temp agencies, IT services firms (ESN), training centres. |
| `superRecruiterOnly` | boolean | Only employers HelloWork badges as "Super recruteur". |
| `sortBy` | enum | `date` (newest first, default: every matching job once) or `relevance` (HelloWork's order; skips 2–4% of jobs). |

#### 📄 Output

| Field | Type | What it does |
|---|---|---|
| `includeDetails` | boolean | Open each job page for the description and extra fields (on by default). Off = fastest, cheapest runs. |
| `includeCompanyProfile` | boolean | Add each employer's company profile (fields listed under Output). One extra page per company per run; needs full details on. Off by default. |
| `descriptionFormat` | enum | `all`, `text`, `html` or `markdown`. |
| `descriptionMaxLength` | integer | Cut the description and candidate profile to this many characters (empty or 0 = full text). |
| `compact` | boolean | Core fields only: title, company, location, contract, remote, salary, date, URL. Ideal for AI agents and MCP clients. |
| `excludeEmptyFields` | boolean | Drop null/empty fields for cleaner output. |

#### ♻️ Incremental monitoring

| Field | Type | What it does |
|---|---|---|
| `incrementalMode` | boolean | Compare against the previous run and emit only what changed (see the monitoring section). |
| `stateKey` | string | Stable name for the tracked search (auto-derived if blank). |
| `emitUnchanged` / `emitExpired` | boolean | Also emit UNCHANGED jobs / jobs that disappeared since the last run. |
| `skipReposts` | boolean | Drop jobs re-posted under a new ID (same title, company and location as a job seen in an earlier run). Skipped before their page is opened, so they cost nothing. |

#### 🔔 Notifications

Credentials are secret inputs: encrypted at rest, masked in the UI and never written to the run log.

| Field | Type | What it does |
|---|---|---|
| `telegramToken` + `telegramChatId` | string | Telegram bot token + chat or channel ID. |
| `slackWebhookUrl` / `discordWebhookUrl` | string | Incoming webhook URL. |
| `whatsappPhoneNumberId` + `whatsappAccessToken` + `whatsappTo` | string | WhatsApp Cloud API phone number ID, access token and recipient number(s). |
| `webhookUrl` + `webhookHeaders` | string / object | POST structured JSON anywhere: n8n, Make, Zapier. |
| `notificationLimit` | integer | How many jobs to include per message (default 5). |
| `notifyOnlyChanges` | boolean | In incremental mode, alert only on NEW, UPDATED and REAPPEARED jobs. |

#### 📓 Send results to Notion

| Field | Type | What it does |
|---|---|---|
| `notionApiKey` | string | Internal integration secret from notion.so/my-integrations (starts with `ntn_`). Connect the integration to your database (⋯ → Connections). |
| `notionDatabaseId` | string | The database URL or its 32-character ID. It can start empty — columns are created on the first run. |
| `notionCreateProperties` | boolean | Create any missing columns with the right Notion type (on by default). Off = write only into columns you made. |

#### ⚙️ Advanced

| Field | Type | What it does |
|---|---|---|
| `proxyConfiguration` | object | Optional; not needed normally. |
| `maxRequestRetries` | integer | Retries per failed request (default 3). |

#### More example inputs

Nurses and care jobs across three regions, posted in the last 24 hours:

```json
{
  "query": "infirmier, aide-soignant",
  "location": "Île-de-France, Auvergne-Rhône-Alpes, Occitanie",
  "postedWithin": "24h",
  "workingTime": ["ft"],
  "maxResults": 500
}
```

Daily monitoring of new accounting jobs in Paris from direct employers, with Slack alerts:

```json
{
  "query": "comptable",
  "location": "75",
  "jobFunctions": ["Compta_gestion_finance_audit"],
  "employerTypes": ["Entreprises"],
  "incrementalMode": true,
  "emitExpired": true,
  "slackWebhookUrl": "https://hooks.slack.com/services/..."
}
```

***

### Output

Each dataset item is one HelloWork job. Every record carries the core fields from the search results; **Fetch full details** (on by default) adds the description, skills, education, experience, industry, employer details and dates. A real record with company profiles on (long text shortened):

```json
{
  "id": "83585312",
  "url": "https://www.hellowork.com/fr-fr/emplois/83585312.html",
  "title": "Ingénieur - Ingénieure Observabilité H/F",
  "company": "Capgemini",
  "location": "Lille - 59",
  "city": "Lille",
  "departmentCode": "59",
  "postalCode": "59000",
  "region": "Hauts-de-France",
  "contractType": "CDI",
  "workingTime": "Temps plein",
  "remoteWork": "Télétravail occasionnel",
  "isRemote": false,
  "isHybrid": true,
  "salaryText": "Estimation Hellowork → 33 200 - 48 800 € / an",
  "salaryMin": 33200,
  "salaryMax": 48800,
  "salaryPeriod": "YEAR",
  "salaryCurrency": "EUR",
  "salaryIsEstimate": true,
  "salaryEstimateP25": 33200,
  "salaryEstimateP75": 48800,
  "postedAt": "2026-09-21T10:56:51Z",
  "validThrough": "2026-10-21T10:56:51Z",
  "experienceText": "Exp. 1 à 7 ans",
  "experienceMonths": 12,
  "experienceYearsMin": 1,
  "experienceYearsMax": 7,
  "educationLevels": ["Bac +5"],
  "skills": ["Ansible", "Prometheus", "PowerShell", "API", "AWS", "Grafana", "Instrumentation", "Kubernetes", "Node.js", "Optimisation des performances", "Python", "Scripting", "Java", "Monitoring", "Docker"],
  "industry": "Secteur informatique, ESN",
  "employerType": "ESN",
  "isSuperRecruiter": false,
  "jobReference": "241411 44456342",
  "companyUrl": "https://www.hellowork.com/fr-fr/entreprises/capgemini-france-6026.html",
  "companyLogo": "https://f.hellowork.com/img/entreprises/160_160/193881.png",
  "companyOpenJobs": 545,
  "companyFoundedYear": 1967,
  "companyHeadquarters": "Issy-les-Moulineaux - 92",
  "companyRevenue": "22 Milliards d'euros",
  "companyRevenueEur": 22000000000,
  "companyRemotePolicy": "Télétravail partiel possible",
  "companyAverageAge": 37,
  "companyMenPercent": 67,
  "companyWomenPercent": 33,
  "companyBenefits": ["Formations et certifications (Azure, AWS, GCP, SAP...)", "Couverture santé et prévoyance", "Télétravail entre 20% et 70% du temps", "Prime de participation et d'intéressement"],
  "description": "Les missions du poste — Choisir Capgemini, c'est choisir une entreprise où vous serez en mesure de façonner votre carrière selon vos aspirations. Avec le soutien et …",
  "qualifications": "Votre profil — * Formation : Bac +5 en informatique, en technologie de l'information ou dans un domaine connexe. — * Expérience : A minima 5 ans d'expérience dans la …",
  "searchKeyword": "ingénieur",
  "searchUrl": "https://www.hellowork.com/fr-fr/emploi/recherche.html?k=ing%C3%A9nieur",
  "source": "hellowork.com",
  "scrapedAt": "2026-09-29T20:19:19.762365+00:00"
}
```

The description also comes as `descriptionHtml` and `descriptionMarkdown` (choose with `descriptionFormat`).

#### Data fields

- **Core (from search results)**: `id`, `url`, `title`, `company`, `location`, `city`, `departmentCode`, `contractType`, `contractDuration`, `contractDurationDays`, `workingTime`, `remoteWork`, `isRemote`, `isHybrid`, `salaryText`, `salaryMin`, `salaryMax`, `salaryIsEstimate`, `postedAgo`, `postedAt`, `isSuperRecruiter`, `companyLogo`.
- **Details** (with `includeDetails`): `salaryEstimateMedian`, `salaryEstimateP10`/`P25`/`P75`/`P90`, `salaryEstimatePeriod`, `description`, `descriptionHtml`, `descriptionMarkdown`, `qualifications` (the "profil recherché" candidate profile, on about 4 in 5 jobs), `skills`, `experienceText`, `experienceMonths`, `experienceYearsMin`, `experienceYearsMax`, `educationLevels`, `educationCredentials`, `industry`, `occupationalCategory`, `employmentType`, `validThrough`, `jobReference`, `directApply`, `tags`.
- **Company**: `company`, `employerType`, `isSuperRecruiter`, `companyUrl`, `companyLogo`.
- **Company profile** (with `includeCompanyProfile`): `companyOpenJobs`, `companyHeadcount`, `companyHeadcountMin`, `companyHeadcountMax`, `companyFoundedYear`, `companyHeadquarters`, `companyRevenue`, `companyRevenueEur`, `companyRemotePolicy`, `companyAverageAge`, `companyAverageTenureYears`, `companyMenPercent`, `companyWomenPercent`, `companyParityIndex`, `companyBenefits`. Coverage varies by employer: open jobs almost always, HQ, founding year and headcount ~85%, benefits about half, revenue and gender split about one in four.
- **Location**: `postalCode`, `region`, `country`, plus `streetAddress`, `latitude`, `longitude` when the posting shows a map.
- **Tracking**: `source`, `searchKeyword`, `searchLocation`, `searchUrl` (the results page the job was found on), `scrapedAt`, `detailFetched`, `contentHash`, plus the monitoring fields described below.

Missing values are `null`; `compact` and `excludeEmptyFields` trim the record (see Input). The Output tab also has a ready-made **Overview** table view.

***

### ♻️ How to monitor HelloWork with incremental mode

Schedule the Actor and turn on **incremental mode**: each run compares against the last and
emits only what changed. Unchanged jobs are recognised from the search results *before* their
job page is opened and are never charged, so after the first run you pay only for new or changed jobs.

Every record then carries `changeType`:

- **NEW**: first time this search has seen the job.
- **UPDATED**: title, company, place, contract, working time, remote mode or salary changed.
- **REAPPEARED**: the job had disappeared and is back (within 60 days).
- **UNCHANGED**: only emitted with `emitUnchanged`.
- **EXPIRED**: gone since the last run, with `expiredAt`; only emitted with `emitExpired`.

`firstSeenAt`, `lastSeenAt` and `previousSeenAt` show how long each job stays open. A job that an
employer re-posts under a new ID (same title, company and location) is flagged with `isRepost`,
`repostOfId` and `repostDetectedAt`, or dropped entirely with **Skip reposts**.

#### Setting up scheduled monitoring

1. Configure your keywords, locations and filters. **Posted within: last 24 hours** works well for daily runs.
2. Turn on **Incremental mode**. To be told when jobs close, also turn on **Include expired records** and set **Max results** to 0: expiries are only reported when a run covers the whole search, since a job past the cap isn't gone.
3. Run it once to seed the baseline.
4. Open the **Schedules** tab and set a recurring run (e.g. hourly or daily).
5. Optionally add an alert channel (next section).

***

### 🔔 How to set up HelloWork alerts

Get pinged the moment a matching job appears on HelloWork: ✈️ **Telegram**, 💬 **Slack**,
🎮 **Discord**, 🟢 **WhatsApp** or any 🪝 **webhook** (n8n, Make, Zapier). Fill in only the
channels you want (the fields are listed under Input → Notifications); a failing channel never
stops the run. Pair it with **incremental mode** to hear only about genuinely new or changed
jobs, with no duplicates across runs.

***

### 💡 What can you do with HelloWork data?

#### Find jobs before everyone else

Run a daily search on your role, region and minimum salary and get new HelloWork postings pushed to Telegram or Slack. Filter out agencies and on-site roles so every alert is worth opening.

#### Recruitment and staffing lead generation

Every record names the hiring company, its employer type and its HelloWork company page; company profiles add headcount, revenue and open-job counts to size each lead.

#### Salary benchmarking in France

Numeric min/max salaries by contract, job function, industry, experience and département turn thousands of postings into a pay grid. Benchmark on posted pay only, or add HelloWork's estimate percentiles for wider coverage.

#### Labour-market, remote-work and skills research

Track how many jobs each region, industry or job function opens every week, the share of hybrid and full-remote roles, and which skills and diploma levels (Bac +2 to Bac +5) employers ask for.

#### Feed AI agents and LLM pipelines

Send compact JSON into an LLM, an MCP tool or a vector store for job matching or CV tailoring.

***

### 💰 How much does it cost to scrape HelloWork?

This Actor uses Apify's **pay-per-event** model: a small fee when a run starts, plus a
fee for each job returned. See the Actor's **Pricing** tab for the current numbers. They're
shown live there, so this page never goes out of date.

Three things cut your bill:

- **Filters**: jobs you filter out (including **Salary shown** and **Exclude keywords**) are never billed.
- **Incremental mode**: after the first run you pay only for new or changed jobs.
- **Details off**: for pure volume or counting work, switch off full details for the fastest runs.

***

### 🔌 Integrations & export

Export to **JSON, CSV or Excel**, or use the **API**. Runs on a **schedule**, connects to
**Google Sheets, Make, Zapier and n8n**, and works as an **MCP tool** for AI agents.

***

### 🔗 Using the API

Run this Actor from your own code. Example with the Apify Python client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run_input = {
    "query": "développeur",
    "location": "Lyon",
    "contractTypes": ["CDI"],
    "remoteWork": ["Partiel", "Complet"],
    "maxResults": 50,
}

run = client.actor("corvuslab/hellowork-scraper").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["company"], item["salaryText"])
```

It also works with the JavaScript/TypeScript client, the Apify CLI and the REST API.

***

### ❓ FAQ

**How many jobs can I get?** As many as your search matches, up to 20,000 per run. Set `maxResults` (`0` = unlimited). With full details on, a run handles several thousand jobs per hour, so raise the run timeout for very large pulls. A run with no keyword and no location covers all of France, which is hundreds of thousands of jobs, so add filters or a cap.

**Why did my Lyon search return jobs in Villeurbanne and other nearby towns?** HelloWork searches 20 km around a city by default. Set **Search radius** to `City only (0 km)` for exact matches, or widen it to 50 or 100 km.

**What does `salaryIsEstimate` mean?** When an employer doesn't post a salary, HelloWork often shows its own estimate. We return it in `salaryMin`/`salaryMax` with `salaryIsEstimate: true`, and on its own as a median and 10th–90th percentiles (`salaryEstimate…`). In our tests close to 9 in 10 detailed jobs came with a numeric salary, roughly a third of them estimates.

**Why is `remoteWork` or `employerType` empty on some jobs?** Both are only filled when the posting states them; a `null` remote mode usually means on-site or unspecified. To target remote roles, use the **Remote work** filter.

**Why are `latitude`, `longitude` and `streetAddress` often empty?** They only exist when the posting shows a map (about one job in five). City, postal code, département and region are filled on nearly every job.

**Does it return recruiter emails or phone numbers?** No. HelloWork doesn't publish recruiter contact details on its job pages, and applications go through the site. You do get the company name, employer type, company page and the direct-apply flag.

**Are posting dates accurate?** Yes. `postedAt` and `validThrough` are real UTC timestamps, and `postedAgo` keeps the site's own French "posted … ago" text.

***

### ⚖️ Is it legal to scrape HelloWork?

This Actor collects only **publicly available** job listings. You're responsible for how you use
the data, in particular any personal information, and for complying with HelloWork's terms and
applicable law, including the GDPR. Not affiliated with, endorsed by or sponsored by HelloWork.

***

**Keywords:** hellowork scraper · hellowork api · hellowork.com scraper · hellowork jobs scraper · scrape hellowork jobs · offres d'emploi hellowork · France job scraper · French job listings · emploi France · salary data France · télétravail jobs · job monitoring · recruitment lead generation · export to CSV · export to Excel · no-code scraper · MCP tool for AI agents

# Changelog

This Actor's version history is a separate document: https://apify.com/corvuslab/hellowork-scraper/changelog.md

# Actor input Schema

## `query` (type: `string`):

Job title, skill or company, e.g. développeur, comptable, infirmier. Separate several searches with commas — each runs on its own and results are merged and de-duplicated.

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

City, département number or region, e.g. Lyon, 75, Île-de-France. Separate several with commas — every keyword is searched in every location. Leave empty for all of France.

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

How far around a city to search. Only applies when a location is set. Left empty, the site uses 20 km — so 'Lyon' also returns nearby towns. Pick 'City only' for exact matches.

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

Paste HelloWork search URLs (every filter you set on the site is kept) or individual job URLs such as https://www.hellowork.com/fr-fr/emplois/83841806.html.

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

Maximum number of jobs to return across all searches. Set 0 for unlimited (bounded by how many jobs the search has).

## `ignoreUrlFailures` (type: `boolean`):

Skip URLs that cannot be interpreted instead of failing the whole run.

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

Only jobs with these contract types.

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

Only jobs offering this kind of remote work.

## `workingTime` (type: `array`):

Full-time or part-time.

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

Only jobs asking for this much experience.

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

Only jobs published in this window. Use 'Last 24 hours' for a daily schedule.

## `minAnnualSalary` (type: `integer`):

Only jobs paying at least this much per year, e.g. 40000. Leave empty for no salary filter.

## `salaryFilter` (type: `string`):

Keep only jobs that show pay. 'Posted salary only' keeps jobs where the employer published the pay. 'Posted or HelloWork estimate' also keeps jobs where HelloWork shows its own salary estimate (needs 'Fetch full details'; with details off it keeps posted salaries only). Skipped jobs are never charged.

## `excludeKeywords` (type: `string`):

Skip jobs whose title contains any of these words, e.g. stage, alternance, senior. Separate several with commas; case and accents are ignored. Skipped jobs are never charged.

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

The kind of role (the site's 'Fonction' filter).

## `industries` (type: `array`):

The employer's sector (the site's 'Secteur' filter).

## `employerTypes` (type: `array`):

Who is hiring — e.g. skip agencies by picking 'Direct employers' only.

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

Only employers the site badges as 'Super recruteur' (responsive, reliable recruiters).

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

Newest first (default) returns every matching job exactly once. Relevance is HelloWork's own order; it ranks the best matches first but repeats some jobs across pages and skips a few (2-4% of a search).

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

Open each job's page for the full description and the extra fields. Turn off for the fastest, cheapest runs.

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

Also open each employer's HelloWork company page (once per company per run) and add its profile: open jobs, headcount band, founding year, headquarters, revenue, remote-work policy, average age and tenure, gender split, gender-equality index and the benefits they list. Needs full details on. Not every company publishes every fact.

## `descriptionFormat` (type: `string`):

Which format(s) of the job description to include.

## `descriptionMaxLength` (type: `integer`):

Cut the description and the candidate profile (qualifications) to this many characters. Leave empty or 0 for the full text — handy for smaller payloads in AI pipelines.

## `compact` (type: `boolean`):

Emit only the core fields (title, company, location, contract, remote, salary, date, URL). Ideal for AI agents and MCP clients.

## `excludeEmptyFields` (type: `boolean`):

Remove null, empty-string and empty-array fields from each record.

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

Track state between runs and tag every record with a changeType (NEW / UPDATED / UNCHANGED / EXPIRED).

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

Stable name for the tracked search. Leave empty to derive one automatically from your search settings.

## `emitUnchanged` (type: `boolean`):

Also emit records that have not changed since the previous run.

## `emitExpired` (type: `boolean`):

Emit a record for each job that was present last run but is gone now. Only reported when the run covers the whole search (Max results 0, or above the number of matching jobs) — a job beyond the cap isn't gone.

## `skipReposts` (type: `boolean`):

Drop jobs that are re-posts of a job seen in an earlier run (same title, company and location under a new ID). They're skipped before any detail fetch, so they cost nothing.

## `telegramToken` (type: `string`):

Bot token from @BotFather.

## `telegramChatId` (type: `string`):

Chat or channel ID, e.g. "-100123456789" or "@yourchannel".

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL.

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL.

## `whatsappPhoneNumberId` (type: `string`):

WhatsApp Cloud API phone number ID (Meta for Developers → WhatsApp → API setup).

## `whatsappAccessToken` (type: `string`):

WhatsApp Cloud API access token.

## `whatsappTo` (type: `string`):

Recipient phone number(s) in international format, comma-separated, e.g. "33612345678". Meta delivers free-form messages to numbers that messaged your business number in the last 24 hours.

## `webhookUrl` (type: `string`):

Any HTTPS endpoint. Receives a JSON POST with the matched records — works with n8n, Make and Zapier.

## `webhookHeaders` (type: `object`):

Extra headers for the webhook request, e.g. {"Authorization": "Bearer xyz"}.

## `notificationLimit` (type: `integer`):

How many records to include in each notification message.

## `notifyOnlyChanges` (type: `boolean`):

In incremental mode, send only NEW, UPDATED and REAPPEARED jobs to your channels (useful with 'Include unchanged records').

## `notionApiKey` (type: `string`):

Optional. Create an internal integration at notion.so/my-integrations, copy its Internal Integration Secret (starts with 'ntn\_'), then open the target database → ⋯ → Connections → and connect that integration. Without that last step Notion returns 'object_not_found'.

## `notionDatabaseId` (type: `string`):

Optional. Paste the database's URL or its 32-character ID. Every job becomes one page in that database. The database can start completely empty — the columns are created for you on the first run.

## `notionCreateProperties` (type: `boolean`):

Add any columns the target database is missing (with the right Notion type) on the first run. Turn this off to write only into columns you created yourself — fields with no matching column are then skipped.

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

Optional. Not needed for normal use — the actor works without a proxy. Enable it only if runs start getting refused.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

## Actor input object example

```json
{
  "query": "développeur",
  "location": "Paris",
  "maxResults": 25,
  "ignoreUrlFailures": true,
  "postedWithin": "any",
  "salaryFilter": "any",
  "superRecruiterOnly": false,
  "sortBy": "date",
  "includeDetails": true,
  "includeCompanyProfile": false,
  "descriptionFormat": "all",
  "compact": false,
  "excludeEmptyFields": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "notificationLimit": 5,
  "notifyOnlyChanges": false,
  "notionCreateProperties": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxRequestRetries": 3
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `allItems` (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 = {
    "query": "développeur",
    "location": "Paris"
};

// Run the Actor and wait for it to finish
const run = await client.actor("corvuslab/hellowork-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 = {
    "query": "développeur",
    "location": "Paris",
}

# Run the Actor and wait for it to finish
run = client.actor("corvuslab/hellowork-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 '{
  "query": "développeur",
  "location": "Paris"
}' |
apify call corvuslab/hellowork-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corvuslab/hellowork-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/8t43VSkqwrT4igiWJ/builds/JftZfFxuBGR2Oeskw/openapi.json
