# Hiring Companies Scraper: Who's Hiring + Decision-Maker (`dltik/hiring-companies-scraper`) Actor

Find companies hiring across 6 French job boards at once (France Travail, Indeed, HelloWork, WTJ, JobTeaser, APEC), deduplicated to one lead per company with the decision-maker, LinkedIn, email, revenue, open roles and a hard-to-fill score. For recruiters and B2B sales. $0.02/company.

- **URL**: https://apify.com/dltik/hiring-companies-scraper.md
- **Developed by:** [Walid](https://apify.com/dltik) (community)
- **Categories:** Business, Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 hiring company (deduplicated + scored)s

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?

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

## Hiring Companies Scraper: Find Companies That Are Hiring

**⭐ Bookmark this actor** — the Apify Store ranks actors by bookmarks, so it's the single strongest signal to keep this Hiring Companies Scraper visible and maintained.

Find **companies that are hiring** across **France Travail + Indeed + HelloWork + Welcome to the Jungle + JobTeaser + APEC** in a single run. Unlike a raw job scraper, this actor **deduplicates the same company across boards** (keyed on its **SIREN**, not a fuzzy name), enriches it with **company size / sector / status**, and scores **how long and how hard** each company has been hiring — so you get one clean **hiring lead per company**, sorted with the most motivated employers first. Turn on **watch mode** and it becomes a recurring hiring-signal feed that tracks how long each company stays open.

### What it does

Raw job scrapers give you thousands of duplicate listings. This one turns that noise into a prospect list:

- **Aggregates 6 boards** — France Travail, Indeed, HelloWork, Welcome to the Jungle, JobTeaser and APEC (French cadre/executive board) at once.
- **Watch mode** — persists the first time each company was seen hiring, so recurring runs surface *how long* a role has stayed open (the strongest hard-to-fill signal) and emit only new/hardest companies.
- **Deduplicates by SIREN** — "ACME SAS" on Indeed and "Acme" on France Travail merge into one record for the legal entity, with all their open roles and listings.
- **Company intelligence** — each lead is resolved to its SIREN with legal name, size (headcount), sector (NAF), category (PME/ETI/GE), **age and latest revenue** (turnover + net income, when filed) and active/ceased status — so you can qualify a healthy, growing employer at a glance.
- **Decision-maker + LinkedIn** — the person to contact (Président / Directeur général / Gérant) with name, role, a **LinkedIn people-search deep-link** (one click to reach them), HQ city, and an optional MX-verified email guess.
- **Career page (ATS)** — optionally match each company to its own Greenhouse / Lever / Ashby / SmartRecruiters / Recruitee / Teamtailor board: which ATS, its **total open-roles count** (a strong scaling signal), and the direct careers URL.
- **Hard-to-fill signal** — a 0–100 score built from days-open, how many boards the company is posting on, and repost depth. The recruitment analogue of a property's days-on-market: long-open + cross-posted = a motivated employer.
- **Client-direct filter** — optionally exclude staffing/temp agencies to keep only end-employers hiring directly.
- **Reverse-sourcing (AI)** — optionally reveal the END CLIENT behind a staffing-agency or ESN posting ("Développeur pour notre client, un leader de l'assurance"), named when disclosed and resolved to its SIREN. Turns an intermediary posting into a named account.

### Who uses it

- **Recruitment & staffing agencies** — a "pige" feed of companies actively hiring for a role, ranked by how hard the role is to fill (their highest-margin work).
- **B2B sales teams** — hiring is a buying/intent signal: a company scaling a team is growing and buying tools.
- **Market & competitive intelligence** — track who is hiring for what, where.

### Input

```json
{
  "keywords": "developpeur",
  "location": "Paris",
  "sources": ["francetravail", "indeed", "hellowork"],
  "clientDirectOnly": true,
  "maxLeads": 100
}
```

| Field | Type | Description |
|---|---|---|
| `keywords` | string | Role/skill to find companies hiring for (required). |
| `location` | string | City (Indeed/HelloWork) or France Travail code (`75D`, `75001`). Empty = national. |
| `sources` | array | Boards to aggregate. Default: all three. |
| `maxResultsPerSource` | int | Listings pulled per board before dedup (default 25). |
| `clientDirectOnly` | bool | Exclude staffing agencies. |
| `maxLeads` | int | Max hiring companies returned. |
| `watchMode` + `stateKey` | bool + string | Track companies across runs; `days_tracked` = true hiring-need age. |

### Output

One record per hiring company:

```json
{
  "company": "ACME TECHNOLOGIES SAS",
  "siren": "812345678",
  "decision_maker": "Marie Dupont",
  "decision_maker_role": "Directrice générale",
  "decision_maker_email": "marie.dupont@acme.fr",
  "decision_maker_linkedin": "https://www.linkedin.com/search/results/people/?keywords=Marie%20Dupont%20ACME",
  "ats": "lever",
  "ats_open_roles": 23,
  "careers_url": "https://jobs.lever.co/acme",
  "end_client": null,
  "end_client_siren": null,
  "email_status": "unverified guess (MX-valid domain; SMTP-verified when the network allows it)",
  "hq_city": "NANTES",
  "top_role": "Développeur Fullstack (H/F)",
  "roles": ["Développeur Fullstack (H/F)", "Développeur Backend (H/F)"],
  "listings_count": 4,
  "boards": ["francetravail", "indeed"],
  "seen_on_n_boards": 2,
  "days_open": 63,
  "reposted": true,
  "hard_to_fill_score": 81,
  "is_staffing_agency": false,
  "company_data": { "employee_range": "50-99", "sector": "...", "is_active": true },
  "locations": ["Paris"],
  "listings": [ { "source": "indeed", "title": "...", "url": "..." } ]
}
```

### Pricing

| Event | Price | What you get |
|---|---|---|
| `hiring-lead` | **$0.02** | One deduplicated hiring company: SIREN + size/sector, **decision-maker (name + role)** + HQ, open roles across all boards, days-open, cross-post breadth and the hard-to-fill score. Everything included. |
| `contact-found` | +$0.02 | Optional (`enrichContact`): a professional email for the decision-maker, from the company's MX-verified domain + `prenom.nom` pattern (with alternates). Billed only for leads that get an email. |
| `reverse-sourced` | +$0.02 | Optional (`enrichReverse`, paid plans): AI reveals the end client behind an agency/ESN posting (named + SIREN when disclosed). Billed per intermediary lead processed. |

### FAQ

**How is this different from an Indeed or LinkedIn jobs scraper?** Those return raw listings from one board. This aggregates several boards, collapses duplicates to one lead **per company** using its SIREN, adds company data, and scores hiring urgency — a prospect list, not a listing dump.

**Do I need any API keys?** No. Company resolution uses the free official French company register.

**What is the hard-to-fill score?** A 0–100 estimate of how motivated the employer is, from how long the role has been open, how many boards it's posted on, and how often it's reposted. Higher = a company struggling to fill it (a recruiter's best lead).

**Can I get only companies hiring directly (not agencies)?** Yes — turn on `clientDirectOnly`.

# Actor input Schema

## `keywords` (type: `string`):

The role/skill to find companies hiring for. Examples: 'developpeur', 'commercial', 'infirmier', 'data engineer'. Required.

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

Optional. A city name (used by Indeed/HelloWork), or a France Travail department/INSEE code like '75D' or '75001'. Leave empty to search nationally (France).

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

Which boards to search and merge. Default: all three. More sources = better dedup signal (a company hiring on several boards scores higher).

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

How many listings to pull from EACH board before dedup. 25 is a good default; raise for broader coverage of a role.

## `enrichContact` (type: `boolean`):

When ON, finds a professional email for each lead's decision-maker: derives the company's mailing domain (MX-verified via DNS) and applies the standard prenom.nom@domain pattern, with alternates. The domain is verified; the exact address is a high-probability guess. Billed as 'contact-found' only for leads that get an email.

## `enrichATS` (type: `boolean`):

When ON, matches each company to its own Applicant Tracking System board (Greenhouse, Lever or Ashby) and attaches which ATS it uses, its TOTAL open-roles count (a strong scaling signal), and the direct careers URL. Free (public ATS APIs). A high open-roles count boosts the hard-to-fill score.

## `enrichReverse` (type: `boolean`):

When ON, for intermediary leads (staffing agencies, ESN) an AI reads the posting text and extracts the END CLIENT the role is really for — named when disclosed, else a precise description (sector/size). Turns an agency posting into a named account. Requires a paid Apify plan. Billed as 'reverse-sourced' per intermediary lead processed.

## `clientDirectOnly` (type: `boolean`):

When ON, drops recruitment/temp agencies and consultancies (NAF 78.xx + known agency names) so you only get END-employers hiring directly — what recruiters prospecting for new clients want.

## `maxLeads` (type: `integer`):

Maximum number of deduplicated hiring companies to return (billing is per hiring lead). Results are sorted by hard-to-fill score, so the most motivated employers come first.

## `watchMode` (type: `boolean`):

When ON, remembers every company seen on previous runs (per stateKey) and records the FIRST time it was seen hiring. On recurring runs, 'days\_tracked' reflects the true age of the hiring need and the hard-to-fill score rises for companies still open after weeks — turning the actor into a daily/weekly hiring-signal feed. By default only NEW companies + high-score still-open ones are emitted.

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

Namespace for the watch baseline, so several saved searches (different roles/cities) keep separate histories under one actor. Any short string, e.g. 'dev-paris'. Defaults to 'default'.

## `includeUnchanged` (type: `boolean`):

When watchMode is ON, also emit every still-open company (not just NEW + high-score). Leave OFF to receive mainly the delta + the hardest-to-fill.

## Actor input object example

```json
{
  "sources": [
    "francetravail",
    "indeed",
    "hellowork",
    "wtj",
    "jobteaser",
    "apec"
  ],
  "maxResultsPerSource": 25,
  "enrichContact": false,
  "enrichATS": false,
  "enrichReverse": false,
  "clientDirectOnly": false,
  "maxLeads": 100,
  "watchMode": false,
  "includeUnchanged": false
}
```

# Actor output Schema

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

One deduplicated hiring company per record.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("dltik/hiring-companies-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("dltik/hiring-companies-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 '{}' |
apify call dltik/hiring-companies-scraper --silent --output-dataset

```

## MCP server setup

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