# France Travail Scraper $1💰 Jobs, Salaries & Apply Links (`abotapi/francetravail-fr-scraper`) Actor

Scrape job offers from France Travail with titles, companies, locations, salaries, contracts, descriptions, skills, employer details, and apply links. Search by keyword, location, contract, sector, salary, sort options, or paste job/search URLs.

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

## Pricing

from $1.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Scraper

Scrape structured job-offer data from **France Travail** ([francetravail.fr](https://francetravail.fr), formerly Pôle Emploi) — France's national employment platform with 700,000+ active listings.

Returns normalized job records: listing id + canonical URL, title, employer/recruiter, full location + postal code, contract type, salary range, full description, experience, skills & soft skills, additional information, employer page + apply/contact links, ROME codes, and listing labels.

### Why use this actor

- **Market researchers & analysts** — track hiring volume, salary ranges, contract mix, and regional/role demand (logistics, IT, healthcare, hospitality).
- **Recruiting intelligence** — benchmark employer hiring patterns, contract mix, and compensation across regions and sectors.
- **Data engineers** — feed structured records into dashboards, warehouses, ETL pipelines, alerts, or search/matching engines.
- **Lead generation** — identify employers, recruiters, and role-level context for prospect research.

### Input parameters

Provide keywords + filters (search mode) or paste France Travail search URLs (url mode).

| Parameter | Type | Description | Default |
| --- | --- | --- | --- |
| `mode` | `string` | `search` (keywords + filters) or `url` (paste search links). | `search` |
| `queries` | `string[]` | Search keywords (one per line), e.g. `data analyst`, `cariste`. Each runs a separate search. | — |
| `location` | `string` | City, department code, region, or postal area. Empty = all of France. | — |
| `radius` | `integer` | Search radius in km around the location (0 = none). | `10` |
| `publishedDate` | `string` | `Last 24 hours` | `Last 3 Days` | `Last Week` | `Last 2 Weeks` | `Last Month`. | — |
| `contractType` | `string[]` | Contract types (CDI, CDD, Intérim, Apprentissage, …). | — |
| `contractDuration` | `string[]` | `Full-time` | `Part-time` | `Not specified`. | — |
| `jobCategory` | `string[]` | Professional domains (IT, Healthcare, Logistics, Hospitality, …). | — |
| `minSalary` | `integer` | Minimum monthly gross salary in EUR. `0` = keep all. | `0` |
| `experience` | `string[]` | Entry / Mid / Senior / Not specified (applied from job detail). | — |
| `seniority` | `string[]` | Executive / Non-executive / Not specified. | — |
| `onlyFranceTravail` | `boolean` | Keep only offers published directly on France Travail (exclude partners). | `false` |
| `inclusiveEmployer` | `boolean` | Keep only disability-inclusive (Handi-engage) employers. | `false` |
| `adaptedCompany` | `boolean` | Keep only adapted companies. | `false` |
| `sortBy` | `string` | `Most relevant` | `Newest`. | `Newest` |
| `urls` | `string[]` | France Travail search URLs (url mode). | — |
| `maxItems` | `integer` | **The run cap** — global max listings returned. | `20` |
| `maxPages` | `integer` | Per-search page limit (20 jobs/page). `0` = unlimited (stops at `maxItems`). | `0` |
| `fetchDetails` | `boolean` | Open each job page for the full description, salary, skills, employer block, apply/contact links. Billed as a detail-enrichment surcharge. | `true` |
| `proxy` | `object` | Apify proxy settings. Residential is recommended. | Residential |

#### One cap rule

`maxItems` is the single cap. `maxPages` defaults to **unlimited** and stops at `maxItems`. Set `maxPages` only when you want a hard per-search page limit.

### Output

Each record has the stable envelope `type` + `id` + `url` (dedupe key: `type + ":" + id`):

- **Core**: `type`, `id`, `url`, `title`, `seedId`, `seedType`, `seedValue`, `pageIndex`
- **Location**: `location`, `postalCode`, `addressLocality`, `addressRegion`, `addressCountry`, `mapUrl`
- **Contract**: `contractType`, `workTime`, `workHours`, `employmentType`, `publishedAt`, `validThrough`
- **Description**: `description`
- **Salary**: `salary`, `salaryCurrency`, `salaryMin`, `salaryMax`, `salaryUnit`, `salaryText`
- **Requirements**: `experienceRequirements[]`, `skills[]`, `softSkills[]`, `additionalInformation[]`
- **Employer**: `company`, `companySize`, `recruiterName`, `recruiterDescription`, `employerPageUrl`, `employerLogoUrl`, `employerPhone`, `employerEmail`, `applyActionUrl`, `contactActionUrl`, `industry`, `qualification`, `romeCodes[]`, `jobLabels[]`
- **Badges**: `inclusiveEmployer`, `adaptedCompany`, `scrapedAt`

### Example inputs

Query-driven run:

```json
{
  "mode": "search",
  "queries": ["data analyst", "business analyst"],
  "location": "Paris",
  "publishedDate": "Last Week",
  "contractType": ["Permanent contract (CDI) | CDI"],
  "sortBy": "Newest | Date",
  "maxItems": 50
}
```

Targeted category + salary:

```json
{
  "mode": "search",
  "queries": ["cariste"],
  "location": "Lille",
  "jobCategory": ["Logistics | Transport, Logistique"],
  "contractDuration": ["Full-time | Temps plein"],
  "minSalary": 2000,
  "maxItems": 30
}
```

### Pricing

Pay-per-event: a `Results` event per dataset row, plus a small `detail-enrichment` event per detail page fetched (only when `fetchDetails` is on). An Apify `Actor Start` event covers compute.

### Connection guidance

Apify **Residential** proxy (any country) gives the highest reliability. Some datacenter exit IPs may be geo-restricted; if a run returns no results on datacenter, switch the proxy to Residential or re-run for a fresh exit IP. If you are on the Apify Free plan, residential proxy access is not included — upgrade or paste your own residential proxy URLs in the proxy field.

### Compliance & ethics

This actor collects publicly available job-posting information from francetravail.fr for legitimate business purposes (labor-market research, recruiting intelligence, monitoring). Users are responsible for ensuring their collection, storage, and use complies with applicable laws, regulations, and platform terms. This section is informational, not legal advice.

# Actor input Schema

## `mode` (type: `string`):

search = build a search from keywords and filters. url = paste one or more France Travail search URLs and walk them forward.

## `queries` (type: `array`):

Job titles, skills, or hiring phrases such as "data analyst", "cariste", or "assistant comptable". Each line runs a separate search.

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

A city, department code, region, or postal area applied to all searches (e.g. "Paris", "75D", "69000"). Leave empty to search across France.

## `radius` (type: `integer`):

Radius around the location, in kilometres (0 = no radius). Only used when a location is set.

## `publishedDate` (type: `string`):

Keep only jobs posted within the chosen window.

## `contractType` (type: `array`):

Contract types to include (permanent, fixed-term, temporary, apprenticeship, …). Allowed values: CDI, CDD, Intérim, CDI Intérimaire, Saisonnier, Contrat apprentissage, Cont. professionnalisation, Prépa.opérationnel.emploi, CDI de chantier ou d'opération, Contrat d'Engagement Educatif ….

## `contractDuration` (type: `array`):

Keep only full-time, part-time, or unspecified working-time listings. Allowed values: Temps plein, Temps partiel, Non renseignée.

## `jobCategory` (type: `array`):

Professional domains to include (IT, healthcare, logistics, hospitality, construction, …). Allowed values: Achats, Comptabilité, Gestion, Arts, Artisanat d'art, Banque, Assurance, Bâtiment, Travaux Publics, Commerce, Vente, Communication, Multimédia, Conseil, Etudes, Direction d'entreprise, Espaces verts et naturels, Agriculture, Pêche, Soins aux animaux, Hôtellerie - Restauration, Tourisme, Animation ….

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

Drop listings whose salary is below this monthly gross amount. Leave at 0 to keep all.

## `experience` (type: `array`):

Experience requirements to include (applied client-side from the job detail). Allowed values: Moins de 1 an, De 1 à 3 ans, Plus de 3 ans, Non renseignée.

## `seniority` (type: `array`):

Executive, non-executive, or unspecified qualification levels. Allowed values: Cadre, Non cadre, Non renseignée.

## `onlyFranceTravail` (type: `boolean`):

When ON, keep only offers published directly on France Travail (partner offers excluded).

## `inclusiveEmployer` (type: `boolean`):

When ON, keep only offers from employers showing the Handi-engage commitment.

## `adaptedCompany` (type: `boolean`):

When ON, keep only offers from adapted companies (entreprises adaptées).

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

Sort by relevance or by publication date.

## `urls` (type: `array`):

One or more France Travail search URLs, e.g. https://candidat.francetravail.fr/offres/recherche?motsCles=developpeur. Multi-URL supported. Filters above are ignored in this mode; pagination starts at the page implied by the URL's range and walks forward.

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

Global cap on the number of jobs to return across all searches. This is THE cap — Max pages defaults to unlimited and stops at this number.

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

Per-search page limit (20 jobs per page). 0 means no page limit — the run stops at Max listings.

## `fetchDetails` (type: `boolean`):

Open each job page to add the full description, salary range, experience, skills, soft skills, employer block, and apply/contact links. Adds one request per job (billed as a detail-enrichment surcharge). Turn off for a faster, lighter run using only the search-card fields.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl of job listings without returning or charging for jobs already collected there. Use this after an interrupted run, or when continuing a job catalogue pull in another run. For recurring daily monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching jobs as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED jobs. Turn on "Emit unchanged" or "Emit expired" only when you also want those jobs returned (and billed). State is kept separately for each mode/queries/filters/URL and detail-mode setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode/queries/filters/URL and detail settings — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return jobs that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return jobs that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search — not when Max listings capped it or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `proxy` (type: `object`):

Apify Residential proxy (any country) is recommended for the highest reliability. Some datacenter exit IPs may be geo-restricted.

## `mcpConnectors` (type: `array`):

Optionally send a condensed summary of each result into the apps you already use, via Model Context Protocol (MCP) connectors. The full record stays in the dataset. Leave empty to skip. Supported: Notion, Linear, Airtable, Apify.

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "developpeur"
  ],
  "location": "Paris",
  "radius": 10,
  "publishedDate": "Last Week",
  "contractType": [
    "Permanent contract (CDI) | CDI"
  ],
  "contractDuration": [
    "Full-time | Temps plein"
  ],
  "jobCategory": [
    "IT | Informatique, Télécommunication"
  ],
  "minSalary": 0,
  "experience": [],
  "seniority": [],
  "onlyFranceTravail": false,
  "inclusiveEmployer": false,
  "adaptedCompany": false,
  "sortBy": "Newest | Date",
  "urls": [
    "https://candidat.francetravail.fr/offres/recherche?motsCles=developpeur"
  ],
  "maxItems": 20,
  "maxPages": 0,
  "fetchDetails": true,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "queries": [
        "developpeur"
    ],
    "location": "Paris",
    "radius": 10,
    "publishedDate": "Last Week",
    "contractType": [
        "Permanent contract (CDI) | CDI"
    ],
    "contractDuration": [
        "Full-time | Temps plein"
    ],
    "jobCategory": [
        "IT | Informatique, Télécommunication"
    ],
    "minSalary": 0,
    "experience": [],
    "seniority": [],
    "onlyFranceTravail": false,
    "inclusiveEmployer": false,
    "adaptedCompany": false,
    "sortBy": "Newest | Date",
    "urls": [
        "https://candidat.francetravail.fr/offres/recherche?motsCles=developpeur"
    ],
    "maxItems": 20,
    "maxPages": 0,
    "fetchDetails": true,
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/francetravail-fr-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 = {
    "mode": "search",
    "queries": ["developpeur"],
    "location": "Paris",
    "radius": 10,
    "publishedDate": "Last Week",
    "contractType": ["Permanent contract (CDI) | CDI"],
    "contractDuration": ["Full-time | Temps plein"],
    "jobCategory": ["IT | Informatique, Télécommunication"],
    "minSalary": 0,
    "experience": [],
    "seniority": [],
    "onlyFranceTravail": False,
    "inclusiveEmployer": False,
    "adaptedCompany": False,
    "sortBy": "Newest | Date",
    "urls": ["https://candidat.francetravail.fr/offres/recherche?motsCles=developpeur"],
    "maxItems": 20,
    "maxPages": 0,
    "fetchDetails": True,
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/francetravail-fr-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 '{
  "mode": "search",
  "queries": [
    "developpeur"
  ],
  "location": "Paris",
  "radius": 10,
  "publishedDate": "Last Week",
  "contractType": [
    "Permanent contract (CDI) | CDI"
  ],
  "contractDuration": [
    "Full-time | Temps plein"
  ],
  "jobCategory": [
    "IT | Informatique, Télécommunication"
  ],
  "minSalary": 0,
  "experience": [],
  "seniority": [],
  "onlyFranceTravail": false,
  "inclusiveEmployer": false,
  "adaptedCompany": false,
  "sortBy": "Newest | Date",
  "urls": [
    "https://candidat.francetravail.fr/offres/recherche?motsCles=developpeur"
  ],
  "maxItems": 20,
  "maxPages": 0,
  "fetchDetails": true,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call abotapi/francetravail-fr-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1OvR0Wt04Z8o6Cw1a/builds/0vIgI49gzJmgrlvLQ/openapi.json
