# APEC Jobs Scraper - France Cadre Jobs, Salary & Company (`haketa/apec-jobs-scraper`) Actor

Scrape APEC (apec.fr) France executive and cadre job listings. Extract job title, hiring company, location, salary range, contract type, description, publication date and geo-coordinates by keyword. Export JSON, CSV, Excel for recruitment, salary benchmarking and market research.

- **URL**: https://apify.com/haketa/apec-jobs-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Jobs, Business, Lead generation
- **Features:** Limited permissions
- **Stats:** 18 total users, 8 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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/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

## APEC Jobs Scraper — France Cadre Jobs with Salary, Company, Location & Geo

> **Extract structured French executive and *cadre* job listings from [APEC (apec.fr)](https://www.apec.fr/) — France's official job board for managers, engineers, and professionals.** This **APEC scraper** delivers job titles, hiring **company**, location, **salary range** (published on virtually every offer), contract type, full description, publication dates, and GPS geo-coordinates. **Scrape APEC** by keyword with zero login and zero coding. Built for recruitment agencies, compensation benchmarking, B2B lead generation, and French labour-market intelligence.

Export every result to **JSON, CSV, Excel, or API** with 1,000+ results pagination unlocked.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/haketa/apec-jobs-scraper)
[![Live Data](https://img.shields.io/badge/Data-Live%20at%20Run%20Time-orange)]()
[![Pricing](https://img.shields.io/badge/Pricing-Pay%20Per%20Result-yellow)]()
[![Region](https://img.shields.io/badge/Region-France%20%F0%9F%87%AB%F0%9F%87%B7-red)]()
[![Coverage](https://img.shields.io/badge/Coverage-Cadre%20%26%20Executive-purple)]()
[![Salary](https://img.shields.io/badge/Includes-Salary%20Ranges-success)]()
[![Company](https://img.shields.io/badge/Includes-Company%20%26%20Geo-brightgreen)]()
[![No Auth](https://img.shields.io/badge/Auth-None%20Required-success)]()
[![Export](https://img.shields.io/badge/Export-JSON%20%C2%B7%20CSV%20%C2%B7%20Excel-lightgrey)]()

***

### ⚡ At a glance

| Feature | Details |
| :--- | :--- |
| **Target Platform** | [APEC (apec.fr)](https://www.apec.fr/) — Association Pour l'Emploi des Cadres (France) |
| **Core Data Extracted** | Job Title, Hiring Company, Salary Range (`k€ brut annuel`), Contract Type, City/Department, GPS Coordinates, Description, Dates |
| **Unique Advantage** | **~100% Salary Transparency** — nearly every APEC cadre listing publishes an explicit annual gross salary range |
| **Search Modes** | Multi-keyword search (`développeur`, `chef de projet`, `finance`, etc.) or unfiltered latest cadre feed |
| **Sorting Options** | Relevance (`relevance`) or Most Recent (`date`) |
| **Pagination & Scale** | Deep pagination unlocked (100 jobs/page, **1,000+ results pagination** per keyword or across keywords) |
| **Deduplication** | Automatic deduplication by official `offerNumber` (`numeroOffre`) across all pages and keywords |
| **Proxy Requirement** | France Residential Proxy (`RESIDENTIAL`, `FR` — pre-configured by default for France geo-access) |
| **Export Formats** | JSON, CSV, Excel (XLSX), HTML, XML, RSS, and REST API |

***

### 📋 Table of contents

- [Why scrape APEC?](#-why-scrape-apec)
- [What this APEC scraper does](#-what-this-apec-scraper-does)
- [High-value use cases](#-high-value-use-cases)
- [Input configuration](#-input-configuration)
- [Output sample & field reference](#-output-sample--field-reference)
- [Pagination & 1,000+ scale](#-pagination--1000-scale)
- [How to use (Console & API)](#️-how-to-use-console--api)
- [Pro tips for French recruitment & salary analysis](#-pro-tips-for-french-recruitment--salary-analysis)
- [Honest limitations](#-honest-limitations)
- [FAQ](#-faq)
- [Related scrapers](#-related-scrapers)
- [Changelog](#-changelog)

***

### 🔎 Why scrape APEC?

**[APEC](https://www.apec.fr/)** — the *Association Pour l'Emploi des Cadres* — is France's mandated national job board for **cadres**: executives, managers, engineers, financial specialists, and qualified white-collar professionals. It is the primary hiring channel for mid-to-senior corporate talent in France, hosting tens of thousands of active job openings across Paris, Île-de-France, Lyon, Marseille, Toulouse, Bordeaux, Lille, Nantes, and every French department.

APEC data stands apart from every other European job board for one critical reason: **virtually every job offer publishes an explicit annual gross salary range** (e.g., `45 - 55 k€ brut annuel`). On general French job portals, pay is frequently hidden as *"selon profil"*. On APEC, salary disclosure is standard practice. Combined with the hiring company's commercial name, company logo, city and department number, GPS coordinates (`latitude` / `longitude`), normalized contract type (`CDI`, `CDD`, `Travail temporaire`, `Alternance`), and full job description, **APEC data extractor** workflows provide unmatched B2B intelligence.

Collecting this information manually does not scale. Browsing page by page, decoding contract identifiers, and removing duplicate postings across overlapping searches takes hours. This **APEC scraper** automates the entire pipeline and delivers clean, deduplicated records ready for spreadsheets, BI dashboards, or ATS/CRM ingestion.

**Key reasons teams scrape APEC:**

- 💶 **Executive Salary Benchmarking** — build real-time compensation matrices by role, seniority, department, and contract type using published French gross salary bands.
- 🧑‍💼 **B2B Lead Generation & Agency Sourcing** — identify French companies actively hiring high-value *cadre* roles and route hiring signals directly to recruitment consultants or sales teams.
- 📊 **Labour-Market & Economic Research** — track hiring velocity, contract distribution (`CDI` vs `CDD`), and regional demand shifts across France.
- 🏢 **Competitor Hiring Intelligence** — monitor which competitors are expanding engineering, sales, or management teams and what compensation packages they offer.
- 📈 **Job Board & HR Tech Aggregation** — populate talent platforms, career portals, and internal mobility tools with structured French executive listings.
- 🤖 **HR Analytics & NLP Datasets** — train compensation prediction models and skill-extraction pipelines on clean French job descriptions paired with real salary labels.

***

### ✨ What this APEC scraper does

The **APEC Jobs Scraper** accepts one or more search keywords (or runs with no keywords to capture the latest nationwide cadre offers) and extracts every matching listing across result pages into a flat, analysis-ready schema.

- ✅ **Multi-Keyword Search** — pass any list of French roles, skills, cities, or sectors (`["développeur", "chef de projet", "data scientist", "comptable"]`); each keyword is paginated independently.
- ✅ **Published Salary Ranges (`salary`)** — captures APEC's explicit salary band (e.g., `45 - 50 k€ brut annuel`) on ~100% of offers.
- ✅ **Hiring Company & Branding** — extracts the employer's commercial name (`company`), logo URL (`logo`), and confidentiality status (`confidential`).
- ✅ **Decoded Contract Types (`contractType`)** — translates internal APEC facet codes into clean French contract labels: **CDI, CDD, Travail temporaire, Freelance, Stage, Alternance**.
- ✅ **Precise Location & GPS Coordinates** — provides both human-readable `location` (`Wasquehal - 59`, `Paris 08 - 75`) and exact `latitude` / `longitude` coordinates for geospatial mapping.
- ✅ **Clean Full-Text Descriptions** — strips HTML tags and entities from `description` so the text is immediately usable for reading, search indexing, or LLM prompting.
- ✅ **Deep 1,000+ Pagination** — steps through result pages in batches of 100 offers (`startIndex` pagination) until your `maxItemsPerSearch` / `maxTotalItems` target is met or all offers are exhausted.
- ✅ **Global Deduplication** — deduplicates every offer by its unique `offerNumber` (`numeroOffre`), ensuring zero duplicate rows even when multiple keywords overlap.
- ✅ **Flexible Sorting** — order results by best match (`relevance`) or newest postings first (`date`).

***

### 🎯 High-value use cases

#### 1. Recruitment Agencies & Executive Headhunters (BD Signals)

Every open *cadre* listing on APEC is a verified buying signal: a company has budget approval to hire a salaried manager, engineer, or specialist. Filter out confidential listings (`confidential: "false"`), group by `company` and `location`, and equip business development teams with a daily list of French employers actively recruiting in your niche.

#### 2. Total Rewards & Compensation Consultants

Because APEC enforces salary bands across almost all postings, HR teams can export 1,000+ offers for a target function (e.g., `ingénieur DevOps`, `directeur financier`, `juriste`), parse the minimum and maximum `k€ brut annuel` values, and compare Paris (75) / Hauts-de-Seine (92) pay scales against regional hubs like Lyon (69), Toulouse (31), or Bordeaux (33).

#### 3. B2B SaaS & Corporate Services Lead Generation

Companies hiring specific roles reveal their technology stack and operational priorities. Scraping APEC for keywords like `Salesforce`, `SAP`, `cybersécurité`, or `RSE` identifies French enterprises investing in those exact domains.

#### 4. Regional Economic & Academic Labour Studies

Geospatial coordinates (`latitude`, `longitude`) and department codes in `location` allow economists, urban planners, and workforce analysts to map white-collar job creation across French territories over time.

***

### 📥 Input configuration

All fields are optional. Running with the default prefill collects a fast sample of French cadre jobs; setting `maxItemsPerSearch: 0` and `maxTotalItems: 1000` (or higher) unlocks deep multi-page extraction.

| Field | Type | Default / Prefill | Description |
| :--- | :--- | :--- | :--- |
| `searchKeywords` | `array` | Prefill: `["développeur"]` | Job keywords to search on APEC (e.g., `développeur`, `chef de projet`, `data scientist`). Each keyword is searched separately across result pages. Leave empty to collect the latest cadre offers nationwide. |
| `sortBy` | `string` | `"relevance"` | Order in which jobs are collected: `"relevance"` (Best match) or `"date"` (Most recent). |
| `maxItemsPerSearch` | `integer` | Default: `0` (Prefill: `100`) | Maximum number of jobs to collect per keyword. Set to `0` for all available jobs (governed by `maxTotalItems`). |
| `maxTotalItems` | `integer` | `0` | Global cap across all keywords combined. `0` = no global cap (an empty run with no keywords and no limits defaults to a fast 100-job sample). |
| `proxyConfiguration` | `object` | Residential `FR` | Proxy configuration. A France residential proxy is required because APEC is geo-locked to French IPs, and is pre-configured by default. |

#### Example 1 — Quick 100-job keyword run (Prefill)

```json
{
  "searchKeywords": ["développeur"],
  "sortBy": "relevance",
  "maxItemsPerSearch": 100,
  "maxTotalItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "FR"
  }
}
```

#### Example 2 — Deep 1,000+ job extraction across multiple tech & management roles

```json
{
  "searchKeywords": ["développeur", "data engineer", "chef de projet IT", "product manager"],
  "sortBy": "date",
  "maxItemsPerSearch": 0,
  "maxTotalItems": 1500,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "FR"
  }
}
```

***

### 📤 Output sample & field reference

Each job listing is stored as a clean, flat JSON object in the Apify dataset. Below is an authentic output record from a live APEC run:

```json
{
  "jobId": "179444601",
  "offerNumber": "179444601W",
  "title": "Concepteur développeur (Développeur informatique) F/H",
  "company": "CD Consulting",
  "location": "Wasquehal - 59",
  "salary": "45 - 50 k€ brut annuel",
  "contractType": "CDI",
  "description": "Notre client, Dickson Constant, est leader mondial des textiles techniques d'extérieur...",
  "datePublished": "2026-10-26T07:32:36.000+0000",
  "dateValidated": "2026-10-26T07:32:36.000+0000",
  "latitude": "50.6751234",
  "longitude": "3.1279233",
  "confidential": "false",
  "remoteId": "",
  "logo": "https://www.apec.fr/media_entreprise/718992/logo_CD_CONSULTING_718992_1093927.png",
  "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi/detail-offre/179444601W",
  "searchKeyword": "développeur",
  "scrapedAt": "2026-11-10T02:30:00.000Z"
}
```

#### 🗂️ Field reference & coverage table

##### 💼 Core Job & Compensation Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `jobId` | `string` | 🟢 High (100%) | Internal numeric APEC job identifier. |
| `offerNumber` | `string` | 🟢 High (100%) | Official APEC offer reference (`numeroOffre`, e.g., `179444601W`) used as the primary deduplication key. |
| `title` | `string` | 🟢 High (100%) | Clean job title (`intitule`), typically including `F/H` gender-neutral designation. |
| `salary` | `string` | 🟢 High (~100%) | Published gross annual salary range (e.g., `45 - 50 k€ brut annuel`, `Selon profil`). |
| `contractType` | `string` | 🟢 High (100%) | Decoded contract type label (`CDI`, `CDD`, `Travail temporaire`, `Freelance`, `Stage`, `Alternance`). |
| `description` | `string` | 🟢 High (100%) | Plain-text job description preview/summary with HTML tags stripped. |
| `url` | `string` | 🟢 High (100%) | Direct canonical URL to the public job offer on `apec.fr`. |

##### 🏢 Employer & Location Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `company` | `string` | 🟢 High (~99%) | Hiring company commercial name (`nomCommercial`). Empty only on strictly anonymous postings. |
| `confidential` | `string` | 🟢 High (100%) | `"true"` if the employer hid its identity, `"false"` otherwise. |
| `logo` | `string` | 🟡 Conditional (~65%) | Full URL to the employer's uploaded logo image on APEC. |
| `location` | `string` | 🟢 High (100%) | City and French department number (e.g., `Bordeaux - 33`, `Paris 08 - 75`). |
| `latitude` | `string` | 🟢 High (~94%) | WGS84 GPS latitude of the workplace when geocoded by APEC. |
| `longitude` | `string` | 🟢 High (~94%) | WGS84 GPS longitude of the workplace when geocoded by APEC. |
| `remoteId` | `string` | 🟡 Conditional (~45%) | APEC remote-work (*télétravail*) policy identifier when specified by the employer. |

##### 🕒 Dates & Run Metadata

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `datePublished` | `string` | 🟢 High (100%) | Original publication timestamp (ISO 8601). |
| `dateValidated` | `string` | 🟢 High (100%) | Latest validation/refresh timestamp by APEC moderators (ISO 8601). |
| `searchKeyword` | `string` | 🟢 High (100%) | The input keyword that matched this job offer. |
| `scrapedAt` | `string` | 🟢 High (100%) | ISO 8601 timestamp when the record was extracted. |

***

### 🔁 Pagination & 1,000+ scale

The **APEC Jobs Scraper** is engineered for both quick sampling and deep 1,000+ bulk extraction:

- **100-Offer Page Batches** — each pagination step retrieves up to 100 job offers in a single structured payload, minimizing network overhead and keeping runs fast.
- **Unclamped Deep Pagination** — `maxItemsPerSearch` defaults to `0` (unlimited per keyword, governed by `maxTotalItems`). Whether you request 100, 1,000, or 5,000 offers for high-volume keywords like `développeur` (3,400+ active offers) or `chef de projet`, the scraper steps `startIndex` (`0 → 100 → 200 → ...`) until your exact limit is reached or `totalCount` is exhausted.
- **Cross-Keyword Deduplication** — an in-memory `Set` tracks every `offerNumber` across the entire run. If a job matches both `data scientist` and `machine learning`, it is saved once and never duplicated.
- **Empty-Run Safety** — if started with an empty input `{}` and no explicit limits, the actor automatically collects a fast 100-job sample of the latest French cadre openings.

***

### ⚙️ How to use (Console & API)

#### In Apify Console

1. Open **[APEC Jobs Scraper](https://apify.com/haketa/apec-jobs-scraper)** in Apify Console.
2. Enter one or more French job terms in **Search keywords** (e.g., `développeur`, `ingénieur`, `commercial`).
3. Choose **Sort by** (`Relevance` or `Most recent`).
4. Set **Max jobs per keyword** (e.g., `100` for a quick test, or `0` with **Max total jobs** set to `1000` for a deep pull).
5. Click **Start** and download your dataset in **JSON, CSV, or Excel** from the **Storage** tab.

#### Via Apify API (Python)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "searchKeywords": ["développeur", "chef de projet"],
    "sortBy": "date",
    "maxItemsPerSearch": 0,
    "maxTotalItems": 1000,
}

run = client.actor("haketa/apec-jobs-scraper").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['offerNumber']} | {item['title']} | {item['company']} | {item['salary']}")
```

#### Via Apify API (JavaScript / Node.js)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('haketa/apec-jobs-scraper').call({
    searchKeywords: ['développeur'],
    sortBy: 'date',
    maxItemsPerSearch: 500,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Extracted ${items.length} unique APEC cadre jobs.`);
```

***

### 💡 Pro tips for French recruitment & salary analysis

- **Parse min/max salary numbers in Excel or Python** — APEC formats salaries consistently as `"XX - YY k€ brut annuel"` or `"À partir de XX k€ brut annuel"`. Extracting the first and second integers gives you instant numeric `min_salary_keur` and `max_salary_keur` columns.
- **Extract the French Department code from `location`** — `location` follows the pattern `"City - Dept"` (e.g., `"Lyon 03 - 69"`, `"Nantes - 44"`). Splitting on `" - "` lets you group offers by French *département* (75, 92, 69, 31, 33, 59, etc.).
- **Schedule daily delta runs with `sortBy: "date"`** — when sorted by most recent, the first 100–200 offers per keyword capture all newly published jobs from the past 24 hours.
- **Keep France Residential Proxy enabled** — APEC restricts access outside French IP ranges. The default `RESIDENTIAL` (`FR`) proxy configuration handles session initialization automatically.

***

### ⚠️ Honest limitations

- **France Geo-Lock Requires FR Residential Proxy** — APEC blocks non-French datacenter traffic at the network edge. Keep the default France residential proxy enabled for reliable execution.
- **Search-Feed Description Scope** — the `description` field contains the rich plain-text summary returned by APEC's search feed (~300–600 characters) rather than fetching a separate HTML page per job, which keeps runs 50× faster and dramatically reduces residential proxy transfer costs.
- **Conditional Fields** — `logo` (~65%) and `remoteId` (~45%) are only populated when the hiring employer explicitly uploaded a logo or tagged a remote-work policy on the listing.

***

### ❓ FAQ

#### Does every APEC job listing include a salary?

Almost all of them. Unlike general job boards where salary is optional, APEC requires employers to specify a compensation band or policy on virtually every *cadre* offer (~100% fill rate in live benchmarks).

#### How many jobs can I scrape in a single run?

You can collect **1,000+ jobs** in a single run. Set `maxItemsPerSearch: 0` and `maxTotalItems: 1000` (or `0` for unlimited) to paginate through all matching pages at 100 jobs per page.

#### Why is a France residential proxy required?

APEC (`apec.fr`) is geo-locked to France and protected against non-French automated traffic. The actor is pre-configured with Apify's France (`FR`) residential proxy so it works out of the box without any manual proxy setup.

#### Do I need an APEC candidate or recruiter account?

No. All extracted job listings are publicly visible cadre offers. No login, cookies, or credentials are required.

#### How are contract types formatted?

APEC's internal numeric contract codes are automatically decoded into standard French HR labels: `CDI` (permanent contract), `CDD` (fixed-term contract), `Travail temporaire` (interim), `Freelance`, `Stage`, and `Alternance`.

#### Can I scrape all latest APEC jobs without entering a keyword?

Yes. Leave `searchKeywords` empty (`[]`) and set your desired `maxTotalItems` (e.g., `500` or `1000`) along with `sortBy: "date"` to stream the newest executive job openings across all sectors in France.

#### Which export formats and integrations are supported?

You can export datasets to **JSON, CSV, Excel (XLSX), HTML, XML, or RSS**, or connect directly to **Google Sheets, Make, Zapier, n8n, Airbyte, Slack, HubSpot, and custom webhooks** via the Apify API.

#### Can I filter by contract type (`CDI`, `CDD`, `Alternance`) or department?

Every extracted record includes the decoded `contractType` field (`CDI`, `CDD`, `Travail temporaire`, `Freelance`, `Stage`, `Alternance`) and the `location` field with the 2-digit French department number (e.g., `Paris 08 - 75`, `Lyon - 69`). You can also include city or contract terms directly in `searchKeywords` (e.g., `"développeur Lyon"`, `"ingénieur CDI"`).

#### How does deduplication work when running multiple keywords?

The scraper maintains a global set of APEC offer numbers (`offerNumber`, e.g., `179444601W`) across the entire run. If the same job offer matches multiple keywords in `searchKeywords`, it is pushed to the dataset only once.

***

### 🔌 Integrations, scheduling & automation workflows

Connect the **APEC Jobs Scraper** to your existing HR, recruitment, or analytics stack in minutes:

| Integration | Workflow Example |
| :--- | :--- |
| **Google Sheets** | Automatically append newly published French cadre openings to a live Google Sheet every morning for recruitment teams. |
| **Make / Zapier / n8n** | Trigger automated workflows whenever a target company publishes a new `CDI` role above a specific salary band, routing leads to **HubSpot**, **Salesforce**, or **Pipedrive**. |
| **Slack & Microsoft Teams** | Send instant notifications to recruiter channels when new executive roles match high-priority keywords. |
| **Airbyte / BigQuery / Snowflake** | Schedule weekly bulk runs (`maxTotalItems: 2000`) to build historical compensation and hiring-velocity tables in your cloud data warehouse. |
| **Webhooks** | Configure an Apify `ACTOR.RUN.SUCCEEDED` webhook to notify your backend API as soon as a dataset is ready for ingestion. |

#### cURL REST API Example

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~apec-jobs-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchKeywords": ["développeur", "architecte cloud"],
    "sortBy": "date",
    "maxItemsPerSearch": 0,
    "maxTotalItems": 1000
  }'
```

***

### 🔗 Related scrapers

Build a comprehensive European & global recruitment intelligence pipeline by pairing this actor with:

- [XING Jobs Scraper](https://apify.com/haketa/xing-jobs-scraper) — DACH region jobs (Germany, Austria, Switzerland).
- [Arbeitnow Jobs Scraper](https://apify.com/haketa/arbeitnow-scraper) — European & remote tech job listings.
- [Seek Jobs Scraper](https://apify.com/haketa/seek-scraper) — Australia & New Zealand job listings.
- [ZipRecruiter Scraper](https://apify.com/haketa/ziprecruiter-scraper) — US job listings with salary and company data.
- [Bayt Jobs Scraper](https://apify.com/haketa/bayt-scraper) — MENA & Gulf region job board extractor.
- [GulfTalent Jobs Scraper](https://apify.com/haketa/gulftalent-jobs-scraper) — Middle East executive and professional jobs.

***

### 📋 Changelog

#### v1.2 (2026-11) — Deep 1,000+ Pagination Unlocked & Faster Prefill

- **Unlocked 1,000+ Pagination**: Changed `maxItemsPerSearch` default from `200` to `0` (unlimited per keyword, governed by `maxTotalItems` / `maxItems`) so single-keyword and multi-keyword runs scale seamlessly past 1,000+ jobs without per-keyword caps.
- **Fast Prefill Configuration**: Set `maxItemsPerSearch` prefill to `100` (1 page batch) for rapid `<15s` verification and low-cost trial runs, while preserving a 100-item default sample cap on completely empty inputs (`{}`).
- **Added `maxItems` Alias Support**: Added `maxItems` as a fallback alias for `maxTotalItems` for seamless compatibility with standard Apify workflows.
- **Documentation Upgrade**: Expanded README with `⚡ At a glance` summary, coverage indicators, French salary parsing tips, and changelog.

#### v1.1 (2026-10) — Session Resilience & Contract Mapping

- Improved session warm-up and automatic IP rotation on France residential proxies.
- Expanded contract type dictionary (`CDI`, `CDD`, `Travail temporaire`, `Freelance`, `Stage`, `Alternance`).

#### v1.0 (2026-08) — Initial Release

- Initial release of APEC Jobs Scraper with keyword search, 100-item page batching, salary extraction, and geo-coordinates.

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/apec-jobs-scraper/changelog.md

# Actor input Schema

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

Job keywords to search on APEC (e.g. développeur, chef de projet, data scientist). Each keyword is searched separately across all result pages. Leave empty to collect the latest cadre offers.

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

Order in which jobs are collected.

## `maxItemsPerSearch` (type: `integer`):

Maximum number of jobs to collect per keyword. Set to 0 for all available (governed by Max total jobs).

## `maxTotalItems` (type: `integer`):

Global cap across all keywords. Set 0 for no global cap (an empty run with no keywords defaults to a fast 100-job sample).

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

Proxy configuration. A France residential proxy is required (APEC is geo-locked) and enabled by default.

## Actor input object example

```json
{
  "searchKeywords": [
    "développeur",
    "chef de projet"
  ],
  "sortBy": "relevance",
  "maxItemsPerSearch": 100,
  "maxTotalItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}
```

# Actor output Schema

## `jobId` (type: `string`):

APEC internal job ID

## `offerNumber` (type: `string`):

APEC offer number (numeroOffre)

## `title` (type: `string`):

Job title

## `company` (type: `string`):

Hiring company (nom commercial)

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

Location text (city - department)

## `salary` (type: `string`):

Salary text (e.g. 34 - 48 k€ brut annuel)

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

Contract type (CDI, CDD...)

## `description` (type: `string`):

Job description text

## `datePublished` (type: `string`):

Publication date (ISO)

## `dateValidated` (type: `string`):

Validation date (ISO)

## `latitude` (type: `string`):

Latitude

## `longitude` (type: `string`):

Longitude

## `confidential` (type: `string`):

Whether the offer is confidential

## `remoteId` (type: `string`):

Teletravail (remote work) id

## `logo` (type: `string`):

Company logo URL

## `url` (type: `string`):

Job detail page URL

## `searchKeyword` (type: `string`):

Keyword used

## `scrapedAt` (type: `string`):

Extraction timestamp

# 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 = {
    "searchKeywords": [
        "développeur"
    ],
    "maxItemsPerSearch": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "FR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/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 = {
    "searchKeywords": ["développeur"],
    "maxItemsPerSearch": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "FR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/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 '{
  "searchKeywords": [
    "développeur"
  ],
  "maxItemsPerSearch": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}' |
apify call haketa/apec-jobs-scraper --silent --output-dataset

```

## MCP server setup

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