# Indeed, Welcome to the Jungle, France Travail, Hellowork & more (`cycha/france-job-scraper`) Actor

French job listings from Indeed, Welcome to the Jungle, France Travail (Pôle emploi), Hellowork and Cadremploi in one run: full descriptions, contract, salary, remote, experience, deduplicated across sites. Only-new mode for daily job alerts. No login.

- **URL**: https://apify.com/cycha/france-job-scraper.md
- **Developed by:** [Ken Digital](https://apify.com/cycha) (community)
- **Categories:** Lead generation
- **Stats:** 54 total users, 4 monthly users, 99.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 job listings

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

## Indeed, Welcome to the Jungle, France Travail, Hellowork & Cadremploi Scraper

French job offers from **Indeed France**, **Welcome to the Jungle**, **France Travail** (ex Pôle emploi), **Hellowork** and **Cadremploi** (executive and manager jobs) in a single run, in a single format. Every row carries the full job description, contract type, salary as numbers, remote policy, experience, industry and posting date, and duplicates posted on several sites are removed. Turn on **Only new jobs** and schedule it for daily job alerts that never repeat an offer.

> **New name:** this actor is now `cycha/france-job-scraper` (it was `joyouscam35875/france-job-scraper` until 21 October 2026). If an API call or integration stopped working, update the name, or use the actor ID `RmzXYGyXnseoeZIet`, which never changes.

*Offres d'emploi Indeed, Welcome to the Jungle, France Travail, Hellowork et Cadremploi en une seule recherche : description complète, contrat, salaire, télétravail, expérience. Mode « nouvelles offres uniquement » pour des alertes quotidiennes.*

- **Five job sites, one schema.** Same fields whatever the source; `source` tells you where each offer came from.
- **Full descriptions included** at no extra cost.
- **Real filters:** city, region or département; date posted; CDI, CDD, intérim, stage, alternance, freelance; remote only; minimum salary.
- **Only new jobs** remembers what earlier runs delivered, so scheduled runs return and bill only fresh offers.
- **No login, no API key, no proxy to set up.** Only public pages and Indeed's public app search.

### Sample output

Five rows from a real search for `développeur python` (one per site). Each row also has the full description, remote policy, experience, industry, postcode and apply link.

| Site | Job | Company | Location | Contract | Salary | Posted |
|---|---|---|---|---|---|---|
| Welcome to the Jungle | Développeur Python | Visian | Courbevoie | CDI | €43k–63k / year | 2026-10-20 |
| France Travail | Lead Développeur Python H/F | Groupagora | Rennes | CDI | €40k–50k / year | 2026-10-19 |
| Hellowork | Développeur·se Python H/F | Scalian | Ollioules | CDI | €37k–42k / year | 2026-10-17 |
| Cadremploi | Développeur Python F/H | AddixWare | Marseille | CDI | €37k–44k / year | 2026-10-14 |
| Indeed | Développeur Python Senior – H/F | Storm Group | Paris | CDI | €50k–60k / year | 2026-10-22 |

### Quick start

```json
{
  "keywords": "développeur python\ndata engineer",
  "location": "Lyon",
  "datePosted": "pastWeek",
  "contractTypes": ["cdi"],
  "maxJobsPerSearch": 150
}
```

**Daily alert:** add `"onlyNewJobs": true`, save as a task, schedule it every morning, and connect Slack, email or Google Sheets from the task's Integrations tab.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string | required | One search per line. |
| `location` | string | all France | City (`Paris`, `Nantes`), region (`Île-de-France`, `Occitanie`) or département number (`69`, `33`). |
| `sources` | array | all five | `welcometothejungle`, `francetravail`, `hellowork`, `cadremploi`, `indeed`. |
| `datePosted` | string | `any` | `any`, `past24h`, `pastWeek`, `pastMonth`. |
| `contractTypes` | array | all | `cdi`, `cdd`, `interim`, `internship`, `apprenticeship`, `freelance`. |
| `remoteOnly` | boolean | false | Full, partial or occasional remote only. France Travail does not publish remote information, so its offers drop out. |
| `minSalary` | integer | | Minimum yearly salary in euros. Offers without a published salary are kept. |
| `maxJobsPerSearch` | integer | 200 | Per keyword, shared across the selected sites. `0` = no limit (about 1,000 per site). |
| `includeDetails` | boolean | true | Full description, experience, industry, salary and validity date. Included in the price. |
| `onlyNewJobs` | boolean | false | Return only offers not delivered by earlier runs of the same searches (one found by two searches is sent once). |

Earlier inputs (`maxResults`, `maxDaysOld`, `contractType`) still work, and rows keep the earlier `description` (first 500 characters) and `salary` (text) fields for existing integrations.

### Output

```json
{
  "jobId": "francetravail:7427450",
  "source": "francetravail",
  "url": "https://candidat.francetravail.fr/offres/recherche/detail/7427450",
  "title": "Ingénieur(e) Développeur(se) C++ / Python Embarqué - F/H",
  "company": "CTS Corporate",
  "location": "Paris 1er Arrondissement",
  "postalCode": "75001",
  "region": "Île-de-France",
  "remote": null,
  "contractType": "CDI",
  "contractTypeRaw": "CDI - Non renseigné",
  "salaryMin": 35000.0,
  "salaryMax": 40000.0,
  "salaryPeriod": "year",
  "salaryCurrency": "EUR",
  "salaryText": "Annuel de 35000.0 Euros à 40000.0 Euros",
  "experience": "2 An(s)",
  "industry": "Ingénierie,études techniques",
  "datePosted": "2026-09-26",
  "validThrough": "2027-09-26",
  "summary": "Au sein de notre société de conseil en ingénierie, nous acco...",
  "descriptionText": "Au sein de notre société de conseil en ingénierie, nous accompagnons les fleurons de la ha...",
  "descriptionHtml": "<p>Au sein de notre société de conseil en ingénierie, nous a...",
  "detailsStatus": "ok",
  "searchKeywords": "développeur python",
  "searchLocation": "Paris",
  "scrapedAt": "2026-09-26T10:00:00+00:00"
}
```

Welcome to the Jungle rows also carry `keyMissions`, `benefits`, `companySize`, `companyLogo` and `educationLevel`; Indeed rows carry `companySize` as the lower bound of Indeed's range ("51 to 200" gives 51). `contractType` is normalized to `CDI`, `CDD`, `Intérim`, `Stage`, `Alternance`, `Freelance` or `Autre`; `contractTypeRaw` keeps the site's own wording. `remote` is `full`, `partial`, `occasional`, `none` or `null` when the site does not say.

### Pricing

Pay per event: one `result` event per job row, full details included, plus a tiny actor-start fee. With **Only new jobs** on, a run with nothing new costs only the start fee.

### Use cases

- **Job alerts** for a role and city, delivered every morning to Slack, email or a sheet
- **Recruitment and sales intelligence:** who is hiring what, where, on which contracts and at what salary
- **Labour-market studies:** salary ranges, remote share and contract mix by role and region
- **Job boards and aggregators:** a deduplicated daily feed of French offers with full text

### Integrations

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("cycha/france-job-scraper").call(run_input={
    "keywords": "comptable",
    "location": "Île-de-France",
    "datePosted": "past24h",
    "onlyNewJobs": True,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["source"], job["datePosted"], job["company"], job["title"], job["url"])
```

Works with Make, Zapier, n8n, Google Sheets, schedules and webhooks, and as an MCP tool for AI agents.

### FAQ

**What about LinkedIn?** Use the [LinkedIn Jobs Scraper](https://apify.com/cycha/linkedin-jobs-scraper). Indeed France is included here since October 2026.

**Only need one site?** The [Welcome to the Jungle Scraper](https://apify.com/cycha/welcome-to-the-jungle-scraper) and the [France Travail Scraper](https://apify.com/cycha/france-travail-scraper) run this same code for one site at $1 per 1,000 jobs.

**What if my run has a short timeout?** Fetching full details takes time: about a minute per few hundred offers. When the run's timeout is too short for everything you asked, the actor stops shortly before it, keeps every offer already saved, and ends successfully with a message saying so. Offers whose details were cut off are not charged. With **Only new jobs** on, the next run continues where this one stopped.

**How are duplicates detected?** By normalized title, company and city: one employer's identical openings in different cities stay separate rows. When an offer is on several sites, the first site to return it wins.

**Why do some rows have no salary?** Many French offers do not publish one. `minSalary` never drops those.

**Is it legal?** The actor reads publicly visible job offers. You are responsible for how you use the data and for complying with each site's terms and the GDPR.

### Feedback

Missing a field or a site? Open an issue on the actor's **Issues** tab. If this scraper saved you time, a short review on the Store page helps other people find it.

### Related actors by the same developer

| Actor | What it does |
|---|---|
| [LinkedIn Jobs Scraper](https://apify.com/cycha/linkedin-jobs-scraper) | LinkedIn jobs with full descriptions and only-new mode |
| [Google News & RSS Scraper](https://apify.com/cycha/rss-news-aggregator) | Articles by keyword, language and country |
| [Google Trends Scraper](https://apify.com/cycha/google-trends-scraper) | Interest over time, related queries, regions |

# Actor input Schema

## `keywords` (type: `string`):

One search per line, e.g. 'comptable' on one line and 'développeur python' on the next.

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

City (Paris, Lyon, Nantes...), region (Île-de-France, Occitanie...) or département number (69, 33). Leave empty for all of France.

## `sources` (type: `array`):

Which job sites to search. All five by default.

## `datePosted` (type: `string`):

Only jobs posted within this window.

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

Leave empty for all.

## `remoteOnly` (type: `boolean`):

Only jobs offering full, partial or occasional remote work. France Travail does not publish remote information, so its offers are excluded when this is on.

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

Drops jobs whose published yearly salary is below this. Jobs without a published salary are kept.

## `maxJobsPerSearch` (type: `integer`):

Per keyword, shared across the selected sites. 0 = no limit (up to about 1,000 per site).

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

Open each offer for the full description, experience, industry, salary and validity date. Included in the price.

## `onlyNewJobs` (type: `boolean`):

Remember the jobs delivered by earlier runs of the same searches and return only jobs not delivered before, even when another search of the task found them. You only pay for new jobs.

## Actor input object example

```json
{
  "keywords": "développeur python",
  "location": "Paris",
  "sources": [
    "welcometothejungle",
    "francetravail",
    "hellowork",
    "cadremploi",
    "indeed"
  ],
  "datePosted": "any",
  "remoteOnly": false,
  "maxJobsPerSearch": 200,
  "includeDetails": true,
  "onlyNewJobs": false
}
```

# Actor output Schema

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

One row per job offer, same fields for every site.

# 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": "développeur python",
    "location": "Paris"
};

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

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

```

## MCP server setup

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