# HelloWork Scraper - French Jobs, Salaries & Companies (`scrapewise/hellowork-scraper`) Actor

Scrape hellowork.com jobs in France by keyword, city, radius, contract (CDI, CDD, interim, internship), remote work, experience, date and minimum salary: title, company, salary range, skills, education, address, full description and profile. Schedule it with onlyNew. Error rows are free.

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

## Pricing

from $0.85 / 1,000 job delivereds

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?

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 Scraper: French jobs with salaries, skills, companies and full descriptions

HelloWork Scraper collects **job offers from hellowork.com**, one of the largest job boards in France, without an
account or cookies. Search by keyword and city with the same filters the site offers (contract type,
remote work, experience, working time, date and minimum salary), or paste job and search links. Each job comes back as
one clean row: title, company, city, region and postal code, contract, salary range in numbers, required experience
and education, skills, sector, publication and expiry dates, the full description and the candidate profile.

It is used to monitor the French job market by role or region, to feed job alert and aggregator sites, to benchmark
salaries, to find companies that are hiring (lead generation for recruiters, staffing and training agencies), and to
build datasets for HR analytics and AI.

### At a glance

| What | Price |
|---|---|
| Job delivered | **US$ 1.00 per 1,000 jobs** (US$ 0.001 each) |
| Run start | US$ 0.005 per run |

- 500 jobs with full details = **US$ 0.505**.
- Error rows, duplicates and jobs skipped by `onlyNew` are never charged. `maxItems` is a hard cap, and a spending
  limit set on the run stops it cleanly with everything delivered so far.
- About 150 jobs with full details in 12 seconds in our tests (one search, one job page per job).

### Quick start

```json
{
  "searchQueries": ["data analyst"],
  "location": "Paris",
  "maxItems": 50
}
```

Permanent contracts with partial remote work, published in the last week, at least 45,000 EUR a year, newest first:

```json
{
  "searchQueries": ["software engineer", "devops"],
  "location": "Lyon",
  "radiusKm": 20,
  "contractTypes": ["CDI"],
  "remoteWork": ["Partiel"],
  "postedWithin": "w",
  "minYearlySalary": 45000,
  "sortBy": "date",
  "maxItems": 200
}
```

Links work too: job pages, search pages copied from the address bar (every filter in the link is kept) and category
pages:

```json
{
  "startUrls": [
    "https://www.hellowork.com/fr-fr/emplois/83247207.html",
    "https://www.hellowork.com/fr-fr/emploi/recherche.html?k=accountant&l=Bordeaux&c=CDI",
    "https://www.hellowork.com/fr-fr/emploi/domaine_achat.html"
  ],
  "maxItems": 100
}
```

An empty input runs the example search, so a first click on Start always returns data.

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Keywords or job titles, one per line, in French or English. Each one is a separate search. Empty with a `location` = every job of that place. |
| `location` | City, department or region in France (Paris, Lyon, Gironde, Bretagne...). Empty = all of France. |
| `radiusKm` | Distance around the city in km (the site offers 10, 20, 30, 50 and 100). |
| `contractTypes` | `CDI` (permanent), `CDD` (fixed term), `Travail_temp` (interim), `Stage` (internship), `Alternance` (apprenticeship), `Independant`, `Franchise`, `Associe`, `Fonctionnaire` (civil service), `Freelance`, `Stage_de_lycee`. |
| `postedWithin` | `all`, `h` (24 hours), `d` (3 days), `w` (1 week), `m` (1 month). |
| `experienceLevels` | `deb` (beginners welcome), `0-1y`, `2-3y`, `4-5y`, `6-10y`, `gt10y`, `unknown`. |
| `remoteWork` | `Complet` (full remote), `Partiel` (hybrid), `Occasionnel`, `Pas_teletravail` (no remote). |
| `workingTimes` | `ft` (full time), `pt` (part time), `np` (not specified). |
| `minYearlySalary` | Minimum gross yearly salary in euros, up to 100000. |
| `sortBy` | `relevance` or `date`. |
| `startUrls` | Job links, search links and category links from hellowork.com. |
| `includeDetails` | On by default: opens each job page for the description, profile, salary numbers, skills, education, address and dates. Off: only the search card fields, faster. |
| `maxItems` | Cap for the whole run, across all searches (default 50; 0 = no cap). |
| `onlyNew` | For schedules: delivers only jobs not delivered in earlier runs of the same search. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

Common names from other job tools are accepted too: `keyword`, `query`, `searchTerms`, `urls`, `city`, `where`,
`maxResults`, `limit`, `jobType`, `datePosted`, `remote` (true = full remote).

### Output

| Field | What it is |
|---|---|
| `jobId`, `url` | HelloWork job id and link |
| `title` | Job title as published |
| `companyName`, `companyId`, `companyHelloworkUrl`, `companyLogo`, `companyCoverImage` | Hiring company and its HelloWork page |
| `location`, `city`, `region`, `postalCode`, `country` | Where the job is |
| `contractType` | Contract as shown on the card (CDI, CDD, Stage, Alternance, Intérim...) |
| `employmentType` | Full time, part time, internship, temporary... |
| `remoteAllowed`, `tags` | Remote work flag and the card tags (for example "Télétravail partiel") |
| `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | Salary as shown and in numbers (`yearly`, `monthly`, `hourly`) |
| `minExperienceMonths`, `educationLevels` | Required experience in months and education level |
| `skills`, `industries`, `category` | Skills listed by the recruiter, company sector and job category |
| `isSuperRecruiter`, `hasApplicationTracking`, `applyType`, `directApply` | Recruiter badges and how the application works |
| `reference` | Recruiter's job reference |
| `postedAgo`, `publishedAt`, `validThrough` | Relative date on the card, publication date and expiry date (UTC) |
| `description`, `descriptionHtml` | Full job description as text and HTML |
| `profile`, `profileHtml` | The "profil recherché" section (who the company is looking for) |
| `sourceQuery`, `scrapedAt` | The search or link that found the job, and when |

One real row (description and profile shortened):

```json
{
  "type": "job",
  "jobId": "83247207",
  "url": "https://www.hellowork.com/fr-fr/emplois/83247207.html",
  "title": "Développeur - Développeuse Flutter H/F",
  "companyName": "Alpee",
  "companyId": "93511",
  "companyHelloworkUrl": "https://www.hellowork.com/fr-fr/entreprises/alpee-93511.html",
  "location": "Chambéry - 73",
  "city": "Chambéry",
  "region": "Auvergne-Rhône-Alpes",
  "postalCode": "73000",
  "country": "FR",
  "contractType": "CDI",
  "employmentType": ["Full time"],
  "remoteAllowed": true,
  "tags": ["Télétravail partiel"],
  "salaryText": "45 000 - 60 000 € / an",
  "salaryMin": 45000,
  "salaryMax": 60000,
  "salaryCurrency": "EUR",
  "salaryPeriod": "yearly",
  "minExperienceMonths": 12,
  "educationLevels": ["postgraduate degree"],
  "skills": ["Force de proposition", "Intelligence artificielle", "Firebase", "Autonomie", "Flutter"],
  "industries": ["Secteur informatique", "ESN"],
  "category": "Informatique",
  "hasApplicationTracking": true,
  "applyType": "ATS",
  "directApply": true,
  "reference": "4326656/30209705 DF/73C",
  "postedAgo": "il y a 6 jours",
  "publishedAt": "2026-10-11T00:09:45Z",
  "validThrough": "2026-11-10T00:09:45Z",
  "description": "Les missions du poste\n\nJeune société de conseil et d'ingénierie, ALPEE accompagne des entreprises industrielles du bassin Alpin...",
  "profile": "- Compétences techniques: Flutter : Firebase\n- Compétences approuvées sur les tests unitaires...",
  "sourceQuery": "developpeur"
}
```

Text comes in the language of the offer (almost always French). Emails and phone numbers inside descriptions are
replaced with `[contact removed]`; no recruiter names are collected.

### Errors you may see

Every error is a row with `errorCode` and is never charged:

| errorCode | Meaning |
|---|---|
| `INVALID_INPUT` | A filter has a value the site does not offer (the message lists the valid ones) |
| `INVALID_URL` | Not a hellowork.com job, search or category link |
| `NOT_FOUND` | The job is no longer online (expired or filled) or the page does not exist |
| `NO_RESULTS` | The search and filters return no job; try fewer filters |
| `NO_DATA` | The job page opened without job data |
| `BLOCKED` | HelloWork refused every attempt; run it again in a few minutes |
| `NOT_REACHED` | The run time, `maxItems` or the cost guard arrived before this job link |

### Integrations, scheduling and AI agents

- **Schedule** a daily run with `onlyNew: true` and `sortBy: date` in
  [Apify schedules](https://docs.apify.com/platform/schedules) to get only the jobs published since the last run.
- **Export** as JSON, CSV, Excel or XML, or read the dataset from the [Apify API](https://docs.apify.com/api/v2).
- **Connect** it to Make, n8n, Zapier, Google Sheets or Slack through
  [Apify integrations](https://docs.apify.com/platform/integrations), for example a new row in a sheet for every new
  CDI in your city.
- **AI agents:** call it as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp)
  in Claude, ChatGPT, Cursor or any MCP client, for example "find 100 data engineer jobs in Paris published this week
  and give me the median salary and the top 10 skills".

### FAQ

**Do I need a HelloWork account?** No. Everything comes from public pages, without login or cookies.

**How many jobs can one search return?** As many as the site lists for it, page after page (30 per page). Set
`maxItems` to 0 to get them all; a broad keyword across France can have tens of thousands.

**Why is the salary empty on some jobs?** Many French offers do not publish a salary. When the recruiter gives one,
you get the text and the numbers with the period (yearly, monthly or hourly).

**Can I get only the jobs published today?** Yes: `postedWithin: "h"` for the last 24 hours, or a schedule with
`onlyNew` to receive each job once.

**Does it work for jobs outside France?** HelloWork lists jobs in France (including overseas departments). Use other
job boards for other countries.

**Is it legal?** The Actor reads public job pages only and returns no personal data of candidates or recruiters. You
are responsible for how you use the data under the laws that apply to you (including the GDPR).

**Something broke or a field is missing?** Open an issue on the Actor page; issues are answered within a day.

### Limitations

- `includeDetails: false` returns only what the search card shows (title, company, location, contract, salary text,
  tags, relative date); numbers, skills, address and description need the job page.
- About 1 job in 40 (mostly offers from training centres) has no structured data on its page; those rows still get
  the description, profile, skills, reference and publication date from the page text, without the address fields.
- Company profiles and company reviews are not collected yet.
- Values are the ones HelloWork shows at the moment of the run.

### Changelog

- **16 Oct 2026:** first version: keyword and link search with every site filter, full job details from the job
  page, onlyNew for schedules, free error rows.

# Actor input Schema

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

Job titles or keywords, one per line, in French or English, for example data analyst, comptable or infirmier. Each keyword is one search. Leave empty to list every job of the location, or when you paste links below.

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

City, department or region in France, for example Paris, Lyon, Gironde or Bretagne. Empty = all of France.

## `radiusKm` (type: `integer`):

Distance around a city, in km (the site offers 10, 20, 30, 50 and 100). Empty = the site default.

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

Keep only these contract types. Empty = all.

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

Only jobs published in this period.

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

Required experience. Empty = all.

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

Remote work policy of the job. Empty = all.

## `workingTimes` (type: `array`):

Full time or part time. Empty = both.

## `minYearlySalary` (type: `integer`):

Only jobs whose salary reaches at least this gross yearly amount in euros, for example 45000 (the site goes up to 100000).

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

Order of the results, same options as the site. onlyNew switches Relevance to Most recent.

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

Optional: job links (https://www.hellowork.com/fr-fr/emplois/12345678.html) or search and category links copied from the address bar after setting filters on the site. Search links keep every filter they carry.

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

On: opens each job page for the full description, candidate profile, salary numbers, skills, education, address, publication and expiry dates. Off: faster, the row has the search card fields (title, company, location, contract, salary text, tags).

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

Hard cap for the whole run, across all searches. 0 = no cap.

## `onlyNew` (type: `boolean`):

On: remembers the jobs delivered in earlier runs of the same search (in your account) and delivers only jobs not seen before. Skipped jobs are free.

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

Apify datacenter proxy by default.

## Actor input object example

```json
{
  "searchQueries": [
    "data analyst"
  ],
  "location": "Paris",
  "postedWithin": "all",
  "sortBy": "relevance",
  "includeDetails": true,
  "maxItems": 50,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (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 = {
    "searchQueries": [
        "data analyst"
    ],
    "location": "Paris",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/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 = {
    "searchQueries": ["data analyst"],
    "location": "Paris",
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/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 '{
  "searchQueries": [
    "data analyst"
  ],
  "location": "Paris",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/hellowork-scraper --silent --output-dataset

```

## MCP server setup

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