# Qualibat · RGE Companies & Emails (`corent1robert/qualibat-entreprises`) Actor

Export Qualibat-labelled BTP firms: SIRET, phone, email from the certificate PDF, RGE work categories, directors, founded date, size. No official API. $4/1k. Empty shells not billed.

- **URL**: https://apify.com/corent1robert/qualibat-entreprises.md
- **Developed by:** [Corentin Robert](https://apify.com/corent1robert) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.66 / 1,000 directory company (fiche + pdf)s

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

### What does Qualibat Entreprises do?

Reads the public [Qualibat company directory](https://www.qualibat.com/annuaire-entreprises-qualifiees) and writes **one row per labelled firm**. There is **no official Qualibat API**.

You get the **SIRET**, the **phone** on the fiche, **email / website / mobile** from the official Qualibat **certificate PDF** (text layer, not OCR), **RGE work categories** (chaudières, VMC, ITE…), **directors**, **founded date**, workforce / CA bands, and the qualification codes.

This is **not** a dump of every French BTP company, and it is **not** the ADEME / France Rénov RGE list ([RGE SIREN enrich](https://apify.com/corent1robert/rge-siren-enrich)). Qualibat is the **qualification directory**. ADEME is the **RGE register**. Use both if you need both signals.

### Who is this for?

This is for you if you sell **into labelled BTP** and you need the **firm**, not a screenshot of the map.

- **CRM / outbound for artisans** — SIRET + phone + **email** + directeur, sliced by département and a trade keyword (`PLOMBERIE`, `PHOTOVOLTAIQUE`).
- **Renovation marketplaces / MaPrimeRénov aggregators** — keep **RGE only**, keep the **RGE work categories** from the certificate (not just the badge).
- **Insurers / courtage BTP** — labelled firms with a public phone, age, capital, not a raw SIRENE dump.
- **Clay / Lemlist / HubSpot** — one SIRET, one phone, one email, one city, one ICP slice. No logos, no map tiles, no PDF bodies.

Do not pick **None** on the département list hoping to paginate France. Qualibat **caps the public list at 50** until you set a département (or a city / postcode). Use **All of France** (Advanced) to bypass that cap.

Schedule the same search weekly with **Only new companies** so you do not pay twice for the same Qualibat id.

### Why scrape Qualibat companies?

- Turn a directory slice into a **call file** without opening 26 “Voir la fiche” tabs
- Keep the **phone** Qualibat already publishes (`data-url` is base64 `+33…`, `data-content` is `04 28 29 95 90`)
- Keep **SIRET / SIREN / dirigeant / effectif / CA** from the same fiche
- Keep **email / website / 06** from the official certificate PDF (`dq_…` / `dq_rge_…`). The fiche has no mailto — the PDF does.
- Keep **RGE work categories** (chaudières, VMC, ITE), **dates**, **PROB**, **capital / CA tranche**, **company age** — the ICP slice, not just a phone.

On Apify you can **schedule** runs, download **JSON / CSV / Excel**, and push to Sheets, Make, n8n or Clay.

### What data can this Qualibat scraper extract?

| Field | Description |
|---|---|
| `companyId`, `name`, `profileUrl` | Qualibat fiche (`/entreprises/{id}-{slug}`) |
| `siret`, `siren` | Establishment + company ids |
| `phone`, `phoneNational` | E.164 + national format from the obfuscated tel |
| `email`, `emails[]`, `website` | From the certificate PDF text layer |
| `phoneMobile`, `fax`, `nace`, `legalForm` | Certificate PDF |
| `certificateNumber`, `certificateIssuedAt`, `certificateValidUntil` | e.g. `E-E136694`, issued / valid until |
| `isRge`, `rgeQualifications[]`, `rgeCertificateUrl` | RGE badge, RGE codes, RGE PDF |
| `rgeCategories[]` | **Travaux RGE couverts** (chaudières, VMC, ITE…) with `attributedAt` |
| `qualifications[]`, `certificateUrl` | Métier codes + `attributedAt` / `isProb` / `level` when the PDF has them |
| `address`, `postcode`, `city`, `lat`, `lng` | Card + fiche |
| `directors`, `directorNames[]` | Fiche line + clean names from the PDF |
| `workforce`, `workforceBand`, `revenueEur`, `revenueBand`, `capitalEur` | Size: effectif, CA, capital, Qualibat tranches (EFF2A / CA6) |
| `foundedAt`, `legalFormSince`, `compliantUntil` | Company age, current forme juridique since, *A jour au* |
| `hasProbation`, `qualificationCount` | PROB (2-year) flag + how many quals |
| `sourceQuery`, `sourceLocation`, `scrapedAt` | How the slice was built |

Not extracted: ADEME RGE ids, map tiles, insurance policy numbers, certificate PDF bytes (we parse the text, we do not store the file).

### How to scrape Qualibat labelled companies

1. Open this Actor in Apify Console.
2. Keep Search `PLOMBERIE` (or type a company / SIRET) and pick a **département**. Optional city/postcode narrows the slice.
3. Leave **How many** at **20** for a cheap first run. Click **Start**.
4. Next week: same slice + **Only new companies** — already billed ids are skipped (named store `qualibat-seen-ids`).

Every row is the **full fiche + certificate PDF** (SIRET, phone, email, RGE categories, directors, founded date). There is no lighter Console mode.

The run summary (`OUTPUT`) includes **fill rates** so you can see how complete the file is — not just the row count.

Live slice **19 Aug 2026** — `PLOMBERIE` × Rhône, 12 firms:

| Field | Fill |
|---|---|
| SIRET | **100%** |
| Email (certificate PDF) | **100%** |
| Mobile | **100%** |
| Phone (fiche) | **92%** |
| Directors | **100%** |
| RGE work categories | **83%** |
| Founded date | **58%** |
| Website | **33%** |
| Callable (phone or email) | **100%** |

**Clay / Lemlist / HubSpot:** map `siret`, `phone`, `email`, `directorNames`, `rgeCategories`, `city`, `foundedAt`. One row = one firm.

See the **Input** tab for the visible options.

**Limits (Qualibat, not this Actor):**

- Search is required unless you switch **Advanced → All of France**.
- A bare qualification code (`3118`) without a location returns **0**.
- Without a département (or city / postcode) the public UI **stops at 50**. With a département, Qualibat paginates 5 cards per page via POST `page=N`.
- `robots.txt` is empty (`Disallow:`). You are still responsible for GDPR / legitimate interest on B2B outreach.
- **RGE** filters the badge after the slice. Qualibat’s métier dropdowns live in PHP session and are not a stable second API.

**All of France** (Advanced): Qualibat has no company sitemap. We HEAD `dq_{id}` (200 + PDF = live firm), newest first. Search / département still filter after the PDF. Same **$4 / 1k**. Free plans stop at 20.

### How much does it cost to scrape Qualibat companies?

**$4 per 1,000 companies** on the Free plan. Actor start is **$0.00005** (invisible). Rows with no id/name/phone/SIRET are **$0**.

Every Console run bills that event — fiche + certificate (email, RGE categories, dates) included. There is no “cards only” toggle.

Live Apify Store comps (19 Aug 2026) — there is **no other Qualibat Actor**. Closest substitutes:

| Actor | You pay for | Free / 1k |
|---|---|---|
| [PagesJaunes saswave](https://apify.com/saswave/pagesjaunes-scraper) | 1 Yellow Pages listing (phone, often email) | **$1.50** |
| [PagesJaunes leads](https://apify.com/mostafa-ennadi/fast-pagesjaunes-france-business-leads-scraper-no-proxy) | 1 PJ lead | **$1.00** |
| [France SIREN registry](https://apify.com/logiover/france-company-registry-scraper) | 1 SIRENE company | **$3.50** |
| [SIRENE + RGE flag](https://apify.com/seemuapps/pappers-sirene-scraper) | 1 SIRENE row (`estRge` filter, no Qualibat quals) | **$4.50** |
| [RGE SIREN enrich](https://apify.com/corent1robert/rge-siren-enrich) | 1 ADEME RGE artisan (+ optional website add-on) | **$5.00** |
| **This Actor** | **1 Qualibat firm** (label + SIRET + phone + **certificate email / RGE categories**) | **$4.00** |

PJ is cheaper because it is **generic France**. This slice is the **Qualibat label + fiche phone + certificate**. Priced **under** our RGE Actor and **in the SIRENE band**.

Paid Apify plans go lower. Diamond is **$2.00 / 1k**.

**Free plan:** a run stops at **20 companies** — enough to test (~$0.08).

| Apify plan | Company / 1k |
|---|---|
| Free | **$4.00** |
| Bronze | **$3.55** |
| Silver | **$3.10** |
| Gold | **$2.66** |
| Platinum | **$2.66** |
| Diamond | **$2.00** |

Default 20 rows in Rhône ≈ **$0.08**.

### Input

| Field | Default | Notes |
|---|---|---|
| `query` | `PLOMBERIE` | Name, SIRET, or trade keyword |
| `department` | `69` (Rhône) | Dropdown of official départements. **None** = 50-row cap |
| `city` | empty | Optional city or 5-digit CP. Overrides the département |
| `rge` | `any` | `yes` / `no` filter the badge after the slice |
| `maxCompanies` | `20` | Unique Qualibat ids |
| `onlyNew` | `false` | Skip ids already billed on this same search |
| `coverage` | `slice` | Advanced. `all` = scan live certificates nationwide |

Radius, row depth and “parse PDFs” stay on the API only. Console always GETs the fiche and the certificate.

### Output example

```json
{
  "companyId": "1068679",
  "name": "A V R PLOMBERIE",
  "siret": "50262720100069",
  "siren": "502627201",
  "phone": "+33428299590",
  "phoneNational": "04 28 29 95 90",
  "email": "administratif@avrplomberie.fr",
  "website": null,
  "phoneMobile": null,
  "isRge": false,
  "address": "150 RUE DU 8 MAI 1945, 69100 VILLEURBANNE",
  "postcode": "69100",
  "city": "VILLEURBANNE",
  "directors": "SEVERINE BOURGEOIS",
  "directorNames": ["BOURGEOIS SEVERINE"],
  "workforce": 27,
  "workforceBand": "EFF6C",
  "revenueEur": 2633499,
  "revenueBand": "CA11",
  "capitalEur": 7000,
  "foundedAt": "2008-02-15",
  "hasProbation": false,
  "rgeCategories": [],
  "qualifications": [
    {
      "code": "5111",
      "label": "Installation de plomberie sanitaire en habitat individuel, collectif ou autre bâtiment inférieur à 1000 m²",
      "attributedAt": "2024-01-15"
    }
  ],
  "profileUrl": "https://www.qualibat.com/entreprises/1068679-a-v-r-plomberie"
}
```

### FAQ

#### Is there a Qualibat API?

No. Qualibat does not publish a company API. This Actor is the Store alternative: public directory search + official certificate PDFs.

#### Qualibat vs ADEME RGE — which list is this?

**Qualibat** = qualification directory (métier codes, certificate, fiche phone). **ADEME / France Rénov** = the RGE register. A firm can be on one and not the other. Use [RGE SIREN enrich](https://apify.com/corent1robert/rge-siren-enrich) for ADEME.

#### Can I skip companies I already paid for?

Yes. Turn on **Only new companies**. Memory is per search (keyword × département × city × RGE) in the named key-value store `qualibat-seen-ids`. Empty shells are never stored.

#### How complete is the email / RGE file?

Open the run **OUTPUT** record. `fill.emailPct` / `phonePct` / `rgeCategoryPct` / `callablePct` are computed on billed rows. The fiche has no mailto — a missing email means the certificate PDF had no text-layer address, not that we skipped the PDF.

#### Can I skip the certificate PDF to pay less?

No. The fiche has no mailto — email, RGE work categories and founded date live on the PDF. Console always parses it. The $4 event is that full row.

### Changelog

See [CHANGELOG.md](CHANGELOG.md).

# Actor input Schema

## `query` (type: `string`):

Company name, **SIRET**, or a trade keyword (`PLOMBERIE`, `PHOTOVOLTAIQUE`). Needed for **This search**. On **All of France**, empty = every live firm.

A bare qualification code (`3118`) without a location returns **0** — that is Qualibat, not this Actor.

## `department` (type: `string`):

Search the whole **département**. Pick **None** only for a SIRET or company-name lookup (Qualibat then stops at **50**). A city below overrides this.

## `city` (type: `string`):

Optional. Leave empty for the **whole département**. Fill `Lyon` or `69003` to narrow. Typos fail — prefer the département list when you can.

## `rge` (type: `string`):

**Any** = every Qualibat-labelled firm. **RGE only** = badge on the card. Applied after the search, not a second Qualibat API.

## `maxCompanies` (type: `integer`):

Unique firms. Default **20** ≈ **$0.08**. Free Apify plans stop at 20.

## `onlyNew` (type: `boolean`):

Skip Qualibat ids already billed on a **previous run of this same search** (keyword × département × city × RGE). First run builds the memory. Relist a département without paying the same artisans twice.

## `coverage` (type: `string`):

**This search (recommended):** Qualibat directory for the keyword × département above.

**All of France:** Qualibat has no company sitemap and caps a broad list at 50. We scan live certificates instead (slow). Search / département still filter after. Newest first.

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

Legacy free-text. Console uses Département + City. Still accepted on the API; city/location wins over the département.

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

Used when City is set (Qualibat slider 1–200). Hidden. Default 30 km.

## `rowDepth` (type: `string`):

API only. Console always uses directory (fiche + PDF). Pass listing for cards without phone/email.

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

Optional. First request is direct. One retry with this proxy on 403 / challenge. Hidden in Console.

## `minDelayMs` (type: `integer`):

Pause between HTTP requests. Session cookie must survive the whole run.

## `idFrom` (type: `integer`):

Get all: start scanning downward from this certificate id. Hidden.

## `idMin` (type: `integer`):

Get all: stop scanning below this id. Hidden.

## `idMax` (type: `integer`):

Get all: skip auto-detect of the highest live id. Hidden.

## Actor input object example

```json
{
  "query": "PLOMBERIE",
  "department": "69",
  "rge": "any",
  "maxCompanies": 20,
  "onlyNew": false,
  "coverage": "slice",
  "radiusKm": 30,
  "rowDepth": "directory",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "minDelayMs": 400
}
```

# Actor output Schema

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

Name, SIRET, phone, email, RGE, city

## `icp` (type: `string`):

RGE categories, age, size, probation

## `rge` (type: `string`):

Rows with the Qualibat RGE badge

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

All company rows

## `output` (type: `string`):

Pushed / fill rates / skippedSeen

## `runLog` (type: `string`):

Live progress

# 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 = {
    "query": "PLOMBERIE",
    "department": "69"
};

// Run the Actor and wait for it to finish
const run = await client.actor("corent1robert/qualibat-entreprises").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 = {
    "query": "PLOMBERIE",
    "department": "69",
}

# Run the Actor and wait for it to finish
run = client.actor("corent1robert/qualibat-entreprises").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 '{
  "query": "PLOMBERIE",
  "department": "69"
}' |
apify call corent1robert/qualibat-entreprises --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corent1robert/qualibat-entreprises"
        }
    }
}

```

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/FcZO6meMJGNRb5FSP/builds/TqPxNcG1ctcbbOGmM/openapi.json
