# France Travail Scraper — Scrape Job Offers from Pôle Emploi (`apikiy/france-travail-scraper`) Actor

An [Apify actor](https://apify.com/) that scrapes job listings from [France Travail](https://candidat.francetravail.fr/) (formerly Pôle Emploi) using Playwright

- **URL**: https://apify.com/apikiy/france-travail-scraper.md
- **Developed by:** [Julien ApiKiy](https://apify.com/apikiy) (community)
- **Categories:** Jobs
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 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/platform/actors/running/actors-in-store#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

## France Travail Job Scraper

An [Apify actor](https://apify.com/) that scrapes job listings from [France Travail](https://candidat.francetravail.fr/) (formerly Pôle Emploi) using Playwright with anti-detection measures.

### Features

- 🔍 Search jobs by keyword, location, and contract type
- 📄 Multi-page pagination with configurable depth
- 🛡️ Anti-detection: random user agents, delays, webdriver override
- 💰 Optional detail page visits for salary and full description extraction
- 🇫🇷 French market focus — defaults to all of France
- 📊 Deduplication across pages and queries
- ⚙️ Configurable concurrency, delays, and result limits

### Usage

#### On Apify Platform

1. Go to the actor's page on Apify Console
2. Set the input — at minimum provide `searchQueries`:

```json
{
  "searchQueries": ["développeur react", "ingénieur python"],
  "locations": ["Paris", "Lyon"],
  "contractTypes": ["CDI"],
  "maxResults": 50,
  "maxPages": 5,
  "visitDetails": false
}
```

3. Click **Start** and wait for results in the dataset.

#### Run Locally

```bash
## Install dependencies
npm install

## Run with Apify local APIFIFY_TOKEN
APIFY_TOKEN=your_token npm start

## Or provide input via stdin
echo '{"searchQueries": ["développeur web"], "maxResults": 10}' | npm start
```

#### Run via Docker

```bash
docker build -t france-travail-scraper .
docker run -e APIFY_TOKEN=your_token france-travail-scraper
```

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `searchQueries` | `string[]` | *required* | Job titles, keywords, or skills (e.g., `"comptable"`, `"infirmier"`) |
| `locations` | `string[]` | `[]` (all France) | Cities, departments, or regions (e.g., `"Paris"`, `"75"`) |
| `contractTypes` | `string[]` | `[]` (all) | Filter: `CDI`, `CDD`, `Interimaire`, `Stage`, `Apprentissage` |
| `maxResults` | `number` | `20` | Maximum total job listings to collect (1–200) |
| `maxPages` | `number` | `5` | Max search result pages per query (1–20) |
| `visitDetails` | `boolean` | `false` | Visit each job's detail page for salary/full description |
| `delayMin` | `number` | `2000` | Minimum delay between requests (ms) |
| `delayMax` | `number` | `5000` | Maximum delay between requests (ms) |
| `maxConcurrency` | `number` | `1` | Concurrent browser pages (keep ≤2 to avoid detection) |
| `debugMode` | `boolean` | `false` | Enable verbose logging |

### Output

Each job listing contains:

```json
{
  "jobId": "210SSZN",
  "title": "Développeur Web Full Stack",
  "company": "ACME Corp",
  "location": "75 - Paris",
  "contractType": "CDI",
  "salary": "Annuel de 35000.0 Euros à 40000.0 Euros",
  "publicationDate": "Publié hier",
  "description": "Nous recherchons un développeur web...",
  "url": "https://candidat.francetravail.fr/offres/recherche/detail/210SSZN",
  "searchQuery": "développeur web",
  "scrapedAt": "2025-01-15T10:30:00.000Z"
}
```

### Development

```bash
## Install dev dependencies
npm install

## Run tests
npm test

## Watch mode
npm run test:watch
```

### How It Works

1. Builds search URLs for each query × location combination with pagination
2. Launches a headless Chromium browser with anti-detection flags
3. Navigates to France Travail search results pages
4. Extracts job listings from the DOM (title, company, location, contract, URL)
5. Optionally visits detail pages to get salary and full descriptions
6. Deduplicates by job ID and pushes results to the Apify dataset

### Anti-Detection Measures

- Random user agent rotation (8 Chrome/Firefox/Safari agents)
- Configurable random delays between requests (default 2–5s)
- `navigator.webdriver` override to hide automation
- Fake `navigator.plugins` and French language preferences
- Chromium flags: `--disable-blink-features=AutomationControlled`, `--lang=fr-FR`
- Cookie consent banner auto-dismissal

### 💰 Pricing

Pay-per-use, no monthly fees:

| | Price |
|---|---|
| **Actor start** | $0.01 |
| **Per result** | $0.01 |

> 💡 Example: A run returning 500 results costs **$5.01** total ($0.01 start + 500 × $0.01). Runs with 0 results cost only **$0.01**.

### License

ISC

# Actor input Schema

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

Job titles, keywords, or skill sets to search for (e.g., 'développeur', 'comptable', 'infirmier')

## `locations` (type: `array`):

Cities, departments, or regions to search in (e.g., 'Paris', 'Lyon', '75'). Leave empty for all France.

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

Filter by contract type

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

Maximum number of job listings to scrape total

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

Maximum number of search result pages to scrape per query

## `visitDetails` (type: `boolean`):

Visit each job's detail page to extract salary and full description (slower but more complete)

## `delayMin` (type: `integer`):

Minimum delay between requests in milliseconds

## `delayMax` (type: `integer`):

Maximum delay between requests in milliseconds

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

Number of concurrent browser pages (keep low to avoid detection)

## `debugMode` (type: `boolean`):

Enable verbose logging for debugging

## Actor input object example

```json
{
  "searchQueries": [
    "développeur"
  ],
  "contractTypes": [
    "CDI"
  ],
  "maxResults": 20,
  "maxPages": 5,
  "visitDetails": false,
  "delayMin": 2000,
  "delayMax": 5000,
  "maxConcurrency": 1,
  "debugMode": false
}
```

# Actor output Schema

## `results` (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": [
        "développeur"
    ],
    "contractTypes": [
        "CDI"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apikiy/france-travail-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": ["développeur"],
    "contractTypes": ["CDI"],
}

# Run the Actor and wait for it to finish
run = client.actor("apikiy/france-travail-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 '{
  "searchQueries": [
    "développeur"
  ],
  "contractTypes": [
    "CDI"
  ]
}' |
apify call apikiy/france-travail-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/sAzxBvD3ECtdjsIjJ/builds/vpDHfgptg5Q8yLWoV/openapi.json
