# APEC Jobs Scraper — France Cadre Jobs & Salary API (`crawloop/apec-jobs-scraper`) Actor

APEC jobs scraper for French executive (cadre) listings on APEC.fr. Search by keyword, city, contract, or start URLs — an APEC API alternative with no login. Export title, employer, CDI/CDD, remote/hybrid, EUR salary bands, and descriptions as JSON.

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

## Pricing

from $1.99 / 1,000 job listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/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

## APEC Jobs Scraper — France Cadre Jobs & Salary API

> **Disclaimer:** Unofficial tool for publicly accessible APEC job listings. **APEC**, **apec.fr**, and *Association Pour l'Emploi des Cadres* are trademarks of their respective owners. Not affiliated with, sponsored by, or endorsed by APEC. For informational, research, aggregation, and recruiting-intelligence use only. Respect applicable terms of use and law.

**APEC jobs scraper** for France’s reference job board for **cadres** (executives, managers, engineers, and qualified professionals). A practical **APEC API alternative** and **apec.fr scraper**: search by **keyword**, **city / department / region**, **CDI / CDD**, **télétravail**, or paste **listing start URLs**. Export **title**, **employer**, **location**, **contract**, **remote / hybrid**, **EUR salary bands (k€ brut annuel)** — published on most APEC offers — and **description snippets** as **JSON**, **CSV**, or **Excel** via fast **HTTP** — **no headless browser** and **no login**. Scrape APEC with **Python**, **Node.js**, **cURL**, or **Apify MCP** / AI assistants.

Ideal for **French cadre job-board aggregation**, **salary benchmarking**, **CDI vs CDD tracking**, **recruiting intelligence**, and **employer lead generation** across Paris, Lyon, Toulouse, and nationwide.

| Actor | Focus |
| :--- | :--- |
| APEC Jobs Scraper ◄── you are here | APEC.fr France cadre / executive jobs |
| [Stepstone Jobs Scraper](https://apify.com/crawloop/stepstone-jobs-scraper) | DACH commercial job board |
| [Arbeitsagentur Jobs Scraper](https://apify.com/crawloop/arbeitsagentur-jobs-scraper) | Germany BA Jobsuche |
| [Glassdoor Scraper](https://apify.com/crawloop/glassdoor-scraper) | Employer reviews, salaries, and jobs |
| [Naukri Jobs Scraper](https://apify.com/crawloop/naukri-jobs-scraper) | India’s largest job board (Naukri.com) |
| [Foundit Jobs Scraper](https://apify.com/crawloop/foundit-jobs-scraper) | Foundit.in / Monster India job listings |

### When to use this Actor

- You need an **APEC scraper** / **apec.fr scraper** / **France cadre jobs scraper** that returns structured JSON
- You want **keyword + city + contract + télétravail** without maintaining your own crawler
- You need **EUR salary min/max parsed from k€ brut annuel**, **CDI/CDD labels**, and **geo coordinates** as first-class fields
- You want to scrape APEC with **Python**, **Node.js**, or **MCP** and export a dataset
- You run a **daily monitor** and only want **new offer numbers** billed

### When not to use this Actor

- **Non-cadre generalist boards** — this Actor covers **apec.fr** (executives / managers / engineers)
- **Guaranteed emails or phones** — public listing cards rarely include direct contacts
- **Login-walled apply-form automation** — public search data only
- **Full job-page HTML** — rows are built from APEC search cards (salary, company, and description snippet are already on the card)
- **Historical archives** — currently listed jobs only
- **DACH job boards** — use [Stepstone Jobs Scraper](https://apify.com/crawloop/stepstone-jobs-scraper) or [Arbeitsagentur Jobs Scraper](https://apify.com/crawloop/arbeitsagentur-jobs-scraper)

### Key Features

- **Keyword + city / department / region** — `position`, optional extra keywords, Paris/Lyon/Toulouse and all metropolitan departments, plus APEC lieu autocomplete for other communes
- **Start URL parsing** — paste `/candidat/recherche-emploi.html/emploi?motsCles=…&lieux=75`, function/contract/telework query strings, or a `detail-offre/{numeroOffre}` URL
- **Native APEC filters** — CDI/CDD/alternance/intérim/stage, télétravail (total / partiel / occasionnel), recency (24h / 7d), sort, include/exclude partner boards
- **Structured salary** — most APEC offers publish a **k€ brut annuel** band; parsed to EUR `salaryMin` / `salaryMax` + original `salaryNote` — never a fake zero
- **Description on the card** — no extra detail request; turn the field off only to shrink exports
- **HTTP JSON path** — Chrome TLS impersonation against APEC’s public `rechercheOffre` JSON; 256–512 MB, no Playwright
- **Datacenter-friendly** — HTML warmup obtains the DataDome cookie; residential proxy is optional if you scale
- **Monitor mode** — named Key-Value store of seen offer numbers; later scheduled runs emit only new jobs
- **Deduplicated offer numbers** across pages, keywords, and multi-city runs
- **MCP / AI ready** — call from assistants via Apify MCP

### Use Cases

| Use case | What you get |
| :--- | :--- |
| **Job aggregation** | Fresh APEC.fr cadre openings into a board / search index |
| **Salary benchmarking** | Disclosed EUR bands from k€ brut annuel, rare on other French boards |
| **Remote / hybrid tracking** | `workMode` + `teleworking` from APEC’s télétravail facet |
| **Recruiting intelligence** | Who is hiring, CDI/CDD mix, partner vs direct client, competitor vacancies |
| **Employer lead gen** | Company name and logo for firms with open cadre roles |
| **Daily “what’s new”** | `monitorMode` on a schedule — pay only for new offer numbers |

### Quick Start

**Keyword + city:**

```json
{
  "position": "python",
  "location": "Paris",
  "maxItems": 50,
  "sinceDate": "_7_DAYS",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

**CDI + full remote:**

```json
{
  "position": "chef de projet",
  "location": "Lyon",
  "contractType": "cdi",
  "workMode": "remote",
  "maxItems": 100
}
```

**Listing start URL (filters in the query string are applied):**

```json
{
  "startUrls": [
    { "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi?motsCles=data&lieux=75&typesContrat=101888" }
  ],
  "maxItems": 100
}
```

### Input

| Field | Type | Description |
| :--- | :--- | :--- |
| `position` | string | Free-text keyword (e.g. `python`, `ingénieur logiciel`). Empty = city browse or latest cadre offers |
| `searchKeywords` | string\[] | Extra keyword queries, merged and deduplicated |
| `location` | string | City, department, or region (`Paris`, `Lyon`, `Île-de-France`, `Gironde`) |
| `locations` | string\[] | Extra places, combined into one filter |
| `startUrls` | request list | Search or offer URLs |
| `workMode` | enum | Full remote / hybrid / occasional / remote-or-hybrid |
| `contractType` | enum | CDI, CDD, alternance, intérim, stage |
| `sinceDate` | enum | Last 24 hours, 7 days, 15 days, or 30 days |
| `sortBy` | enum | Relevance (needs a keyword) or newest first |
| `companyName` | string | Employer substring filter |
| `salaryMin` | integer | Keep disclosed annual salaries at or above this EUR amount |
| `includePartners` | boolean | Keep HelloWork / Cadremploi redistributions (on by default) |
| `includeJobDescription` | boolean | Keep card description (on by default; no extra request) |
| `maxItems` / `maxPages` | integer | Caps (20 jobs per page) |
| `monitorMode` | boolean | Charge only new offer numbers after the baseline run |
| `proxyConfiguration` | object | Optional; default is no proxy |

### Output

One dataset row per job. Field names match the Jobs suite (camelCase).

| Field | Type | Description |
| :--- | :--- | :--- |
| `jobId` / `offerNumber` | string | Numeric id and public `numeroOffre` (join key) |
| `title` | string | Listing title |
| `employer` / `employerLogoUrl` | string | Hiring company and logo |
| `city` / `department` / `location` | string | City, department code, full `lieuTexte` |
| `latitude` / `longitude` | number | Coordinates when APEC localised the offer |
| `workMode` / `teleworking` / `workFromHome` | string / string / boolean | `remote` / `hybrid` plus original label |
| `contractType` | string | CDI, CDD, Alternance, Intérim, Stage |
| `salaryNote` / `salaryMin` / `salaryMax` | string / integer | EUR / year when a k€ band is published |
| `salaryPeriod` / `salaryType` | string | `YEAR` and GROSS when parsed |
| `directClient` / `oqaVerified` / `lowApplications` | boolean | APEC quality flags from the card |
| `description` | string | Search-card description snippet |
| `url` | string | Job page |
| `publishedAt` / `scrapedAt` | string | ISO-8601 |

```json
{
  "source": "apec",
  "jobId": "179258068",
  "offerNumber": "179258068W",
  "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi/detail-offre/179258068W",
  "title": "Développeur Python F/H",
  "employer": "STORM GROUP",
  "city": "Paris 02",
  "department": "75",
  "workMode": "hybrid",
  "teleworking": "Télétravail occasionnel",
  "contractType": "CDI",
  "salaryMin": 40000,
  "salaryMax": 55000,
  "salaryPeriod": "YEAR",
  "salaryCurrency": "EUR",
  "salaryType": "GROSS",
  "salaryConfidential": false,
  "publishedAt": "2026-08-12T09:56:17.000+0000"
}
```

### Integration examples

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawloop/apec-jobs-scraper').call({
  position: 'python',
  location: 'Paris',
  maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.slice(0, 5));
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token)
run = client.actor("crawloop/apec-jobs-scraper").call(
    run_input={
        "position": "python",
        "location": "Paris",
        "maxItems": 50,
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item.get("title"), item.get("employer"), item.get("salaryNote"), item.get("url"))
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/crawloop~apec-jobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"position":"python","location":"Paris","maxItems":50}'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp). Connect your Apify account, then call `crawloop/apec-jobs-scraper`.

Example prompts:

- "Run APEC Jobs Scraper for python in Paris, max 50, and return title, employer, salaryNote, contractType, url as JSON"
- "Scrape APEC cadre jobs in Lyon posted in the last 7 days that are CDI and remote or hybrid"
- "Pull APEC chef de projet openings in Île-de-France, then run Glassdoor Scraper for the top hiring employers"
- "Monitor APEC python jobs in Paris daily and return only new offer numbers"

### Suite next step

APEC is France’s high-signal **cadre** board (salary on most cards, CDI-heavy). For employer reviews and interview intel on the same French companies, run [Glassdoor Scraper](https://apify.com/crawloop/glassdoor-scraper) next. For DACH commercial listings use [Stepstone Jobs Scraper](https://apify.com/crawloop/stepstone-jobs-scraper). For Germany’s public Jobsuche feed use [Arbeitsagentur Jobs Scraper](https://apify.com/crawloop/arbeitsagentur-jobs-scraper).

### FAQ

**Is this an official APEC API?**\
No. It calls the same public search JSON the website uses (`rechercheOffre`) and returns structured dataset rows — a practical **APEC API alternative** for pipelines. You do not need APEC developer credentials.

**Do I need to paste a search URL?**\
No. Keyword, city, contract, and télétravail work as inputs. `startUrls` is optional — useful when you already have an APEC search or offer URL.

**Can I paste an APEC search URL?**\
Yes — `startUrls` accepts `/candidat/recherche-emploi.html/emploi` with `motsCles`, `lieux`, `fonctions`, `typesContrat`, `typesTeletravail`, `typesConvention`, `salaireMinimum`, and individual offer URLs (`/detail-offre/…W`).

**Is this a raw JSON dump of the APEC payload?**\
No. Rows are camelCase Jobs-suite fields: parsed EUR `salaryMin` / `salaryMax`, `workMode`, `contractType`, geo, plus the original `salaryNote` — ready for CSV / Excel.

**Does APEC require login?**\
No for public search results and listing cards. Personalized “my applications” feeds are not used.

**Do I need a France residential proxy?**\
Usually not. A short HTML warmup obtains the DataDome cookie and the search JSON worked over datacenter connections in testing. A `proxyConfiguration` input is still available if you scale up and start seeing blocks.

**Why is salary so often present?**\
APEC is one of the few French boards where employers routinely publish a **k€ brut annuel** range. Numeric EUR fields appear when that text parses; `salaryConfidential: true` flags rows with no band.

**Are partner board offers included?**\
Yes by default (`includePartners: true`), matching the site checkbox. HelloWork / Cadremploi redistributions are tagged on the card; turn the option off for APEC-direct listings.

**What is monitor mode?**\
With `monitorMode: true`, seen offer numbers are stored in a named Key-Value store. The first run is the baseline (all matches are new). Later scheduled runs push and charge only numbers not seen before.

**Can I export JSON, CSV, or Excel?**\
Yes — every run writes a dataset you can download as JSON / CSV / Excel, or pull with the Apify API, Python/Node clients, or MCP.

**Can I scrape APEC with Python or Node.js?**\
Yes. Use the Apify client examples above, the REST API, or Apify MCP.

**How many jobs per search?**\
APEC paginates 20 jobs per page. Broad keywords return thousands of cadre offers; split nationwide sweeps by region or contract.

### Related Actors

| Actor | Focus |
| :--- | :--- |
| APEC Jobs Scraper ◄── you are here | APEC.fr France cadre jobs |
| [Stepstone Jobs Scraper](https://apify.com/crawloop/stepstone-jobs-scraper) | DACH job listings |
| [Arbeitsagentur Jobs Scraper](https://apify.com/crawloop/arbeitsagentur-jobs-scraper) | Germany BA Jobsuche |
| [Glassdoor Scraper](https://apify.com/crawloop/glassdoor-scraper) | Reviews, salaries, interviews, jobs |
| [Naukri Jobs Scraper](https://apify.com/crawloop/naukri-jobs-scraper) | Naukri.com India jobs |
| [Foundit Jobs Scraper](https://apify.com/crawloop/foundit-jobs-scraper) | Foundit.in / Monster India |

# Actor input Schema

## `position` (type: `string`):

Free-text job search (e.g. python, ingénieur, chef de projet, data). Leave empty to browse a city/region or the latest cadre offers.

## `searchKeywords` (type: `array`):

Optional extra keyword queries. Each keyword is searched separately; results are merged and deduplicated by APEC offer number.

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

French city (Paris, Lyon, Toulouse), department (Gironde, Nord) or region (Île-de-France, PACA). Comma-separated values are combined into one filter.

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

Optional extra cities, departments or regions. Combined with Location into one multi-lieu search (not a cartesian product).

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

Optional APEC search or offer URLs. Query filters (motsCles, lieux, fonctions, typesContrat, typesTeletravail, typesConvention, salaireMinimum) are parsed automatically.

## `workMode` (type: `string`):

APEC télétravail facet.

## `contractType` (type: `string`):

APEC contract facet.

## `sinceDate` (type: `string`):

Freshness window. Last 24 hours and 7 days use APEC’s native recency filter; 15/30 days are applied on publication date after the search.

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

Relevance only applies when a keyword is set. Empty = relevance with keyword, otherwise newest first.

## `companyName` (type: `string`):

Optional case-insensitive substring match on the employer name (applied after search).

## `salaryMin` (type: `integer`):

Keep only offers whose disclosed annual salary max (or min) is at least this amount in EUR. Offers without a salary are dropped when this filter is set. APEC publishes bands as k€ brut annuel.

## `includePartners` (type: `boolean`):

Keep APEC partner redistributions (HelloWork, Cadremploi, Meteojob, …), matching the site checkbox. Turn off for APEC-direct listings only.

## `includeJobDescription` (type: `boolean`):

Keep the description snippet already present on the search card. No extra request. Turn off to shrink CSV/Excel exports.

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

Maximum job rows to collect across all searches. 0 = unlimited (subject to maxPages). One APEC page returns 20 offers.

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

Safety cap on APEC pagination (20 jobs per page).

## `monitorMode` (type: `boolean`):

On a schedule, push and charge only offer numbers not seen in a previous run. First run delivers the full match set (baseline). Pair with an Apify Schedule and a stable monitorStoreName.

## `monitorStoreName` (type: `string`):

Named Key-Value store for seen offer numbers across scheduled runs. Use a distinct name per watch (e.g. python-paris vs chef-de-projet-lyon).

## `resetMonitorState` (type: `boolean`):

Clear the seen-job cache before this run (next run becomes a new baseline).

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

Optional. APEC search JSON works after a normal HTML warmup (DataDome cookie); leave proxy off for the cheapest run. Add FR residential only if you scale up and see blocks.

## Actor input object example

```json
{
  "position": "python",
  "location": "Paris",
  "startUrls": [
    {
      "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi?motsCles=python&lieux=75"
    }
  ],
  "workMode": "",
  "contractType": "",
  "sinceDate": "",
  "sortBy": "",
  "includePartners": true,
  "includeJobDescription": true,
  "maxItems": 100,
  "maxPages": 20,
  "monitorMode": false,
  "monitorStoreName": "apec-jobs-monitor",
  "resetMonitorState": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Default dataset items.

# 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 = {
    "position": "python",
    "location": "Paris",
    "startUrls": [
        {
            "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi?motsCles=python&lieux=75"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/apec-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 = {
    "position": "python",
    "location": "Paris",
    "startUrls": [{ "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi?motsCles=python&lieux=75" }],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/apec-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 '{
  "position": "python",
  "location": "Paris",
  "startUrls": [
    {
      "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi?motsCles=python&lieux=75"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call crawloop/apec-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawloop/apec-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/4jhmwNEaQt4kKQ1IH/builds/56EDXPg5gcj9I0QOs/openapi.json
