# HelloWork Jobs Scraper (`osamih/hellowork-jobs-scraper`) Actor

Scrape job offers from HelloWork.com (France's largest job board) by keyword, location and advanced filters. Outputs rich job data including salary, remote policy, company info and full HTML description.

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

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Jobs Scraper

Scrapes job offers from [HelloWork](https://www.hellowork.com), France's largest job board (800,000+ offers). Search by keyword and location, apply the same filters as the website (contract type, publication date, remote policy, company type, experience, salary), and get rich, structured job data — including the full HTML description, salary range, remote policy and company details.

### Features

- 🆓 **Free** — no rental fee and no per-result charge; you only pay your own Apify platform usage
- 📄 **39 structured fields per job** — full HTML description *and* a clean plain-text version, salary parsed into min/max/currency/period, remote policy, contract duration, company details, requirements, skills and tags
- 🎛️ **All the site's filters** — contract, publication date, remote (télétravail), distance, company type, experience level, job function, industry sector, full/part-time, CSR labels (RSE), super-recruiter badge, minimum salary — each verified against the live site
- 🔎 **Multiple searches per run** — one search per keyword, merged and de-duplicated by job id, with `maxItems` split evenly so a broad keyword cannot starve the others
- 🔗 **Direct search URLs** — paste any `recherche.html?...` URL from the website and every filter in it is respected
- 🛟 **Expired offers are never lost** — when a detail page is gone (HTTP 410), the search-card data is still saved and flagged `partial_data: true`
- ⚡ **HTTP-only crawling** — no browser, fast and cheap to run

### Input example

```json
{
    "keywords": ["développeur web", "data engineer"],
    "location": "Paris",
    "contractTypes": ["CDI"],
    "publishedSince": "7d",
    "remotePolicy": ["Complet", "Partiel"],
    "maxItems": 200
}
```

Or with a direct URL instead of keywords:

```json
{
    "startUrls": [{ "url": "https://www.hellowork.com/fr-fr/emploi/recherche.html?k=comptable&l=Lyon&c=CDI&d=w" }],
    "maxItems": 100
}
```

### Output example (abridged)

```json
{
    "job_id": "80817007",
    "job_title": "Comptable H/F",
    "link": "https://www.hellowork.com/fr-fr/emplois/80817007.html",
    "company": "Harry Hope",
    "company_id": "88047",
    "company_link": "https://www.hellowork.com/fr-fr/entreprises/harry-hope-88047.html",
    "company_logo": "https://f.hellowork.com/img/entreprises/160_160/197317.png",
    "company_type": "cabinet-recr",
    "location": "Lyon 3e - 69",
    "city": "Lyon",
    "postal_code": "69000",
    "department": "69",
    "region": "Auvergne-Rhône-Alpes",
    "country": "FR",
    "contract": "CDI",
    "employment_type": "temps plein",
    "salary": "35 000 - 40 000 € / an",
    "salary_min": 35000,
    "salary_max": 40000,
    "salary_currency": "EUR",
    "salary_period": "year",
    "remote": null,
    "experiences": ["Exp. 1 à 7 ans"],
    "educations": ["Bac +2"],
    "industries": ["Services aux Entreprises"],
    "skills": ["Établissement des déclarations fiscales", "Accompagnement du client"],
    "description": "<h2>Les missions du poste</h2><p>…</p>",
    "description_text": "Les missions du poste\n…",
    "list_tags": ["montagne", "cdi", "stable", "conseil", "junior"],
    "is_recruiting_firm": true,
    "published_at": "2026-07-01T01:07:28Z",
    "valid_through": "2026-07-31T01:07:28Z",
    "time": "il y a 2 jours",
    "reference": "30024685 EC-DCO-61435",
    "direct_apply": true,
    "source_query": "comptable",
    "extraction_date": "2026-07-03T12:00:00.000Z"
}
```

### Notes & limits

- **~2,010 offers max per search**: HelloWork stops serving results after ~67 pages per query. To collect more, split your run into several narrower searches (more specific keywords, filters, or locations) — the actor de-duplicates overlapping results automatically.
- **No geo coordinates**: HelloWork does not expose latitude/longitude anywhere in its job pages, so the output has no coordinate fields. Use `city` / `postal_code` / `region` for geocoding.
- **`maxItems` is split evenly across searches**: with several keywords (or start URLs), each search gets `maxItems / number of searches` so one broad keyword cannot consume the whole budget. A search that runs out of offers early simply returns fewer items.
- **`partial_data: true`** marks jobs whose detail page was unavailable (expired offers); those items only contain the search-card fields.

### Proxy & keeping runs cheap

The actor defaults to Apify **residential** proxies — the lowest chance of being blocked. Country is left at "Anywhere"; HelloWork does not require French IPs.

Residential traffic is billed **per GB on your own account**, which adds up on large runs and can eat a free plan's allowance quickly. For bulk scraping, switch to datacenter proxies:

```json
{
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["DATACENTER"] }
}
```

Two more ways to cut cost:

- **Turn off detail pages.** With `fetchJobDetails: false` the actor reads only search pages, which carry ~30 offers each — about 1 request per 30 jobs instead of 31. You lose the description, structured salary, requirements and tags, but keep title, company, location, contract, salary text and link.
- **Lower `maxConcurrency`** (default 10) if you are hitting proxy errors; the crawler retries automatically, but fewer parallel requests means fewer retries to pay for.

### Disclaimer

This is an **unofficial** scraper. It is not affiliated with, endorsed by, or sponsored by HelloWork or its operators. "HelloWork" is a trademark of its respective owner and is referenced here only to describe the public website this actor collects data from.

Job listings can contain personal data. You are responsible for using the output lawfully, including under the GDPR, and in line with HelloWork's terms of use.

### Running locally

```bash
npm install
apify run --purge   # reads storage/key_value_stores/default/INPUT.json
```

### Deployment

```bash
apify login
apify push
```

# Actor input Schema

## `keywords` (type: `array`):

Job titles or search terms. One HelloWork search is run per keyword (e.g. <code>développeur web</code>, <code>comptable</code>, <code>data analyst</code>). Results from all searches are merged and de-duplicated.

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

City, department or region in France (e.g. <code>Paris</code>, <code>Lyon</code>, <code>Bretagne</code>). Leave empty to search all of France.

## `distanceKm` (type: `string`):

Maximum radius around the location. Only applies when a location is set. "Site default" lets HelloWork decide (~20 km).

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

Filter by contract type. Leave empty for all contract types.

## `publishedSince` (type: `string`):

Only include offers published within this period.

## `remotePolicy` (type: `array`):

Filter by télétravail policy. Leave empty for all.

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

Filter by the type of employer posting the offer. Leave empty for all.

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

Filter by required experience. Leave empty for all.

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

Filter by job function / domain (métier). Leave empty for all.

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

Filter by the employer's industry sector. Leave empty for all.

## `workTime` (type: `array`):

Filter by full-time / part-time. Leave empty for all.

## `rseLabels` (type: `array`):

Filter by the employer's CSR / social-responsibility labels (labels & engagements RSE). Leave empty for all.

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

Only include offers from companies with HelloWork's "super recruteur" badge (responsive, transparent recruiters).

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

Only include offers with an annual salary of at least this amount in EUR (e.g. <code>35000</code>).

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

Only include offers where the salary is specified.

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

Sort results by relevance or publication date. Use "date" together with "Published since" for monitoring new offers.

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

Maximum number of job offers to scrape across all searches. Note: HelloWork caps each search at ~67 pages (≈2,010 offers) — to collect more, use several narrower keywords or filters.

## `fetchJobDetails` (type: `boolean`):

Visit each job's detail page to get the full HTML description, exact salary range, remote policy, education/experience requirements, tags and company info. Turn off for a much faster run that only returns the basic data from search result cards.

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

Instead of (or in addition to) keywords, paste full HelloWork search URLs, e.g. <code>https://www.hellowork.com/fr-fr/emploi/recherche.html?k=data+engineer\&l=Paris\&c=CDI</code>. All filters in the URL are respected.

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

Proxies to use. Defaults to Apify residential proxies (lowest chance of blocking). Note that residential traffic is billed per GB — switch to datacenter proxies for cheaper large-volume runs.

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

Maximum number of pages loaded in parallel. Lower this if you see rate-limiting errors.

## Actor input object example

```json
{
  "keywords": [
    "comptable"
  ],
  "location": "Lyon",
  "distanceKm": "all",
  "contractTypes": [],
  "publishedSince": "all",
  "remotePolicy": [],
  "companyTypes": [],
  "experienceLevels": [],
  "jobFunctions": [],
  "sectors": [],
  "workTime": [],
  "rseLabels": [],
  "superRecruiterOnly": false,
  "salaryOnly": false,
  "sortBy": "relevance",
  "maxItems": 500,
  "fetchJobDetails": true,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 10
}
```

# 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 = {
    "keywords": [
        "comptable"
    ],
    "location": "Lyon",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("osamih/hellowork-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 = {
    "keywords": ["comptable"],
    "location": "Lyon",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("osamih/hellowork-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "comptable"
  ],
  "location": "Lyon",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call osamih/hellowork-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=osamih/hellowork-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/q1DjIwVFFRt8sjeZK/builds/FVBa47KuKfabAFXWH/openapi.json
