# APEC Jobs Scraper\[💰$0.75] - French Executive Jobs, Salaries (`corvuslab/apec-jobs-scraper`) Actor

Scrape apec.fr, France's job board for cadres, executives and engineers, with every site filter: places + radius, salary range, full advert, skills with level, recruiter contact, first-publication date and every APEC code as a readable label next to its id. Incremental monitoring + alerts.

- **URL**: https://apify.com/corvuslab/apec-jobs-scraper.md
- **Developed by:** [Corvuslab](https://apify.com/corvuslab) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does APEC Jobs Scraper do?

**APEC Jobs Scraper** extracts job offers from **apec.fr**, France's job board for cadres (executives, managers and engineers), which carries around **110,000 live offers**. It supports **every filter apec.fr's own search has** and returns the **full advert** in **77 structured fields**: salary range, contract, remote-work level, skills with their required level, the named recruiter contact, the real first-publication date, and APEC's sector, NAF industry, job role and job function. Every APEC code arrives as a **readable French label next to its raw APEC id**. You can filter on the labels in a spreadsheet and still join on stable ids.

Enter keywords, places and filters, or paste apec.fr search and offer URLs, and get every matching offer as a clean record in JSON, CSV, Excel, through the API or as compact output for AI agents. No APEC account or login is needed.

> New to Apify? Sign up free and use the included monthly platform credit to try this Actor. No credit card needed.

***

### What data can you extract from apec.fr?

A standard record has **77 fields**. Incremental mode adds 8 change-tracking fields.

| Group | Fields |
|---|---|
| **Offer & employer** | `title`, `company`, `companyBrand`, `companyLegalName`, `companyId`, `companyLogo`, `isConfidential`, `url`, `id`, `offerId`, `employerReference` |
| **Salary & contract** | `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryNegotiable`, `contractType`, `contractDurationMonths`, `partTime`, `remoteWork`, `startDate`, `numberOfPositions`, `travelZone` |
| **APEC classification**: each a label plus its `…Id` | `sector`, `industry` (NAF), `experienceLevel`, `jobRole`, `jobFunction`, `contractType`, `remoteWork`, `positionType`, `travelZone`, `educationLevel`, `postingOrigin` |
| **Full advert** | `jobDescription`, `candidateProfile`, `companyDescription`, `recruitmentProcess`, the whole advert as `description` (plain text), `descriptionHtml` and `descriptionMarkdown`, `skills`, `skillDetails` (hard/soft/language, with level), `snippet` |
| **Place, recruiter & apply** | `location`, `department`, `region`, `latitude`, `longitude`, `contactName`, `contactTitle`, `applyUrl`, `applyMethod`, and the posting company's address (`companyStreetAddress`, `companyPostalCode`, `companyCity`) |
| **Freshness & signals** | `postedAt`, `firstPublishedAt`, `isRepublished`, `updatedAt`, `isPartnerListing`, `lowApplicantCount`, `qualityChecked`, `scrapedAt` |
| **Monitoring** (incremental mode) | `changeType` (NEW / UPDATED / REAPPEARED / UNCHANGED / EXPIRED), `isRepost`, `repostOfId`, `repostDetectedAt`, `firstSeenAt`, `lastSeenAt`, `previousSeenAt`, `expiredAt` |

***

### Key features

- 🎚️ **Every apec.fr filter, applied on apec.fr.** Contract type and length, experience, posting age, remote work, salary band in k€, employer type, position status, 29 sectors, 56 job functions and ~450 job roles. You are never charged for offers your filters leave out.
- 🙅 **Extra filters apec.fr doesn't have.** Exclude title words ("stage", "junior"), exclude companies or agencies, and keep only offers that show a salary. Offers left out are never charged.
- 🏷️ **Every APEC code decoded.** 11 classifications come as a readable label **and** the raw APEC id, so you get readable tables and stable join keys from the same record.
- 📍 **Places the way you'd type them.** "Lyon", "Paris 15", "Rhône", "75", "2A", "Bretagne", "Allemagne". Add a **radius of up to 200 km** around any town.
- 🚫 **Partner-board resales left out at the source.** About two in five apec.fr offers are imported from other job boards, often under the board's name. One switch leaves them out before they are read, and they are never charged.
- 🕰️ **The real age of an offer.** `firstPublishedAt` and `isRepublished` show which offers were quietly republished to look fresh. Repost detection catches offers deleted and posted again under a new number.
- 👤 **Named recruiter contact.** The contact's name, and their job title when the advert gives one.
- ♻️ **Incremental monitoring and alerts.** Only new and changed offers are emitted and charged. Alerts go to Telegram, Slack, Discord or any webhook.
- 🤖 **Compact mode for AI agents.** 16 core fields per offer, with optional dropping of empty fields.

***

### 🚀 How to scrape apec.fr

1. Enter one or more **keywords** (e.g. `data engineer`) and **places** (e.g. `Lyon`), then pick filters. Or paste apec.fr URLs into **Start URLs**.
2. Set **Max results** (0 = every matching offer) and keep **Fetch the full advert** on for the rich fields.
3. Optionally, turn on **incremental mode** and a **notification** channel, then **Schedule** the run.
4. Click **Start**, then download the results as JSON, CSV or Excel or pull them from the API.

#### Quick-start example input

```json
{
  "searchTerms": ["data engineer"],
  "locations": ["Lyon"],
  "radiusKm": 30,
  "contractTypes": ["permanent"],
  "excludePartnerListings": true,
  "maxResults": 100
}
```

This returns up to 100 permanent (CDI) data-engineering offers within 30 km of Lyon, newest first, without partner-board resales. Each one has its full advert, salary range, skills and recruiter contact.

***

### Input

There are **44 inputs**, grouped as in the editor. All of them are optional: an empty run returns the 25 newest offers.

#### 🔎 Search

| Field | What it does |
|---|---|
| `searchTerms` | Keywords as you'd type them on apec.fr. Each one runs as its own search. |
| `locations` | Towns, "Paris 15", departments ("75", "Rhône", "2A"), regions ("Bretagne") or countries ("Allemagne"). Empty = France and abroad. |
| `radiusKm` | Widen each town to everything within 0–200 km. |
| `startUrls` | apec.fr search URLs (their filters are used as-is) or offer URLs. Offer URLs are read first. |
| `maxResults` | Cap on offers delivered across all searches (default 25; 0 = no limit). |
| `sortBy` | `date` (newest first, best for monitoring) or `relevance`. |

#### 🎚️ Filters

| Field | What it does |
|---|---|
| `contractTypes` | `permanent` (CDI), `fixedTerm` (CDD), `workStudy` (alternance), `temporary` (intérim), `internship` (stage). |
| `contractDuration` | CDD / intérim length: `1to6`, `7to12` or `13plus` months. |
| `experienceLevels` | `entry` (débutant), `3to5`, `6to9`, `10plus` years. |
| `postedWithin` | `24h`, `7d` or `30d`. |
| `remoteWork` | `occasional`, `partial` (hybrid) or `full`. |
| `minSalaryK` / `maxSalaryK` | Salary band in k€ gross per year. Offers whose range overlaps it are kept. |
| `employerTypes` | `company`, `recruitmentAgency`, `staffingAgency`, `itServices` (ESN), `partner`. |
| `excludePartnerListings` | Leave out offers resold by partner job boards. |
| `excludeKeywords` / `excludeCompanies` | Leave out offers whose title or company contains any of these. |
| `requireSalary` | Keep only offers that publish a salary. |
| `positionStatus` | `privateSector`, `publicSector`, `supervisorTechnician`. |
| `sectors` / `jobFunctions` / `jobRoles` | APEC's 29 sectors, 56 job functions, and ~450 job roles by name (e.g. "Data scientist"). |

#### 📄 Output, ♻️ monitoring, 🔔 notifications and ⚙️ advanced

| Field | What it does |
|---|---|
| `includeDetails` | Fetch the full advert (on by default). Turn it off for the fastest runs, with search-result fields only. |
| `descriptionFormat` / `descriptionMaxLength` | `all`, `text`, `html` or `markdown`, optionally cut to N characters. |
| `compact` / `excludeEmptyFields` | 16 core fields only, and/or drop empty fields. |
| `incrementalMode`, `stateKey` | Emit only what changed since the last run of the same search. |
| `emitUnchanged` / `emitExpired` / `skipReposts` | Also emit unchanged or expired offers, or leave out reposts. |
| `telegramToken` + `telegramChatId`, `slackWebhookUrl`, `discordWebhookUrl`, `webhookUrl` + `webhookHeaders` | Alert channels. Credentials are secret inputs: encrypted, masked and never logged. |
| `notificationLimit` / `notifyOnlyChanges` | Offers listed per chat message, and alerts on new, updated or reappeared offers only. |
| `proxyConfiguration`, `detailConcurrency`, `maxRequestRetries`, `ignoreUrlFailures` | Connection settings. Keep the defaults. |

#### More example inputs

Senior finance roles in Paris and the Hauts-de-Seine, salary shown, no interim missions:

```json
{
  "searchTerms": ["contrôleur de gestion", "directeur financier"],
  "locations": ["75", "92"],
  "experienceLevels": ["6to9", "10plus"],
  "minSalaryK": 60,
  "requireSalary": true,
  "excludeKeywords": ["intérim"],
  "maxResults": 0
}
```

A daily watch on IT offers in Brittany, with Slack alerts on changes only:

```json
{
  "locations": ["Bretagne"],
  "jobFunctions": ["101833"],
  "incrementalMode": true,
  "notifyOnlyChanges": true,
  "slackWebhookUrl": "https://hooks.slack.com/services/...",
  "maxResults": 0
}
```

***

### Output

Each dataset item is one apec.fr offer. Here is a real record, trimmed for length:

```json
{
  "id": "179395587W",
  "title": "Architecte Data F/H",
  "company": "IPPON Technologies",
  "url": "https://www.apec.fr/candidat/recherche-emploi.html/emploi/detail-offre/179395587W",
  "location": "Marseille 01 - 13",
  "department": "13",
  "region": "PACA",
  "latitude": 43.2999856,
  "longitude": 5.3827158,
  "salaryText": "65 - 70 k€ brut annuel",
  "salaryMin": 65000,
  "salaryMax": 70000,
  "salaryPeriod": "year",
  "contractType": "CDI",
  "contractTypeId": 101888,
  "remoteWork": "Télétravail partiel possible",
  "remoteWorkId": 20765,
  "sector": "Activités informatiques",
  "sectorId": 101753,
  "industry": "CONSEIL EN SYSTÈMES ET LOGICIELS INFORMATIQUES",
  "industryId": 101569,
  "experienceLevel": "Minimum 10 ans",
  "jobRole": "Architecte Big Data",
  "jobRoleId": 600072,
  "jobFunction": "Système, réseaux, données",
  "positionType": "Cadre du secteur privé",
  "positionTypeId": 101900,
  "isPartnerListing": false,
  "qualityChecked": true,
  "postedAt": "2026-10-14T03:38:09+00:00",
  "firstPublishedAt": "2026-09-09T17:03:20+00:00",
  "isRepublished": true,
  "skills": ["Snowflake", "Apache Kafka", "Spark", "Python", "Scala", "SQL"],
  "skillDetails": [
    { "name": "Snowflake", "kind": "hardSkill", "level": "Confirmé" },
    { "name": "Curiosité", "kind": "softSkill", "level": null }
  ],
  "candidateProfile": "Vous êtes de tempérament curieux, force de proposition…",
  "companyLegalName": "IPPON TECHNOLOGIES",
  "companyCity": "PARIS 16",
  "contactName": "Alexis Cohen",
  "applyUrl": "https://www.jobposting.pro/emploi-2694530-113#postuler",
  "applyMethod": "URL_ONLY",
  "scrapedAt": "2026-10-23T11:20:56.445070+00:00"
}
```

The offer shows as published on 14 October, but `firstPublishedAt` shows it has been on apec.fr since 9 September. Missing values are `null` in standard mode. **Compact mode** keeps 16 core fields. The Output tab includes an **Overview** table with title, company, place, contract, salary, remote work, experience, date and a link to the offer.

***

### ♻️ How to monitor apec.fr with incremental mode

Schedule the Actor with **incremental mode** on. Each run compares against the previous run of the same search and emits only **NEW**, **UPDATED** and **REAPPEARED** offers, plus **EXPIRED** ones if you ask. Unchanged offers are recognised from the search results *before* their advert is read, so they cost nothing.

| Daily churn (of 1,000 tracked offers) | Billable records | You save |
|---|---|---|
| 5 % | 50 | **95 %** |
| 15 % | 150 | **85 %** |
| 30 % | 300 | **70 %** |

1. Set your keywords, places and filters, and keep **Sort by** on newest first.
2. Turn on **Incremental mode** and run once to record the baseline.
3. Add a **Schedule** (e.g. every morning), plus an alert channel with **Alert only on changes** on.
4. To catch offers that close, turn on **Include expired offers** and set **Max results** to 0 so each run reads the whole search.

***

### 🔔 How to set up apec.fr alerts

| Channel | What to fill in |
|---|---|
| ✈️ Telegram | `telegramToken` (from @BotFather) + `telegramChatId` |
| 💬 Slack | `slackWebhookUrl` |
| 🎮 Discord | `discordWebhookUrl` |
| 🪝 Webhook | `webhookUrl`: structured JSON with every matched offer, for n8n, Make or Zapier |

Each channel works independently, so one broken channel never stops the scrape or the others.

***

### 💡 What can you do with apec.fr data?

#### Executive recruitment and headhunting

See which companies are hiring cadres, for which roles, where and at what salary. The named recruiter contact gives you the hiring side.

#### B2B lead generation

A company posting five data roles has a budget and a need. Build prospect lists from company, legal name, NAF industry and address, with direct employers only.

#### Salary benchmarking for French managers

About 60 % of offers publish a salary range, parsed into numeric min and max. Slice it by job role, experience, region and contract type.

#### Labour-market and skills research

Track skill demand, remote-work adoption and contract mix across sectors and regions. Stable APEC ids keep a time series clean even when label wording changes.

#### Job-search automation and AI pipelines

Watch a precise search and get a Telegram message when a fresh offer lands, or feed compact JSON into an LLM, MCP tool or vector store.

***

### 💰 How much does it cost to scrape apec.fr?

This Actor uses **pay-per-event** pricing: a small fee per run plus a fee per offer in your dataset. The **Pricing** tab shows the current rates. Offers you never receive are never charged. That covers offers left out by your filters, partner resales you excluded and unchanged offers in incremental mode. If you only need titles, companies, places, salaries and dates, turn off the full advert for the fastest runs.

***

### 🔌 Integrations & export

Export to **JSON, CSV, Excel** or HTML, or use the **REST API** and the JavaScript and Python clients. Schedule runs, connect **Google Sheets, Slack, Make, Zapier or n8n**, or call the Actor as an **MCP tool** from an AI agent.

For the broader French job market, see **HelloWork Jobs Scraper** (`corvuslab/hellowork-scraper`).

***

### 🔗 Using the API

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("corvuslab/apec-jobs-scraper").call(run_input={
    "searchTerms": ["chef de projet informatique"],
    "locations": ["Ile-de-France"],
    "contractTypes": ["permanent"],
    "maxResults": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["company"], item["salaryText"], item["url"])
```

***

### ❓ FAQ

**How many offers can I get?** The whole board if you want it: set `maxResults` to 0. Search depth isn't capped, so a broad search reads every matching offer. Duplicates across keywords and places are removed.

**Why is `salaryMin` empty on some offers?** About 60 % of offers publish a salary range. The rest say "A négocier" (`salaryNegotiable: true`) or "Non renseignée". apec.fr's salary filter keeps the negotiable ones. Add `requireSalary` to drop them.

**What is a partner offer?** An offer apec.fr imports from another job board. Its company is often the board's name rather than the real employer. `isPartnerListing` flags these offers, and `excludePartnerListings` leaves them out at the source.

**Is the address where the job is?** No. `location`, `department`, `region` and the coordinates give the job's place. `companyStreetAddress`, `companyPostalCode` and `companyCity` are the address of the account that posted the offer, such as a head office or a recruitment agency, and it is often in another town.

**Why do some offers have no apply link?** About half send candidates to an external page (`applyUrl`). The rest are applied to on apec.fr, and `applyMethod` says which. APEC adverts carry no recruiter e-mail or phone number, so none are returned.

**What's the difference between `postedAt` and `firstPublishedAt`?** `postedAt` is the date apec.fr shows, which employers can refresh to move an offer back to the top. `firstPublishedAt` is when the offer first appeared, and `isRepublished` flags the refreshed ones.

**Which fields are often empty?** Remote work is on about half of offers. Contract length is set only on non-CDI contracts. Education level appears mainly on internships and work-study offers. Start date and recruitment process appear on a small minority.

**Can I search outside France?** Yes. Type a country (e.g. "Allemagne") in Places, or leave Places empty for France and abroad together.

***

### ⚖️ Is it legal to scrape apec.fr?

This Actor collects only **publicly available** job offers. You're responsible for how you use the data, in particular personal information such as recruiter names, and for complying with apec.fr's terms and applicable law, including the GDPR. This Actor is not affiliated with, endorsed by or sponsored by APEC (Association pour l'emploi des cadres).

***

**Keywords:** apec scraper · apec.fr scraper · apec jobs scraper · apec api · scrape apec.fr · French executive jobs · cadre jobs France · emploi cadre · France job scraper · salary benchmarking France · recruiter contact · job monitoring · lead generation · export to CSV · export to Excel · no-code scraper · MCP tool for AI agents

# Changelog

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

# Actor input Schema

## `searchTerms` (type: `array`):

What to search for, as you would type it on apec.fr: a job title, a skill or a company (e.g. "data engineer", "chef de projet", "contrôleur de gestion"). Each keyword runs as its own search. Leave empty to get every live offer, newest first.

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

Towns, departments, regions or countries, as you would type them: "Lyon", "Paris 15", "Rhône", "75", "Bretagne", "Ile-de-France", "Allemagne". Several places are searched together. Leave empty for all of France and abroad.

## `radiusKm` (type: `integer`):

Widen each town in Places to everything within this distance. Applies to towns only (not departments or regions). 0 = the town itself.

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

Optional. Paste apec.fr search URLs (their filters are used as is) or offer URLs (…/detail-offre/179641876W). Search URLs replace the search form above.

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

Maximum number of offers to return across all searches. Set 0 for no limit (every matching offer).

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

Order in which offers are read. Newest first suits monitoring; most relevant matches apec.fr's default for keyword searches.

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

Keep only these contract types.

## `contractDuration` (type: `string`):

Length of fixed-term and interim contracts.

## `experienceLevels` (type: `array`):

Experience the offer asks for.

## `postedWithin` (type: `string`):

Only offers published (or re-published) in this window.

## `remoteWork` (type: `array`):

Keep only offers that allow this remote-work level.

## `minSalaryK` (type: `integer`):

APEC's own salary filter, in thousands of euros gross per year (e.g. 50). An offer is kept when its published range overlaps yours; offers 'à négocier' stay in.

## `maxSalaryK` (type: `integer`):

Upper bound of the salary filter, in thousands of euros gross per year.

## `employerTypes` (type: `array`):

Who posted the offer. Empty = all five types (the whole board).

## `excludePartnerListings` (type: `boolean`):

Leave out offers APEC imports from other job boards (their company is often the board's name). Skipped offers are not charged.

## `excludeKeywords` (type: `array`):

Leave out offers whose title contains any of these words, e.g. "stage", "alternance", "junior". Case and accents are ignored. Left-out offers are not charged.

## `excludeCompanies` (type: `array`):

Leave out offers from these companies or agencies (the name only has to contain what you type). Left-out offers are not charged.

## `requireSalary` (type: `boolean`):

Leave out offers with no published salary ("A négocier", "Non renseignée"). Left-out offers are not charged.

## `positionStatus` (type: `array`):

Status of the position.

## `sectors` (type: `array`):

Business sector of the employer.

## `jobFunctions` (type: `array`):

APEC's job functions (▸ = a whole family).

## `jobRoles` (type: `array`):

Any of APEC's ~450 job roles by name, e.g. "Data scientist", "Contrôleur de gestion", "Chef de projet informatique". Unknown names are skipped with a warning.

## `includeDetails` (type: `boolean`):

Add the full advert (job, candidate profile, company), skills, apply link, first publication date, experience, job role and function, company address and contact name. Turn off for the fastest, search-results-only runs.

## `descriptionFormat` (type: `string`):

Which representation(s) of the full advert to include.

## `descriptionMaxLength` (type: `integer`):

Cut descriptions to this many characters. 0 = full length.

## `compact` (type: `boolean`):

Emit only the core fields (title, company, place, contract, salary, link). Ideal for AI agents and MCP clients.

## `excludeEmptyFields` (type: `boolean`):

Remove null, empty-string and empty-list fields from each record.

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

Track offers between runs and tag every record NEW / UPDATED / UNCHANGED / EXPIRED. Unchanged offers are skipped and not charged.

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

Stable name for the tracked search. Leave empty to derive one automatically from your search settings.

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

Also emit offers that have not changed since the previous run.

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

Emit offers that were open last run but are gone now. Needs a run that reads the whole search (Max results 0 or above the number of matches).

## `skipReposts` (type: `boolean`):

Leave out offers an employer took down and posted again under a new number (same title, company and place as an offer already tracked). They are not charged. Every new offer still carries isRepost either way.

## `telegramToken` (type: `string`):

Bot token from @BotFather.

## `telegramChatId` (type: `string`):

Chat or channel ID, e.g. "-100123456789" or "@yourchannel".

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL.

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL.

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

Any HTTPS endpoint. Receives a JSON POST with every matched offer (up to 1,000 per run) — works with n8n, Make and Zapier.

## `webhookHeaders` (type: `object`):

Extra headers for the webhook request, e.g. {"Authorization": "Bearer xyz"}. Stored encrypted, like the other credentials.

## `notificationLimit` (type: `integer`):

How many offers to list in each Telegram, Slack or Discord message. The webhook always gets every matched offer.

## `notifyOnlyChanges` (type: `boolean`):

In incremental mode, alerts list only new, updated and reappeared offers, even when Include unchanged offers is on.

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

APEC only answers visitors from France. Keep the default proxy settings for reliable runs.

## `detailConcurrency` (type: `integer`):

How many full adverts to read at the same time.

## `ignoreUrlFailures` (type: `boolean`):

Skip start URLs that cannot be interpreted instead of failing the whole run.

## `maxRequestRetries` (type: `integer`):

How many times to retry a refused or failed request (each retry uses a fresh connection).

## Actor input object example

```json
{
  "searchTerms": [
    "data engineer"
  ],
  "maxResults": 25,
  "sortBy": "date",
  "excludePartnerListings": false,
  "requireSalary": false,
  "includeDetails": true,
  "descriptionFormat": "all",
  "descriptionMaxLength": 0,
  "compact": false,
  "excludeEmptyFields": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "notificationLimit": 5,
  "notifyOnlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  },
  "detailConcurrency": 6,
  "ignoreUrlFailures": true,
  "maxRequestRetries": 6
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `allItems` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "data engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("corvuslab/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 = { "searchTerms": ["data engineer"] }

# Run the Actor and wait for it to finish
run = client.actor("corvuslab/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 '{
  "searchTerms": [
    "data engineer"
  ]
}' |
apify call corvuslab/apec-jobs-scraper --silent --output-dataset

```

## MCP server setup

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