# French Jobs Scraper: France, Québec, Africa, from $0.90/1K (`alexmorain/francophone-jobs-scraper`) Actor

Scrape job offers from 42 French-language sources in one schema: career sites (16 ATS), job boards, public employment services, VIE, service civique, volunteering and freelance missions. City, department, region and country parsed, contract normalized, new-jobs-only mode.

- **URL**: https://apify.com/alexmorain/francophone-jobs-scraper.md
- **Developed by:** [Alexis Morain](https://apify.com/alexmorain) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 public agency 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

**French Jobs Scraper** collects job offers from **42 French-language sources** and returns them in **one schema**: company career sites, job boards, public employment services, VIE, service civique, volunteering and freelance missions, in France, Belgium, Switzerland, Luxembourg, Monaco, Canada and Québec, the Maghreb and West and Central Africa. Use it as a **French jobs API** for a job board, a market study, a lead list or a daily alert.

*Version française complète plus bas : [Scraper d'offres d'emploi francophones](#scraper-doffres-demploi-francophones-en-français).*

### What does French Jobs Scraper do?

It reads the public job listings of 42 sources, normalizes every offer into the same 34 fields, removes duplicates across sources, applies your filters, and pushes the result to an Apify dataset you can download as JSON, CSV or Excel, or read through the API.

- **One schema for every source.** City, postal code, French department, region and country parsed from the location text. Contract normalized to CDI, CDD, Stage, Alternance, Intérim, Freelance, VIE, VIA, Service civique, Volontariat, Fonction publique. Remote type (full, partial, none). Salary and daily rate (TJM) as numbers.
- **Sources nobody else covers on the Apify Store.** On 12 October 2026 we searched the Store and found no dedicated actor for Service Civique, JeVeuxAider, France Volontaires, the Monaco Employment Service, the European Solidarity Corps, Québec emploi, Taleez, Collective, ProfilCulture, Livres Hebdo, the French regional book agencies, Educarriere, Africarrieres, Senjob or MediaCongo. They are all here, next to the big ones (Welcome to the Jungle, HelloWork, Meteojob, EURES, Job Bank, jobup.ch).
- **About 2.2 million listings** counted at the sources in October 2026 (each source's own count, before cross-source duplicates), plus any company career site on 15 ATS.
- **New jobs only.** A delta mode remembers what earlier runs returned and outputs only what is new, across sources and across days.
- **You pay for what you keep.** Filtered-out jobs and duplicates are never charged. Every run stops at a per-source cap and respects the spending limit you set on the run.

It does not log in anywhere, does not scrape candidate profiles, and does not return personal emails or phone numbers of recruiters (see [Is it legal to scrape job offers?](#is-it-legal-to-scrape-job-offers)).

### Why use a French jobs scraper?

French-language hiring is spread over dozens of sites with different formats, and most store actors cover one board each. This one is a France job scraper, a source of Québec jobs, Morocco jobs and West African jobs, and a feed of freelance missions in France, all in one run and one table.

Common uses:

- **Job boards and aggregators**: feed a niche board (culture, tech, public sector, Africa) with fresh offers in one format.
- **Job seekers and coaches**: one daily alert for CDI, alternance, VIE or service civique offers matching a few keywords.
- **Recruiting and sales teams**: find companies hiring for a role in a region, then reach them through their public career page.
- **Market studies**: count offers by department, region, contract or remote type; compare salaries where published.
- **Freelancers and agencies**: watch freelance missions (Collective, Free-Work, Codeur) with their daily rate.

What the Apify platform adds: schedules (daily delta runs), the API and webhooks, integrations with Make, Zapier, n8n and Google Sheets, monitoring, and run history.

#### What makes it different

| | French Jobs Scraper | Typical store actor |
|---|---|---|
| Sources | 42, in four families | 1 |
| Countries | 24 in the country filter | 1 |
| Schema | one, with normalized contract and parsed department and region | the source's own fields |
| Language filter | detected offline, French by default | none |
| Delta mode | across sources and days | rare |
| Cross-source duplicates | removed before charge | not applicable |
| Contacts | personal emails and phones removed | often returned |
| Spending | per-source cap, time cap, run spending limit | varies |

### Sources covered

Each source is a value of the **Sources** input. Volumes are the source's own count when we built the connector (October 2026).

| Source (input value) | Family | Countries | Volume | What it covers |
|---|---|---|---|---|
| Company career sites (`ats`) | ATS | any | your list, or up to 200 boards from ready-made lists | Greenhouse, Ashby, Lever, Workday, SmartRecruiters, Workable, Personio, Rippling, Recruitee. A domain, a board URL or `ats:slug` |
| Teamtailor (`teamtailor`) | ATS | any | about 12,000 jobs on 333 career sites | built-in list of employers with jobs in French-speaking countries, or your own |
| Taleez (`taleez`) | ATS | FR, LU | about 11,000 jobs | every public job of the French ATS Taleez |
| Softy (`softy`) | ATS | FR, CD, ES, CH... | about 3,300 jobs on 77 career sites | French ATS: built-in list of employers, or your own |
| Flatchr (`flatchr`) | ATS | any | about 3,700 jobs on 264 career sites | French ATS: built-in list of employers (mostly France), or your own |
| DigitalRecruiters / Cegid (`digitalrecruiters`) | ATS | any | up to 45,000 jobs on 283 career sites | Cegid HR Talent Acquisition: built-in list of employers (mostly France), or your own |
| Breezy HR (`breezy`) | ATS | any | about 2,200 jobs on 76 career sites | employers with jobs in French or in French-speaking countries (Québec, France, Switzerland, Africa), or your own |
| JOIN (`join`) | ATS | any | about 2,500 jobs at 853 companies | company pages on join.com, mostly France; a full read takes about 42 minutes |
| Welcome to the Jungle (`wttj`) | job board | 24 | about 67,000 jobs | every job posted in the French-speaking countries |
| HelloWork (`hellowork`) | job board | FR | about 800,000 jobs | major French job board, France and overseas |
| Meteojob (`meteojob`) | job board | FR | about 300,000 jobs | French job board, full description included |
| Free-Work jobs (`free_work_jobs`) | job board | FR, BE, CH, LU, MC, GB | about 2,600 jobs | IT jobs: CDI, CDD, internships, apprenticeships |
| jobup.ch (`jobup`) | job board | CH | about 34,000 jobs | leading French-speaking Swiss job board |
| Jobillico (`jobillico`) | job board | CA | about 17,500 jobs | Québec job board, offers with a French version |
| ProfilCulture (`profilculture`) | job board | FR, BE, LU, CH | about 1,100 jobs | culture sector |
| Livres Hebdo (`livreshebdo`) | job board | FR | a handful | book trade |
| French book agencies (`agences_livre`) | job board | FR | a few dozen | FILL, ALCA, Bretagne, Auvergne-Rhône-Alpes |
| ReKrute (`rekrute`) | job board | MA, TN, SN | about 1,800 jobs | leading Moroccan board for professionals |
| Tanitjobs (`tanitjobs`) | job board | TN | about 3,100 jobs | largest Tunisian board, last 30 days |
| Emploitic (`emploitic`) | job board | DZ | about 4,400 jobs | leading Algerian board |
| Educarriere (`educarriere`) | job board | CI | about 2,000 jobs | historic Ivorian board |
| Africarrieres (`africarrieres`) | job board | 16 African countries | about 1,600 jobs | Côte d'Ivoire, Senegal, Morocco, Burkina Faso, Cameroon... |
| Senjob (`senjob`) | job board | SN, CI | about 185 jobs | Senegalese board |
| Emploi.cm (`emploi_cm`) | job board | CM | about 360 jobs | Cameroonian board. Opt-in, residential proxy needed (see limitations) |
| MediaCongo (`mediacongo`) | job board | CD | about 80 jobs | DR Congo |
| EURES (`eures`) | public | FR, BE, LU, CH | about 740,000 jobs | European public employment services portal; French offers come from France Travail |
| Le Forem (`forem`) | public | BE, LU, FR, CA | about 26,000 jobs | Walloon public employment service, open data (CC BY-SA 4.0) |
| Job Bank / Guichet-Emplois (`job_bank`) | public | CA | about 18,000 jobs | Government of Canada board: every Québec offer, French or bilingual offers elsewhere |
| Québec emploi (`quebec_emploi`) | public | CA | about 7,400 jobs | Québec government job platform |
| Choisir le service public (`choisir_service_public`) | public | FR | about 54,000 jobs | the three French civil services (State, local, hospitals) |
| Emploi territorial (`emploi_territorial`) | public | FR | about 28,000 jobs | French local government |
| FHF emploi (`fhf`) | public | FR | about 12,000 jobs | French public hospitals and care homes (Fédération hospitalière de France) |
| La bonne alternance (`la_bonne_alternance`) | public | FR | about 11,000 jobs | apprenticeship jobs of the French Ministry of Labour platform and its partners (France Travail, APEC, OPCO...) |
| Service Civique (`service_civique`) | public | any | about 13,000 missions | every mission, in France and abroad |
| European Solidarity Corps (`corps_europeen_solidarite`) | public | any | about 1,000 open placements | volunteering in every host country |
| JeVeuxAider (`jeveuxaider`) | public | FR | about 33,000 missions | volunteering, on site or remote |
| France Volontaires (`france_volontaires`) | public | any | about 60 missions | international volunteering: VSI, international civic service, solidarity leave |
| Monaco Employment Service (`monaco_emploi`) | public | MC | about 240 jobs | MonServicePublic.mc, CDI and CDD in Monaco |
| Collective (`collective`) | freelance | FR, BE, CH, LU, MC, MA | about 1,500 missions | freelance missions |
| Free-Work missions (`free_work`) | freelance | FR, BE, CH, LU, MC, GB | about 7,800 missions | freelance IT missions with daily rate |
| Codeur (`codeur`) | freelance | FR | about 35 projects a day | freelance projects with fixed budgets |
| Freelance-Informatique (`freelance_informatique`) | freelance | FR, BE, LU | about 500 missions | freelance IT missions; client never named, daily rate only when written in the description |

Not covered yet: Civiweb (the official VIE site), France Travail direct, APEC, Indeed (France Travail and APEC apprenticeship jobs come in through La bonne alternance). VIE offers still come in from the boards and career sites that publish them.

### What data can you extract?

Every item has the same 34 fields. The most useful ones:

| Field | Type | Description |
|---|---|---|
| `title` | string | Job title as published |
| `company` | string | Employer |
| `url`, `apply_url` | string | Listing and application links |
| `location` | string | Location text as served by the source |
| `location_city`, `location_postal_code` | string | City and postal code |
| `location_department_code`, `location_department` | string | French department (75, Paris) |
| `location_region` | string | French region, Belgian region, Swiss canton or Canadian province |
| `location_country` | string | ISO country code (FR, BE, CA, MA...) |
| `contract_type` | string | CDI, CDD, STAGE, ALTERNANCE, INTERIM, FREELANCE, VIE, VIA, SERVICE_CIVIQUE, VOLONTARIAT, FONCTION_PUBLIQUE, AUTRE |
| `remote_type` | string | full, partial or none |
| `salary_min`, `salary_max`, `salary_currency`, `salary_period` | number, string | Salary as numbers, when published |
| `daily_rate_min`, `daily_rate_max` | number | Daily rate (TJM) of freelance missions |
| `posted_at`, `expires_at` | string | Publication date and deadline, ISO 8601 |
| `language` | string | Language of the offer (fr, en, nl, de...) |
| `source`, `source_type` | string | Where the job comes from, and its family |
| `source_license` | string | Attribution to keep when you republish (Le Forem) |

Every field can be null: a source that does not publish a salary leaves it null rather than guessing. The dataset has three views in the console: Overview, Location, Contract and salary.

### How to scrape French job offers

1. Open the Actor and click **Try for free**.
2. In **Sources**, leave the list empty to read every source, or pick a few (for example `wttj`, `eures`, `service_civique`).
3. Add filters: **Keywords** (`marketing`, `développeur`), **Title keywords** for words the job title must contain (`Notion`, `Airtable`), **Countries**, **Locations** (`Lyon`, `69`, `Île-de-France`), **Contract types**, **Posted within (days)**.
4. Keep **Languages** on French, or add English for the English-language tech jobs in Paris, Brussels, Geneva or Luxembourg.
5. Click **Start**. Each source stops at 100 jobs or 15 minutes by default.
6. Download the dataset as JSON, CSV or Excel, or read it through the API.
7. For a daily feed, set **Mode** to *New jobs only* and add a schedule.

### How much does it cost to scrape French jobs?

You pay per job pushed to your dataset, at a price that depends on the source family and on your Apify plan. Filtered-out and duplicate jobs are never charged.

| Event | Free plan | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Public agency listing (EURES, Le Forem, Job Bank, civil service, Service Civique, volunteering) | $1.50 / 1,000 | $1.30 | $1.10 | $0.90 |
| Job board listing (WTTJ, HelloWork, Meteojob, jobup.ch, African boards...) | $2.00 / 1,000 | $1.70 | $1.40 | $1.20 |
| Company job (career sites, 16 ATS) | $2.00 / 1,000 | $1.70 | $1.50 | $1.50 |
| Freelance mission (Collective, Free-Work, Codeur) | $3.00 / 1,000 | $2.60 | $2.30 | $2.00 |
| Actor start | $0.01 per run (per GB of memory, 512 MB by default) | | | |

Worked example: one run returning 100 Welcome to the Jungle jobs, 100 EURES offers and 50 freelance missions costs, on the free plan, $0.01 + 100 × $0.002 + 100 × $0.0015 + 50 × $0.003 = **$0.51**. On a Gold plan, the same run costs **$0.32**.

A daily *New jobs only* run on a quiet day costs the $0.01 start fee and nothing else. The Apify free plan gives you $5 of usage every month, enough for about 2,500 job board listings.

To control spending, set **Max results per source**, **Max minutes per source**, and the maximum cost per run in the run options: when the run reaches it, every source stops at its next job.

### Input

See the **Input** tab for every option. Three ready-to-use examples:

#### Tech jobs in Paris, CDI, in English and French

```json
{
    "keywords": ["développeur", "developer", "data engineer", "product manager"],
    "locations": ["Paris"],
    "countries": ["FR"],
    "contractTypes": ["CDI"],
    "languages": ["fr", "en"],
    "presetLists": ["french-unicorns"],
    "postedWithinDays": 14,
    "maxResultsPerSource": 200
}
```

Sources left empty: every source that covers France runs, and `ats` reads the career sites of the French Tech unicorns.

#### Every VIE, VIA, service civique and volunteering offer, France and abroad

```json
{
    "sources": ["service_civique", "corps_europeen_solidarite", "jeveuxaider", "france_volontaires", "wttj", "hellowork", "meteojob"],
    "contractTypes": ["VIE", "VIA", "SERVICE_CIVIQUE", "VOLONTARIAT"],
    "languages": [],
    "maxResultsPerSource": 500,
    "maxMinutesPerSource": 30
}
```

`languages` is empty to keep offers in every language. To keep only missions abroad, filter `location_country` on your side: the Actor has no "exclude a country" filter.

#### Growth and marketing freelance missions, new ones only, every morning

```json
{
    "sources": ["collective", "free_work", "codeur"],
    "keywords": ["growth", "acquisition", "SEO", "marketing"],
    "mode": "new-only",
    "webhookUrl": "https://example.com/hooks/new-missions"
}
```

Schedule it daily. The webhook receives a short JSON summary only when there is something new.

#### Notion and Airtable jobs and missions, by title only

```json
{
    "titleKeywords": ["Notion", "Airtable"],
    "excludeTitleKeywords": ["notion de"],
    "postedWithinDays": 30,
    "maxResultsPerSource": 50
}
```

Only jobs that name one of the tools in their title come out: an office manager offer that lists Notion among its tools stays out. In French, « notion » is also a common word (« notion de comptabilité », some knowledge of accounting): **Exclude title keywords** drops those titles. Put the same words in **Keywords** instead to search titles and descriptions. A title-only search uses the site's own title search where it misses no title (EURES, Emploitic, Free-Work), or skips a job before opening its page; Choisir le service public has no title search and reads its list from the newest job, so keep **Posted within days** set there.

#### Input fields that need a word

- **Companies** (`ats` source): a domain (`example.fr`), a board URL (`https://jobs.lever.co/example`) or an `ats:slug` pair (`greenhouse:example`). Teamtailor sites: `teamtailor:example`; the other career-site sources the same way (`softy:`, `flatchr:`, `breezy:`, `join:`, `digitalrecruiters:`, or their URL).
- **Countries**: a job whose country cannot be established is left out when this filter is set. Remote missions of a French platform count as French.
- **Title keywords**: at least one of them in the job title, whole words, case and accents ignored. With **Keywords** set too, a job must match both lists.
- **Exclude title keywords**: one of them in the title drops the job (`notion de`, `stage`, `senior`). Same matching rules, never charged.
- **Contract types**: a job whose contract cannot be established is left out when this filter is set. A source that cannot offer any of the requested types (service civique for a freelance search) is skipped before any request.
- **Languages**: French only by default. Clear the list to keep every language.
- **Max results per source**: 100 by default; `0` means no cap (EURES alone serves over 400,000 French offers).
- **Max minutes per source**: 15 by default; `0` means no limit.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. One item, anonymized:

```json
{
    "id": "3f2a9c1d7e5b4a60",
    "source": "wttj",
    "source_type": "jobboard",
    "company": "Example Company",
    "job_id": "0b1c2d3e-4f50-6172-8394-a5b6c7d8e9f0",
    "title": "Chargé de marketing digital (H/F)",
    "url": "https://www.welcometothejungle.com/fr/companies/example-company/jobs/charge-de-marketing-digital_paris",
    "apply_url": "https://www.welcometothejungle.com/fr/companies/example-company/jobs/charge-de-marketing-digital_paris",
    "location": "Paris, France",
    "location_city": "Paris",
    "location_postal_code": null,
    "location_department_code": "75",
    "location_department": "Paris",
    "location_region": "Île-de-France",
    "location_country": "FR",
    "remote": false,
    "remote_type": "partial",
    "department": "Marketing",
    "employment_type": "full_time",
    "contract_type": "CDI",
    "part_time": null,
    "posted_at": "2026-10-12T09:00:00+00:00",
    "expires_at": null,
    "salary_min": 45000,
    "salary_max": 55000,
    "salary_currency": "EUR",
    "salary_period": "year",
    "daily_rate_min": null,
    "daily_rate_max": null,
    "description": "Example Company recrute un ou une chargée de marketing digital...",
    "language": "fr",
    "source_license": null,
    "scraped_at": "2026-10-12T16:38:00+00:00"
}
```

A public offer from EURES has the same shape, with `source_type` set to `public`, `company` often null, and the department and region filled from the source's region codes.

Each run also writes a per-source report to its default key-value store under the key `RUN_STATS`: for every requested source, the counts of jobs pushed, filtered, deduplicated, already seen and unreadable, the error if it failed, whether it hit its time budget, and its duration in seconds. Read it with `GET /v2/key-value-stores/{defaultKeyValueStoreId}/records/RUN_STATS` to check each source without parsing the status message.

### Use the French jobs API from Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("alexmorain/francophone-jobs-scraper").call(run_input={
    "sources": ["wttj", "eures", "service_civique"],
    "keywords": ["marketing"],
    "countries": ["FR"],
    "postedWithinDays": 14,
    "maxResultsPerSource": 50,
})

for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["location_city"], job["contract_type"])
```

The same call works from any language through the [Apify API](https://docs.apify.com/api/v2), and the **API** tab of this page shows ready-made snippets.

### Tips

- **Start small.** Pick a few sources and set **Max results per source** to 10 to see the output before a large run.
- **Slow sources.** Taleez, Softy, DigitalRecruiters, JOIN, ReKrute, Africarrieres, Jobillico, Monaco, FHF and Choisir le service public read one page per job; HelloWork does too when you use keywords or full descriptions. Raise **Max minutes per source** to read them further.
- **Freshness.** Use *New jobs only* rather than **Posted within (days)** for a daily feed: some sources publish no date (Workday career sites), and EURES receives France Travail offers about a week late.
- **Belgium.** EURES offers for Belgium are mostly in Dutch (VDAB). Use `forem` for French-language Belgian offers, or add `nl` to **Languages**.
- **Several schedules, one memory.** Give them the same **Delta registry key** to share the *New jobs only* memory.

### FAQ

#### How does deduplication work?

Within a source, a job is identified by its source id. Across sources, two offers with the same employer, title and city are one job, and some sources share a reference (Emploi territorial and Choisir le service public, Le Forem and EURES). The first one pushed wins; the other is counted as a cross-source duplicate and never charged. In *New jobs only* mode the memory keeps these keys too, so a job seen yesterday on one board is not charged today on another.

#### How is the language detected?

From the words of the title and description, without any external service. Short titles with no description stay null and always pass the filter.

#### Why did I get fewer jobs than expected?

Check four things: the language filter (French only by default), the country and contract filters (unknown values are left out), the per-source cap (100), and the status message, which lists for each source how many jobs were pushed, filtered and deduplicated, and how long it ran.

#### Is it legal to scrape job offers?

The Actor reads job offers that employers and agencies publish publicly, without logging in. It removes personal emails and phone numbers of recruiters from titles, departments and descriptions, keeps generic mailboxes (recrutement@, jobs@), and returns no candidate data. It does not detect people's names inside free text. You are responsible for how you use the data, including the terms of each source and data protection law (GDPR in the European Union). If you are unsure, ask a lawyer.

Le Forem offers come from Le Forem's open data (« Offres d'emploi diffusées par le Forem », [ODWB](https://www.odwb.be/explore/dataset/offres-d-emploi-forem/)) under the [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) licence. Each Le Forem item carries this attribution in `source_license`: keep it when you republish, and share derived data under the same licence.

#### What are the limitations?

- **Emploi.cm** blocks Apify datacenter IPs. It is not in the default set: select `emploi_cm` explicitly and turn on a residential proxy. Only the sources that need it use the proxy (today: Emploi.cm); every other source of the run always connects directly.
- **Other sites** can block cloud IPs from time to time. A blocked source shows as failed in the status message and the other sources go on. Jobs it returned before the block are kept; a source blocked from the start returns nothing and charges nothing.
- **EURES Belgium** is mostly Dutch, and EURES France lags France Travail by about a week.
- **Languages** default to French: English, Dutch or German offers are left out until you add them.
- **No date** on some sources (Workday career sites): they are left out when **Posted within (days)** is set.
- **Locations** are parsed conservatively: a location the Actor cannot read with confidence stays null rather than wrong.
- **Civiweb, France Travail direct, APEC and Indeed** are not covered yet (except their apprenticeship jobs, through La bonne alternance).

#### Where do I report a problem?

Open an issue in the **Issues** tab with the run link. Requests for new sources are welcome there too.

***

### Scraper d'offres d'emploi francophones (en français)

**French Jobs Scraper** collecte les offres d'emploi de **42 sources francophones** et les rend dans **un seul schéma** : sites carrières d'entreprises, jobboards, services publics de l'emploi, VIE, service civique, volontariat et missions freelance, en France, Belgique, Suisse, Luxembourg, Monaco, au Canada et au Québec, au Maghreb et en Afrique de l'Ouest et centrale. C'est une API d'offres d'emploi pour un jobboard, une étude de marché, une liste de prospects ou une alerte quotidienne.

### Que fait ce scraper d'offres d'emploi ?

Il lit les offres publiques de 42 sources, ramène chaque offre aux mêmes 34 champs, retire les doublons entre sources, applique vos filtres et pousse le résultat dans un dataset Apify, téléchargeable en JSON, CSV ou Excel, ou lisible par l'API.

- **Un schéma pour toutes les sources.** Ville, code postal, département, région et pays lus dans le lieu. Contrat normalisé : CDI, CDD, Stage, Alternance, Intérim, Freelance, VIE, VIA, Service civique, Volontariat, Fonction publique. Télétravail complet, partiel ou non. Salaire et TJM en nombres.
- **Des sources que personne d'autre ne couvre sur le store Apify.** Le 12 octobre 2026, aucun actor dédié n'existait pour Service Civique, JeVeuxAider, France Volontaires, le Service de l'Emploi de Monaco, le Corps européen de solidarité, Québec emploi, Taleez, Collective, ProfilCulture, Livres Hebdo, les agences régionales du livre, Educarriere, Africarrieres, Senjob ou MediaCongo. Elles sont toutes ici, à côté des grandes (Welcome to the Jungle, HelloWork, Meteojob, EURES, Guichet-Emplois, jobup.ch).
- **Environ 2,2 millions d'offres** comptées par les sources en octobre 2026 (le compte de chaque source, avant doublons entre sources), plus tout site carrières sur 15 ATS.
- **Nouvelles offres seulement.** Le mode delta retient ce que les runs précédents ont rendu et ne sort que le nouveau, d'une source à l'autre et d'un jour à l'autre.
- **Vous payez ce que vous gardez.** Une offre filtrée ou en doublon n'est jamais facturée. Chaque run s'arrête à un plafond par source et respecte la limite de dépense posée sur le run.

L'actor ne se connecte à aucun compte, ne lit aucun profil candidat et ne rend ni e-mail personnel ni téléphone de recruteur.

### Pourquoi utiliser un scraper d'offres d'emploi francophones ?

Le recrutement francophone est éparpillé sur des dizaines de sites aux formats différents, et la plupart des actors du store couvrent un seul site. Celui-ci rend les offres d'emploi en France, au Québec, au Maroc et en Afrique de l'Ouest, l'alternance, les VIE, le service civique et les missions freelance, en un run et une table.

Usages courants :

- **Jobboards et agrégateurs** : alimenter un site de niche (culture, tech, secteur public, Afrique) en offres fraîches au même format.
- **Candidats et coachs** : une alerte quotidienne sur les CDI, l'alternance, les VIE ou le service civique qui contiennent quelques mots-clés.
- **Recrutement et prospection** : trouver les entreprises qui recrutent sur un métier dans une région, puis les joindre par leur page carrières.
- **Études de marché** : compter les offres par département, région, contrat ou télétravail, comparer les salaires publiés.
- **Freelances et agences** : suivre les missions freelance (Collective, Free-Work, Codeur) avec leur TJM.

Ce qu'apporte la plateforme Apify : planification (run delta quotidien), API et webhooks, intégrations Make, Zapier, n8n et Google Sheets, supervision et historique des runs.

### Les sources

Chaque source est une valeur du champ **Sources**. Les volumes sont ceux du tableau de la section anglaise, comptés par chaque source en octobre 2026.

- **Sites carrières (ATS)** : `ats` (Greenhouse, Ashby, Lever, Workday, SmartRecruiters, Workable, Personio, Rippling, Recruitee, avec un annuaire de plus de 15 000 sites et des listes prêtes à l'emploi), `teamtailor` (333 employeurs, environ 12 000 offres), `taleez` (environ 11 000 offres), `softy` (77 employeurs, environ 3 300 offres), `flatchr` (264 employeurs, environ 3 700 offres), `digitalrecruiters` (Cegid HR, 283 employeurs, jusqu'à 45 000 offres), `breezy` (76 employeurs, environ 2 200 offres), `join` (853 entreprises, environ 2 500 offres).
- **Jobboards France** : `wttj` (environ 67 000 offres), `hellowork` (environ 800 000), `meteojob` (environ 300 000), `free_work_jobs`, `profilculture`, `livreshebdo`, `agences_livre`.
- **Jobboards Suisse et Québec** : `jobup` (environ 34 000), `jobillico` (environ 17 500).
- **Jobboards Maghreb et Afrique** : `rekrute` (Maroc), `tanitjobs` (Tunisie), `emploitic` (Algérie), `educarriere` (Côte d'Ivoire), `africarrieres` (16 pays), `senjob` (Sénégal), `emploi_cm` (Cameroun, sur demande), `mediacongo` (RD Congo).
- **Sources publiques** : `eures` (France, Belgique, Luxembourg, Suisse, environ 740 000 offres, celles de France viennent de France Travail), `forem` (Le Forem, données ouvertes), `job_bank` (Guichet-Emplois du Canada), `quebec_emploi`, `choisir_service_public` (les trois fonctions publiques), `emploi_territorial`, `fhf` (hôpitaux publics et établissements médico-sociaux, Fédération hospitalière de France), `la_bonne_alternance` (offres en alternance de la plateforme du ministère du Travail et de ses partenaires), `service_civique` (France et étranger), `corps_europeen_solidarite`, `jeveuxaider`, `france_volontaires` (volontariat international : VSI, service civique international, congés de solidarité), `monaco_emploi` (Service de l'Emploi de Monaco, MonServicePublic.mc).
- **Missions freelance** : `collective`, `free_work`, `codeur`, `freelance_informatique`.

Pas encore couverts : Civiweb (le site officiel des VIE), France Travail en direct, l'APEC, Indeed (leurs offres en alternance arrivent par La bonne alternance). Les VIE arrivent quand même par les jobboards et les sites carrières qui les publient.

### Quelles données ?

Chaque offre a les mêmes 34 champs, dont : intitulé (`title`), employeur (`company`), liens (`url`, `apply_url`), lieu brut (`location`), ville, code postal, code et nom du département, région, pays (`location_*`), contrat normalisé (`contract_type`), télétravail (`remote_type`), salaire (`salary_min`, `salary_max`, `salary_currency`, `salary_period`), TJM (`daily_rate_min`, `daily_rate_max`), dates de publication et de clôture (`posted_at`, `expires_at`), langue (`language`), source et famille (`source`, `source_type`), attribution de licence (`source_license`). Un champ que la source ne publie pas reste à null, jamais deviné.

### Comment récupérer des offres d'emploi francophones

1. Ouvrez l'actor et cliquez sur **Try for free**.
2. Dans **Sources**, laissez la liste vide pour tout lire, ou choisissez-en quelques-unes (`wttj`, `eures`, `service_civique`).
3. Ajoutez des filtres : **Keywords** (`marketing`, `développeur`), **Title keywords** pour les mots que le titre de l'offre doit contenir (`Notion`, `Airtable`), **Countries**, **Locations** (`Lyon`, `69`, `Île-de-France`), **Contract types**, **Posted within (days)**.
4. Gardez **Languages** sur le français, ou ajoutez l'anglais pour les offres tech rédigées en anglais à Paris, Bruxelles, Genève ou Luxembourg.
5. Cliquez sur **Start**. Chaque source s'arrête à 100 offres ou 15 minutes par défaut.
6. Téléchargez le dataset en JSON, CSV ou Excel, ou lisez-le par l'API.
7. Pour un flux quotidien, passez **Mode** sur *New jobs only* et ajoutez une planification.

### Combien coûte le scraping d'offres d'emploi ?

Vous payez chaque offre poussée dans votre dataset, à un prix qui dépend de la famille de la source et de votre plan Apify. Une offre filtrée ou en doublon n'est jamais facturée.

| Événement | Plan gratuit | Bronze | Silver | Gold et plus |
|---|---|---|---|---|
| Offre publique (EURES, Le Forem, Guichet-Emplois, fonction publique, Service Civique, volontariat) | 1,50 $ / 1 000 | 1,30 $ | 1,10 $ | 0,90 $ |
| Offre de jobboard (WTTJ, HelloWork, Meteojob, jobup.ch, jobboards africains...) | 2,00 $ / 1 000 | 1,70 $ | 1,40 $ | 1,20 $ |
| Offre de site carrières (16 ATS) | 2,00 $ / 1 000 | 1,70 $ | 1,50 $ | 1,50 $ |
| Mission freelance (Collective, Free-Work, Codeur) | 3,00 $ / 1 000 | 2,60 $ | 2,30 $ | 2,00 $ |
| Démarrage | 0,01 $ par run (par Go de mémoire, 512 Mo par défaut) | | | |

Exemple : un run qui rend 100 offres Welcome to the Jungle, 100 offres EURES et 50 missions freelance coûte, en plan gratuit, 0,01 + 100 × 0,002 + 100 × 0,0015 + 50 × 0,003 = **0,51 $**. En plan Gold : **0,32 $**.

Un run quotidien *New jobs only* un jour sans nouveauté coûte les 0,01 $ du démarrage. Le plan gratuit d'Apify donne 5 $ d'usage par mois, de quoi lire environ 2 500 offres de jobboard.

Pour maîtriser la dépense : **Max results per source**, **Max minutes per source** et le coût maximal par run dans les options du run. Quand il est atteint, toutes les sources s'arrêtent à leur offre suivante.

### Exemples d'input

#### Offres tech à Paris, en CDI, en anglais et en français

```json
{
    "keywords": ["développeur", "developer", "data engineer", "product manager"],
    "locations": ["Paris"],
    "countries": ["FR"],
    "contractTypes": ["CDI"],
    "languages": ["fr", "en"],
    "presetLists": ["french-unicorns"],
    "postedWithinDays": 14,
    "maxResultsPerSource": 200
}
```

#### Tous les VIE, VIA, services civiques et volontariats, en France et à l'étranger

```json
{
    "sources": ["service_civique", "corps_europeen_solidarite", "jeveuxaider", "france_volontaires", "wttj", "hellowork", "meteojob"],
    "contractTypes": ["VIE", "VIA", "SERVICE_CIVIQUE", "VOLONTARIAT"],
    "languages": [],
    "maxResultsPerSource": 500,
    "maxMinutesPerSource": 30
}
```

Pour ne garder que l'étranger, filtrez `location_country` de votre côté : l'actor n'a pas de filtre d'exclusion de pays.

#### Missions freelance growth et marketing, nouvelles seulement, chaque matin

```json
{
    "sources": ["collective", "free_work", "codeur"],
    "keywords": ["growth", "acquisition", "SEO", "marketing"],
    "mode": "new-only",
    "webhookUrl": "https://example.com/hooks/nouvelles-missions"
}
```

#### Offres et missions Notion ou Airtable, dans le titre seulement

```json
{
    "titleKeywords": ["Notion", "Airtable"],
    "excludeTitleKeywords": ["notion de"],
    "postedWithinDays": 30,
    "maxResultsPerSource": 50
}
```

Seules sortent les offres dont le titre nomme l'un des outils : une offre d'office manager qui cite Notion parmi ses outils reste dehors. **Exclude title keywords** écarte les titres où « notion » est un mot courant (« Assistant avec notion de comptabilité ») ; un seul de ces mots dans le titre suffit à écarter l'offre. Mettez les mêmes mots dans **Keywords** pour chercher dans les titres et les descriptions. Une recherche dans le titre seul passe par la recherche du site quand elle ne rate aucun titre (EURES, Emploitic, Free-Work), sinon saute l'offre avant d'ouvrir sa page ; Choisir le service public n'a pas de recherche sur le titre et lit sa liste depuis l'offre la plus récente : gardez **Posted within days** rempli. Avec les deux champs remplis, une offre doit satisfaire les deux listes. Un type de contrat que la source ne peut pas offrir la fait sauter avant tout appel : une recherche freelance ne lit pas le service civique.

### Sortie

Le dataset se télécharge en JSON, HTML, CSV ou Excel. Une offre a la forme de l'exemple de la section anglaise. Trois vues dans la console : Overview, Location, Contract and salary.

### Intégration en Python

L'exemple `apify-client` de la section anglaise fonctionne tel quel. L'onglet **API** de la page donne les extraits prêts à copier pour les autres langages.

### Conseils

- **Commencer petit** : quelques sources et **Max results per source** à 10 pour voir la sortie.
- **Sources lentes** : Taleez, Softy, DigitalRecruiters, JOIN, ReKrute, Africarrieres, Jobillico, Monaco, FHF et Choisir le service public lisent une page par offre, HelloWork aussi avec des mots-clés ou les descriptions complètes. Montez **Max minutes per source** pour aller plus loin.
- **Fraîcheur** : préférez *New jobs only* à **Posted within (days)** pour un flux quotidien. Certaines sources ne publient pas de date (sites Workday) et EURES reçoit les offres de France Travail avec environ une semaine de retard.
- **Belgique** : les offres EURES de Belgique sont surtout en néerlandais (VDAB). Prenez `forem` pour les offres belges en français, ou ajoutez `nl` dans **Languages**.

### Questions fréquentes

#### Comment les doublons sont-ils retirés ?

Dans une source, une offre est identifiée par son identifiant. Entre sources, deux offres au même employeur, même intitulé et même ville sont une seule offre, et certaines sources partagent une référence (Emploi territorial et Choisir le service public, Le Forem et EURES). La première poussée gagne, l'autre compte en doublon et n'est jamais facturée. En mode *New jobs only*, la mémoire garde aussi ces clés : une offre vue hier sur un site n'est pas facturée aujourd'hui sur un autre.

#### Est-ce légal ?

L'actor lit des offres que les employeurs et les organismes publient en accès libre, sans connexion. Il retire des intitulés, services et descriptions les e-mails personnels et les téléphones des recruteurs, garde les boîtes génériques (recrutement@, jobs@) et ne rend aucune donnée de candidat. Il ne détecte pas les noms de personnes dans le texte libre. L'usage des données relève de votre responsabilité, conditions de chaque source et RGPD compris. En cas de doute, demandez à un juriste.

Les offres du Forem viennent des données ouvertes du Forem (« Offres d'emploi diffusées par le Forem », [ODWB](https://www.odwb.be/explore/dataset/offres-d-emploi-forem/)), sous licence [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). Chaque offre du Forem porte cette attribution dans `source_license` : gardez-la si vous republiez, et partagez les données dérivées sous la même licence.

#### Quelles sont les limites ?

- **Emploi.cm** bloque les IP des datacenters Apify. La source n'est pas dans le jeu par défaut : choisissez `emploi_cm` et activez un proxy résidentiel. Seules les sources qui en ont besoin passent par le proxy (aujourd'hui : Emploi.cm) ; toutes les autres sources du run se connectent toujours en direct.
- **D'autres sites** peuvent bloquer les IP cloud de temps en temps. Une source bloquée apparaît en échec dans le message de statut et les autres continuent. Les offres rendues avant le blocage sont gardées ; une source bloquée dès le départ ne rend rien et ne facture rien.
- **EURES Belgique** est surtout en néerlandais, et EURES France a environ une semaine de retard sur France Travail.
- **Langues** : français seul par défaut, les offres en anglais, néerlandais ou allemand sont écartées tant que vous ne les ajoutez pas.
- **Sans date** sur certaines sources (sites Workday) : écartées quand **Posted within (days)** est rempli.
- **Lieux** lus avec prudence : un lieu illisible reste à null plutôt que faux.
- **Civiweb, France Travail en direct, l'APEC et Indeed** ne sont pas encore couverts, sauf leurs offres en alternance (par La bonne alternance).

#### Où signaler un problème ?

Ouvrez une issue dans l'onglet **Issues** avec le lien du run. Les demandes de nouvelles sources sont les bienvenues au même endroit.

# Actor input Schema

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

Which sources to read. Leave empty to use every source that has what it needs in this input, except <code>emploi_cm</code>, which runs only when you select it.<br><br>• <code>ats</code>: the public job boards of the companies you list below, on 9 applicant tracking systems (the other ATS below have their own source).<br>• <code>collective</code>: freelance missions on Collective.work (France, Belgium).<br>• <code>free_work</code>: freelance IT missions on Free-Work.<br>• <code>free_work_jobs</code>: permanent, fixed-term, internship and apprenticeship IT jobs on Free-Work.<br>• <code>codeur</code>: freelance projects on Codeur.com (fixed budgets, last 30 days unless <code>postedWithinDays</code> is set).<br>• <code>freelance_informatique</code>: freelance IT missions on Freelance-Informatique (about 500, France, a few in Belgium and Luxembourg; the client is never named, the daily rate only when the description writes it).<br>• <code>service_civique</code>: every Service Civique mission, in France and abroad.<br>• <code>wttj</code>: Welcome to the Jungle, every job posted in the French-speaking countries (France and overseas, Belgium, Switzerland, Luxembourg, Canada, Morocco...).<br>• <code>profilculture</code>: culture sector jobs on ProfilCulture (posted in the last month).<br>• <code>livreshebdo</code>: book trade jobs on Livres Hebdo.<br>• <code>agences_livre</code>: jobs and internships posted by the French book agencies (FILL, ALCA Nouvelle-Aquitaine, Livre et lecture en Bretagne, Auvergne-Rhône-Alpes Livre et Lecture).<br>• <code>eures</code>: EURES, the European public employment services portal, for France, Belgium, Luxembourg and Switzerland (most French offers come from France Travail, with about a week of delay).<br>• <code>forem</code>: Le Forem, the Walloon public employment service (Wallonia, Brussels, some Flanders and abroad), from its open data under CC BY-SA 4.0.<br>• <code>jobup</code>: jobup.ch, the leading French-speaking Swiss job board (all of Switzerland).<br>• <code>teamtailor</code>: career sites hosted on Teamtailor. With no Teamtailor entry in <b>Companies</b>, a built-in list of 333 employers with jobs in French-speaking countries; otherwise only the sites you list there.<br>• <code>taleez</code>: every public job of the French ATS Taleez (about 11,000, newest first, read one page at a time).<br>• <code>softy</code>: career sites hosted on Softy, a French ATS. With no Softy entry in <b>Companies</b>, a built-in list of 77 employers (about 3,300 jobs, one page read per job); otherwise only the sites you list there.<br>• <code>flatchr</code>: career sites hosted on Flatchr, a French ATS. With no Flatchr entry in <b>Companies</b>, a built-in list of 264 employers (about 3,700 jobs, mostly France, some Monaco, Belgium, Luxembourg); otherwise only the sites you list there.<br>• <code>digitalrecruiters</code>: career sites of the Cegid HR Talent Acquisition ATS (formerly DigitalRecruiters). With no DigitalRecruiters entry in <b>Companies</b>, a built-in list of 283 employers (up to 45,000 jobs, one page read per job, about 90 jobs a minute); otherwise only the sites you list there.<br>• <code>breezy</code>: career sites hosted on Breezy HR. With no Breezy entry in <b>Companies</b>, a built-in list of 76 employers with jobs in French or in French-speaking countries (about 2,200 jobs: Québec, France, Switzerland, Belgium, Africa); otherwise only the sites you list there.<br>• <code>join</code>: company pages on JOIN (join.com). With no JOIN entry in <b>Companies</b>, a built-in list of 853 employers (about 2,500 jobs, mostly France; a full read takes about 42 minutes, more than the default time budget); otherwise only the pages you list there.<br>• <code>rekrute</code>: ReKrute, the leading Moroccan job board for professionals (a few offers in Tunisia and Senegal). One page is read per job: about an hour for the whole site.<br>• <code>tanitjobs</code>: Tanitjobs, the largest Tunisian job board (last 30 days).<br>• <code>emploitic</code>: Emploitic, the leading Algerian job board, with full descriptions.<br>• <code>educarriere</code>: Educarriere, the historic Ivorian job board.<br>• <code>africarrieres</code>: Africarrieres, jobs in 16 French-speaking African countries (Côte d'Ivoire, Senegal, Morocco, Burkina Faso, Cameroon...). Set <code>countries</code> to read only the ones you need: one page is read per job.<br>• <code>senjob</code>: Senjob, Senegalese job board.<br>• <code>emploi_cm</code>: Emploi.cm, Cameroonian job board (read slowly, 10 seconds between pages, as the site asks). <b>Not in the default set</b>: the site blocks Apify datacenter IPs, so select it explicitly and turn on a <b>residential proxy</b> under Advanced (only this source uses it, the others connect directly).<br>• <code>mediacongo</code>: MediaCongo, jobs posted in the Democratic Republic of the Congo (read slowly, 10 seconds between pages, as the site asks).<br>• <code>choisir_service_public</code>: every offer of the three French civil services (State, local, hospitals) on Choisir le service public, with category, branch and contract (slow: one page read per offer).<br>• <code>emploi_territorial</code>: French local-government jobs on emploi-territorial.fr (permanent posts, fixed-term, apprenticeships, internships).<br>• <code>fhf</code>: jobs of the French public hospitals and care homes on FHF emploi, the Fédération hospitalière de France job site (about 12,000, newest first, one page read per job).<br>• <code>la_bonne_alternance</code>: apprenticeship jobs (apprentissage, professionnalisation) of La bonne alternance, the French Ministry of Labour platform, with its partners' offers (France Travail, APEC, OPCO...), about 11,000.<br>• <code>corps_europeen_solidarite</code>: volunteering placements of the European Solidarity Corps in every host country (European Youth Portal), open ones with a deadline still ahead.<br>• <code>jeveuxaider</code>: volunteering missions on JeVeuxAider.gouv.fr, on site or remote, all over France.<br>• <code>france_volontaires</code>: international volunteering missions published by France Volontaires (VSI, international civic service, solidarity leave), all over the world.<br>• <code>monaco_emploi</code>: job offers of the Monaco Employment Service, published on MonServicePublic.mc (one page is read per job, about 5 minutes for all).<br>• <code>hellowork</code>: HelloWork, a major French job board (about 800,000 jobs, France and overseas). Keywords or <b>Include full job description</b> fetch each job page, about one job per second.<br>• <code>meteojob</code>: Meteojob, French job board (about 300,000 jobs, newest first, full description included).<br>• <code>jobillico</code>: Jobillico, the Québec job board, every offer with a French version (about 17,500, mostly Québec, one page per offer).<br>• <code>job_bank</code>: Job Bank (Guichet-Emplois), the Government of Canada job board: every Québec offer, plus French or bilingual offers in the other provinces and territories.<br>• <code>quebec_emploi</code>: Québec emploi, the Québec government job platform (about 7,400 offers).

## `companies` (type: `array`):

One company per line, for the <code>ats</code> source. Three accepted forms:<br>• <b>a domain</b>: <code>doctolib.fr</code>, resolved through a built-in directory of 15,000+ job boards, then by probing the ATS APIs live.<br>• <b>a job board URL</b>, the most reliable: <code>https://jobs.lever.co/qonto</code>.<br>• <b>an explicit ats:slug pair</b>: <code>greenhouse:doctolib</code>, <code>ashby:alan</code>. Workday needs <code>workday:tenant|wd5|site</code>.<br><br>For the <code>teamtailor</code> source: <code>teamtailor:payfit</code>, <code>teamtailor:careers.example.com</code> for a custom career domain, or a <code>https://payfit.teamtailor.com</code> URL.<br><br>For the other career-site sources, the same forms: <code>softy:habitat70</code>, <code>flatchr:maped</code> or <code>https://maped.flatchr.io</code>, <code>breezy:gozem</code> or <code>https://gozem.breezy.hr</code>, <code>join:amplitudes</code> or <code>https://join.com/companies/amplitudes</code>, <code>digitalrecruiters:recrutement.example.fr</code>. The <code>ats</code> source leaves these entries to their own source.<br><br>A company that fails is logged and skipped, the others go on.

## `presetLists` (type: `array`):

Adds whole lists of companies, already matched to their job boards: <code>french-unicorns</code> (French Tech unicorns), <code>forbes-ai-50</code>, <code>y-combinator</code>, or every board of one ATS (<code>all-greenhouse</code>...), up to <b>Max boards from lists</b>. Boards already in Companies are never scraped twice.

## `maxPresetBoards` (type: `integer`):

Safety cap on the number of job boards the ready-made lists add, all lists combined. Defaults to <code>200</code>. You are charged for jobs returned, not for boards scanned.

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

Keep only jobs whose title (or description, when <b>Include full job description</b> is on) contains at least one of these words, case and accent insensitive: <code>data</code>, <code>développeur</code>, <code>product manager</code>.<br><br>Leave empty to keep everything.

## `titleKeywords` (type: `array`):

Keep only jobs whose <b>title</b> contains at least one of these words, case and accent insensitive, whole words only: <code>Notion</code>, <code>Airtable</code>, <code>chef de projet</code>. A job that only mentions them in its description is left out.<br><br>Used together with <b>Keywords</b>, a job must match both lists. Title-only searches are also faster: sources skip the job pages they would otherwise open to read descriptions.<br><br>Leave empty to keep everything.

## `excludeTitleKeywords` (type: `array`):

Leave out jobs whose <b>title</b> contains any of these words, case and accent insensitive, whole words only. Useful when a tool name is also a common word: with <code>Notion</code> in <b>Title keywords</b>, add <code>notion de</code> here to drop « Assistant avec notion de comptabilité ». Excluded jobs are never charged.<br><br>Leave empty to exclude nothing.

## `countries` (type: `array`):

Keep only jobs located in these countries. A job whose country cannot be established from its location is left out when this filter is set.

## `languages` (type: `array`):

Keep only jobs written in these languages. <b>French only by default.</b> Add <code>en</code> to get the many English-language tech jobs in Paris, Brussels, Geneva or Luxembourg; add <code>nl</code> for Flanders and Brussels, <code>de</code> for German-speaking Switzerland and Luxembourg, <code>ar</code> for the Maghreb and Lebanon. <b>Clear the list to get every language.</b><br><br>The language is read from the job title and description (or given by the source when it says so). A job whose language cannot be established (a short title with no description) is always kept. Filtered-out jobs are never charged.

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

Keep only jobs matching one of these places. A city (<code>Lyon</code>), a postal code (<code>75008</code>), a French department code or name (<code>69</code>, <code>Gironde</code>), a region (<code>Île-de-France</code>), or any part of the location text.

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

Keep only these contract types. The Actor maps every source label to one type (Full-time and Permanent become CDI, Internship becomes Stage, Apprenticeship becomes Alternance...). A job whose contract cannot be established is left out when this filter is set.

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

Keep only fully remote jobs, or jobs the source flags as remote.

## `postedWithinDays` (type: `integer`):

Keep only jobs published in the last N days. Jobs without a publication date (Workday boards serve none) are left out when this is set: use <b>New jobs only</b> mode for reliable freshness instead.

## `maxResultsPerSource` (type: `integer`):

Stops each source once it has returned this many jobs (after filters and duplicates). <b>100 by default.</b><br><br>Set <code>0</code> for no cap: every source is then read to the end, which can mean hundreds of thousands of jobs (EURES alone serves over 400,000), all of them charged.

## `maxMinutesPerSource` (type: `integer`):

Stops a source that is still reading after this many minutes; the jobs it already returned are kept, and the status message says which sources stopped. <b>15 by default.</b><br><br>Some sources read one page per job (Taleez, ReKrute, Choisir le service public) and take an hour or more to read in full. Raise this value to read further, or set <code>0</code> for no time limit.

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

<b>All live jobs</b> returns every matching job on every run.<br><br><b>New jobs only</b> keeps a persistent registry of what previous runs returned and outputs only what is new. Schedule it daily: a quiet day costs the start fee alone. The registry is tied to your sources, filters and companies; change them and a new registry starts.

## `includeDescription` (type: `boolean`):

Adds the full job description as plain text. Off by default: on some boards it costs one extra request per job and makes the run several times longer. It does not change the price.

## `includeRaw` (type: `boolean`):

Keeps the <code>raw</code> field: the original job object exactly as the source served it. Off by default for a lighter dataset.

## `registryKey` (type: `string`):

Only for <b>New jobs only</b>. Leave empty and the registry is derived from your input. Set it to make several schedules share one memory.

## `webhookUrl` (type: `string`):

If set, the Actor POSTs a small JSON summary to this URL at the end of the run, only when at least one job was returned. Stored encrypted, like a password, since a webhook URL often carries a token. An unreachable webhook never fails the run.

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

Only used by sources that need it (today: <code>emploi_cm</code>). All other sources always connect directly.<br><br><code>emploi_cm</code> needs a <b>residential</b> proxy: the site blocks Apify datacenter IPs. Leave this off if you do not run <code>emploi_cm</code>.

## Actor input object example

```json
{
  "sources": [
    "wttj",
    "eures",
    "service_civique"
  ],
  "companies": [
    "doctolib.fr",
    "ashby:alan",
    "https://jobs.lever.co/qonto"
  ],
  "presetLists": [
    "french-unicorns"
  ],
  "keywords": [
    "data",
    "python"
  ],
  "titleKeywords": [
    "Notion",
    "Airtable"
  ],
  "excludeTitleKeywords": [
    "notion de",
    "notions"
  ],
  "countries": [
    "FR"
  ],
  "languages": [
    "fr"
  ],
  "locations": [
    "Paris",
    "69",
    "Bretagne"
  ],
  "remoteOnly": false,
  "postedWithinDays": 14,
  "maxResultsPerSource": 10,
  "maxMinutesPerSource": 15,
  "mode": "all",
  "includeDescription": false,
  "includeRaw": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of the job offers pushed by the run

# 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 = {
    "sources": [
        "wttj",
        "eures",
        "service_civique"
    ],
    "companies": [
        "ashby:ledger",
        "greenhouse:mirakl"
    ],
    "keywords": [
        "marketing",
        "communication"
    ],
    "countries": [
        "FR"
    ],
    "postedWithinDays": 14,
    "maxResultsPerSource": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexmorain/francophone-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 = {
    "sources": [
        "wttj",
        "eures",
        "service_civique",
    ],
    "companies": [
        "ashby:ledger",
        "greenhouse:mirakl",
    ],
    "keywords": [
        "marketing",
        "communication",
    ],
    "countries": ["FR"],
    "postedWithinDays": 14,
    "maxResultsPerSource": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("alexmorain/francophone-jobs-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 '{
  "sources": [
    "wttj",
    "eures",
    "service_civique"
  ],
  "companies": [
    "ashby:ledger",
    "greenhouse:mirakl"
  ],
  "keywords": [
    "marketing",
    "communication"
  ],
  "countries": [
    "FR"
  ],
  "postedWithinDays": 14,
  "maxResultsPerSource": 10
}' |
apify call alexmorain/francophone-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alexmorain/francophone-jobs-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/TaByUeQ7gd31n5P8n/builds/8A6dEUHuBtnaE3E4o/openapi.json
