# HelloWork France Jobs Scraper (`automation-lab/hellowork-france-jobs-scraper`) Actor

Search HelloWork France by keyword and location and export public vacancies with employers, contracts, salaries, dates, skills, descriptions, and source URLs.

- **URL**: https://apify.com/automation-lab/hellowork-france-jobs-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## HelloWork France Jobs Scraper

Turn public **HelloWork jobs** search results into a structured French vacancy dataset.
Search by role and location, follow public job pages, and export stable vacancy IDs,
titles, employers, locations, contract and salary fields when shown, dates, skills,
plain-text descriptions, and canonical source URLs.

The Actor is designed for repeatable recruiting research and French labor-market
monitoring. It uses HelloWork's public server-rendered pages and does not require a
HelloWork account, browser automation, or an automatic paid proxy fallback.

### What does this Actor do?

1. Builds a HelloWork search from a keyword and optional French location, or accepts
   supplied HelloWork search/job URLs.
2. Paginates public search results up to the configured page limit.
3. Deduplicates vacancies by their stable HelloWork job URL.
4. Opens each public vacancy and reads its structured `JobPosting` data.
5. Applies keyword and location filters to direct job URLs too.
6. Saves one typed record per accepted vacancy to the default Apify dataset.

This makes the output suitable for spreadsheets, databases, scheduled comparisons,
recruiting pipelines, and labor-market dashboards.

### Who is it for?

- **Recruiters** building a current shortlist of vacancies by role and city.
- **Talent intelligence teams** comparing employers, contract types, and skills.
- **Labor-market analysts** tracking French hiring demand by region.
- **Job-board operators** collecting source-attributed public vacancy records.
- **Data engineers** feeding normalized HelloWork France data into warehouses.
- **Researchers** studying salary and skill signals where employers publish them.

This Actor focuses on public HelloWork France vacancies. For official France Travail
vacancies, use the related France Travail Actor listed below instead of assuming the
two sources contain the same jobs.

### Why use it?

- Search and detail extraction are combined in one run.
- Stable vacancy IDs make scheduled-run comparisons straightforward.
- Full descriptions are converted from HTML to plain text.
- Salary values retain currency and period instead of becoming an ambiguous string.
- Missing optional source fields remain `null`; they are not invented.
- Every output row keeps its canonical HelloWork URL for auditability.
- Direct URLs and discovered URLs use the same optional filters.
- Conservative limits and bounded retries avoid uncontrolled crawling.

### What HelloWork data is extracted?

| Field | Meaning |
| --- | --- |
| `jobId` | Stable numeric HelloWork vacancy ID |
| `title` | Published vacancy title |
| `employer` | Hiring organization, or `null` |
| `location` | Locality, or `null` |
| `region` | French region, or `null` |
| `postalCode` | Published postal code, or `null` |
| `country` | Source country code, usually `FR` |
| `contractType` | Structured employment type, or `null` |
| `salaryMin` / `salaryMax` | Numeric bounds when shown |
| `salaryCurrency` | Salary currency, such as `EUR` |
| `salaryPeriod` | Salary unit, such as `YEAR` |
| `datePosted` | Source publication timestamp |
| `validThrough` | Source validity timestamp when published |
| `description` | Plain-text vacancy description |
| `skills` | Structured skill names exposed by the source |
| `industry` | Industry when available |
| `category` | HelloWork occupational category |
| `employerUrl` | Public HelloWork employer page when available |
| `url` | Canonical public vacancy URL |
| `searchKeyword` | Keyword supplied to this run, or `null` |
| `searchLocation` | Location supplied to this run, or `null` |
| `scrapedAt` | ISO timestamp when the record was collected |

### Getting started

1. Open the Actor in Apify Console.
2. Enter a role or skill in **Job keyword**, for example `développeur`.
3. Optionally enter a city, department, or region, for example `Paris`.
4. Keep **Maximum jobs** small for your first run.
5. Set **Maximum search pages** to bound discovery work.
6. Click **Start**.
7. Open the Dataset tab to preview or export JSON, CSV, or Excel.

A useful first input is:

```json
{
  "keyword": "développeur",
  "location": "Paris",
  "maxItems": 10,
  "maxPages": 2
}
```

### Input parameters

#### `keyword`

Optional when `startUrls` is supplied. A role, skill, or phrase to search for.
At least `keyword` or one start URL is required.

#### `location`

Optional French city, department, or region. Examples include `Paris`, `Lyon`, and
`Bretagne`. With a direct job URL, the returned location must still match this filter.

#### `startUrls`

Optional list of public HelloWork URLs. Supported URL shapes are:

- `https://www.hellowork.com/fr-fr/emploi/recherche.html?...`
- `https://www.hellowork.com/fr-fr/emplois/<numeric-id>.html`

Other hosts and paths fail closed. A search URL preserves its existing source filters;
`maxPages` controls how many pages are inspected.

#### `maxItems`

Maximum accepted records, from 1 to 1,000. Default: 20.

#### `maxPages`

Maximum pages per search URL, from 1 to 50. Default: 10.
This is a work bound, not a guarantee that every page contains matching vacancies.

### Output example

The following shape comes from a real public HelloWork job page; the long description
is shortened here only for readability:

```json
{
  "jobId": "81400027",
  "title": "Développeur Applicatif - Analyste Développeur H/F",
  "employer": "Havana IT & Apps",
  "location": "Paris",
  "region": "Île-de-France",
  "postalCode": "75000",
  "country": "FR",
  "contractType": "FULL_TIME",
  "salaryMin": 40000,
  "salaryMax": 55000,
  "salaryCurrency": "EUR",
  "salaryPeriod": "YEAR",
  "datePosted": "2026-08-17T00:06:36Z",
  "validThrough": "2026-09-16T00:06:36Z",
  "description": "Les missions du poste Groupe Havana...",
  "skills": ["Transact-SQL", "HTML", "SQL", "Web services"],
  "industry": null,
  "category": "Informatique",
  "employerUrl": "https://www.hellowork.com/fr-fr/entreprises/havana-it-et-apps-83662.html",
  "url": "https://www.hellowork.com/fr-fr/emplois/81400027.html",
  "searchKeyword": "développeur",
  "searchLocation": "Paris",
  "scrapedAt": "2026-08-22T20:05:20.129Z"
}
```

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

Pricing uses one `start` event per run plus one `item` event for each saved vacancy.
The current BRONZE reference price is **$0.005 per run** and **$0.0008 per job**;
higher usage tiers receive lower per-job prices automatically.

Illustrative BRONZE totals:

| Saved jobs | Estimated Actor charge |
| ---: | ---: |
| 10 | $0.005 + (10 × $0.0008) = 0.013 USD |
| 100 | $0.005 + (100 × $0.0008) = 0.085 USD |
| 1,000 | $0.005 + (1,000 × $0.0008) = 0.805 USD |

These examples describe Actor event charges, not third-party infrastructure or storage
fees. A run that finds fewer matching jobs emits and charges fewer item events.

### Recurring vacancy monitoring

Use stable `jobId` values as the comparison key between scheduled runs:

1. Save each run's dataset to your database or cloud storage.
2. Schedule the same keyword, location, and limits daily or weekly.
3. Compare current IDs with the previous run.
4. Treat new IDs as newly observed vacancies.
5. Compare selected fields to detect changed descriptions, salary, or validity dates.
6. Mark IDs absent from later snapshots according to your own expiry policy.

The Actor returns snapshots; it does not persist history or send alerts itself.
Apify schedules and webhooks can trigger your downstream comparison workflow.

### Spreadsheet and data-pipeline exports

The default dataset supports Apify's standard export formats. Typical patterns include:

- download CSV or Excel for an analyst;
- send JSON rows to a warehouse after each scheduled run;
- trigger a webhook when a run succeeds;
- connect Make, Zapier, or another integration to the dataset;
- use `jobId` as an upsert key and `scrapedAt` as observation time.

Keep `url` in downstream systems so analysts can inspect the original public vacancy.

### API usage with cURL

Set `APIFY_TOKEN` in your environment and run:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~hellowork-france-jobs-scraper/runs?token=$APIFY_TOKEN&waitForFinish=120" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"comptable","location":"Lyon","maxItems":20,"maxPages":3}'
```

Read the resulting default dataset using the `defaultDatasetId` returned by the run.
Avoid placing long-lived tokens directly in source code or shared notebooks.

### API usage with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/hellowork-france-jobs-scraper').call({
  keyword: 'développeur',
  location: 'Paris',
  maxItems: 50,
  maxPages: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map(({ jobId, title, employer }) => ({ jobId, title, employer })));
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/hellowork-france-jobs-scraper").call(run_input={
    "keyword": "infirmier",
    "location": "Bordeaux",
    "maxItems": 25,
    "maxPages": 3,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
for item in items:
    print(item["jobId"], item["title"], item.get("employer"))
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/hellowork-france-jobs-scraper"
```

#### Claude Desktop

Add this server to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/hellowork-france-jobs-scraper"
    }
  }
}
```

#### Cursor

Add the same `mcpServers.apify.url` value in Cursor's MCP settings.

#### VS Code

Add the same HTTP MCP server URL through VS Code's MCP server configuration.

Example prompts:

- “Search HelloWork for 20 data engineer jobs in Paris and summarize employers.”
- “Extract this public HelloWork vacancy URL and return its salary and skills.”
- “Run the Lyon accounting-job monitor and give me the resulting dataset link.”

### Limits and source behavior

- The Actor supports public HelloWork France search and vacancy pages only.
- HelloWork can change its HTML or structured data without notice.
- Optional fields such as salary, industry, skills, and validity date may be absent.
- `maxItems` limits saved matches, while `maxPages` limits discovery work.
- Search ranking and available vacancies can change between otherwise identical runs.
- Results reflect the source at collection time; they are not a historical archive.
- No login-only application data, candidate data, or private employer data is collected.
- No automatic browser or paid proxy fallback is enabled.

### Failure and retry behavior

Transient network, rate-limit, and server responses are retried up to three times with
bounded backoff. Deterministic unsupported URLs and non-retryable client errors fail
immediately. A malformed individual job is skipped and logged; if every discovered
job fails extraction, the run fails rather than silently returning a misleading empty
success.

An empty dataset can be valid when the source has no vacancies matching the requested
scope. Check the run log and repeat the same search in a browser before increasing
limits.

### Responsible use and legality

This Actor accesses public vacancy pages. You are responsible for ensuring that your
use complies with HelloWork's terms, applicable law, database rights, employment law,
and privacy obligations. Collect only the data you need, respect reasonable schedules,
and avoid republishing descriptions or employer content without the necessary rights.

Do not use the output for unlawful discrimination, spam, impersonation, or decisions
that require human review. Honor deletion and correction obligations in downstream
systems. This documentation is operational guidance, not legal advice.

### Troubleshooting

#### Why is my dataset empty?

Confirm the keyword and location currently return public results on HelloWork. Try a
broader keyword, remove the location, or supply a known public search URL. Empty natural
results are not replaced with unrelated vacancies.

#### Why is a salary `null`?

HelloWork does not show structured salary values for every vacancy. The Actor preserves
that absence instead of estimating compensation.

#### Why did my start URL fail?

Only the supported HelloWork hostname and public search/job paths are accepted. Remove
tracking redirects and use the canonical `www.hellowork.com/fr-fr/...` URL.

#### Why did the run save fewer jobs than `maxItems`?

`maxItems` is a ceiling. The source may contain fewer matches, filters may exclude
direct URLs, or `maxPages` may stop discovery before that ceiling is reached.

#### Can I search several role/location pairs at once?

Use separate Actor runs or provide multiple pre-filtered HelloWork search URLs. Separate
runs are easier to schedule, compare, and attribute to one monitoring scope.

#### Does this Actor apply to jobs?

No. It extracts public vacancy data only. It does not authenticate, upload résumés,
submit applications, contact employers, or bypass user interaction.

### Related Automation Lab actors

- [France Travail Jobs Scraper](https://apify.com/automation-lab/france-travail-jobs-scraper)
  for official France Travail vacancy data.
- [Welcome to the Jungle Jobs Scraper](https://apify.com/automation-lab/welcome-to-the-jungle-jobs-scraper)
  for a separate French recruiting source.
- [Company Career Page Jobs Scraper](https://apify.com/automation-lab/company-career-page-jobs-scraper)
  for supplied employer career pages rather than a HelloWork search.

Each source has a different inventory and contract. Keep source attribution in any
combined feed and deduplicate using your own cross-source rules.

### FAQ

**Does the Actor require a HelloWork account?**\
No. It uses supported public search and vacancy pages.

**Can I export to CSV or Excel?**\
Yes. Use the standard export controls on the default Apify dataset.

**Are descriptions included in the same item charge?**\
Yes. A saved vacancy is one `item` event; descriptions do not create a separate event.

**Can I schedule it?**\
Yes. Create an Apify schedule with a stable input, then compare datasets downstream.

**Does it guarantee complete HelloWork coverage?**\
No. Coverage is bounded by your inputs, current public source results, and configured
page/item limits.

**What should I use as a database key?**\
Use `jobId` within the HelloWork source namespace. Preserve `url` and `scrapedAt` for
traceability.

# Actor input Schema

## `keyword` (type: `string`):

Role, skill, or phrase to search for, such as développeur, comptable, or infirmier.

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

French city, department, or region, such as Paris, Lyon, or Bretagne.

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

Optional HelloWork search-result or individual job URLs. Filters above are also applied to supplied job URLs.

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

Maximum number of matching job records to save.

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

Maximum search-result pages to inspect per search URL. Lower values make monitoring runs faster.

## Actor input object example

```json
{
  "keyword": "développeur",
  "location": "Paris",
  "startUrls": [],
  "maxItems": 20,
  "maxPages": 10
}
```

# Actor output Schema

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

Default dataset view containing vacancy identity, employer, location, contract, salary, dates, skills, description metadata, and source links.

# 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 = {
    "keyword": "développeur",
    "location": "Paris",
    "startUrls": [],
    "maxItems": 20,
    "maxPages": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/hellowork-france-jobs-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 = {
    "keyword": "développeur",
    "location": "Paris",
    "startUrls": [],
    "maxItems": 20,
    "maxPages": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/hellowork-france-jobs-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 '{
  "keyword": "développeur",
  "location": "Paris",
  "startUrls": [],
  "maxItems": 20,
  "maxPages": 10
}' |
apify call automation-lab/hellowork-france-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/hellowork-france-jobs-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/nfanm7tryABb59IZy/builds/lk9f3ygLINW3IABnv/openapi.json
