# French Company Register Search — SIREN, NAF, Directors, Revenue (`dalbian/french-company-register-search`) Actor

Search every company registered in France through the government's own open register: by name, SIREN, SIRET, department, postcode, NAF activity, legal form, size band or revenue. Returns the headquarters address with coordinates, the readable activity and size labels, the latest filed.

- **URL**: https://apify.com/dalbian/french-company-register-search.md
- **Developed by:** [Benjamin Jerez](https://apify.com/dalbian) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 search runs

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

## French Company Register Search — SIREN, NAF, Directors, Revenue

Search every company registered in France through the government's own open register. By name, by SIREN or SIRET, by department or postcode, by NAF activity, by legal form, by employee band, by filed revenue, or by a radius around a point on the map.

One source, live on every run, no API key and no scraping: `recherche-entreprises.api.gouv.fr`, the search API behind the official French company directory.

### What a company row looks like

A direct SIREN lookup on `775665912`:

| Field | Value |
| --- | --- |
| `siren`, `name` | 775665912 · CENTRE NATIONAL D'ETUDES SPATIALES (CNES) |
| `status`, `dateCreated` | Active · 1984-07-01 |
| `nafCode`, `nafLabel` | 72.19Z · Recherche-développement en autres sciences physiques et naturelles |
| `nafSection`, `nafSectionLabel` | M · Professional, scientific and technical activities |
| `employeeRangeCode`, `employeeRange` | 51 · 2 000 to 4 999 employees |
| `companyCategory` | ETI |
| `address`, `latitude`, `longitude` | 2 PLACE MAURICE QUENTIN 75001 PARIS · 48.861320 · 2.345357 |
| `establishmentCount` | 7 |
| `vatNumber` | FR49775665912 |
| `annuaireUrl` | annuaire-entreprises.data.gouv.fr/entreprise/775665912 |

A ceased company keeps its record. `552100554` comes back as PEUGEOT SA, `status` Ceased, `dateClosed` 2021-01-16, with the last accounts it filed: `financialYear` 2019, `revenue` 74 731 000 000, `netResult` 3 584 000 000.

### Three codes translated

The register stores its three most useful fields as codes. A raw `03` or `10.71C` is unusable in a prospect list, so each one is written back in readable form alongside the code it came from.

**Employee band.** `tranche_effectif_salarie` is an INSEE bracket code, not a headcount, and the codes are not ordinal — `03` is smaller than `11`, and `NN` is not zero. The full INSEE table is applied: `01` is 1 to 2 employees, `02` is 3 to 5, `03` is 6 to 9, `11` is 10 to 19, `12` is 20 to 49, `21` is 50 to 99, up to `53` for 10 000 or more. `NN` means the company employed nobody during the reference year; `00` means it had nobody on 31 December but did employ people earlier in the year.

**Activity.** `nafCode` carries the NAF (APE) code and `nafLabel` the official INSEE sub-class wording — 10.71C is `Boulangerie et boulangerie-pâtisserie`, 62.01Z is `Programmation informatique`. All 732 NAF rév. 2 sub-classes are covered. `nafSectionLabel` gives the 21-section level in English.

**Administrative state.** `A` and `C` become `Active` and `Ceased` on companies. Establishments use a different pair — `A` and `F` — and become `Open` and `Closed`.

### Filters

Every filter below was checked against the live register by comparing result counts and then reading the returned rows back, because the API silently ignores parameters it does not recognise.

Searching `boulangerie` across France returns at least 10 000 active companies. Add `department` 69 and it is 398. Add `nafCode` 10.71C and it is 292. Add `employeeRange` 03 and it is 51 — and all 15 rows pulled from that search carry `nafCode` 10.71C, `nafLabel` Boulangerie et boulangerie-pâtisserie, `employeeRangeCode` 03, `employeeRange` 6 to 9 employees and `status` Active.

`department` and `postcode` filter on **establishments**, not on the head office. One of those 15 bakeries has its registered office in department 59 and was returned because it runs a site in 69; the establishment rows show the site that matched. This is the register's own behaviour and it is usually what you want — a company with a branch in your territory is a prospect.

`activeOnly` is on by default and sends `etat_administratif=A`. Leaving it off does not mean "active first", it means both: a search for `boulangerie` in Corsica returns 103 companies with no state filter, 72 with `A` and 31 with `C`. Direct SIREN and SIRET lookups ignore the filters, so a ceased company you asked for by number is still returned.

`minRevenue` and `maxRevenue` filter on the latest filed turnover. Only companies that actually filed accounts can match, so these quietly exclude everything with no published figures.

### Geographic search

Set `latitude`, `longitude` and `radiusKm` and the run switches to the register's radius endpoint. The radius runs from 0.001 km to 50 km. A 500-metre circle on Place Bellecour in Lyon returns 1 888 companies.

A company matches when **any** of its establishments falls inside the circle, so national chains come back with their head office far outside it — La Poste is returned for a 300-metre circle on the Hôtel de Ville in Paris because it has a counter there. Turn on `includeEstablishments` to see which site matched.

Geographic search accepts only the activity filters. Department, postcode, legal form, size and revenue are not supported by that endpoint and are dropped rather than silently ignored; the summary row lists what was actually sent.

### Output

Four row types, all flat and camelCase, keyed together by `siren`.

`summary` — one per search, pushed before its results: `totalResults`, `returned`, `duplicates`, the `filters` actually sent, and a `note` when something needs explaining.

`company` — the company, with the head office address flattened into `address`, `postcode`, `city`, `department`, `region` and separate numeric `latitude` and `longitude`; the latest filed `financialYear`, `revenue` and `netResult`; establishment counts; the VAT number; and the public-registry flags that people filter on — `isAssociation`, `isSocialEconomy`, `isEnvironmentCertified`, `isOrganicCertified`, `isQualiopiCertified`, `isMissionLedCompany`, `isWorkIntegrationEnterprise`, `isLivingHeritageCompany`, `hasCollectiveAgreement` with `collectiveAgreementIds`, `hasGenderEqualityIndex`, `hasGreenhouseGasReport`.

`director` — optional, on by default. See below.

`establishment` — optional, off by default. The sites that matched the search, with SIRET, address, coordinates, trading names and open or closed state.

### Directors and personal data

`dirigeants` is published French open data from the RNE, the national business register. It names real people in their business capacity, and this Actor treats it as such rather than as a people database.

Each `director` row carries the surname, first names, `role`, nationality and `birthYear` — nothing else. The API also returns `date_de_naissance` as YYYY-MM; **it is dropped and never written to the dataset.** The year is enough to tell two namesakes apart, which is the only thing a company register needs it for.

Corporate officers — auditors and parent companies — carry no personal data at all: they come back as `directorType` `company` with `corporateName` and `corporateSiren`.

The API also offers parameters that search for a named individual across all companies, with a birth-date range. **They are deliberately not exposed by this Actor.** This is a company search, not a person search, and there is no input that will make it behave like one.

If you keep or reuse director rows, you become the data controller for that personal data under the GDPR, including the purpose limitation and the right to object. Set `includeDirectors` to false if you do not need them.

### How complete is the data

Measured on a run of eight broad national searches, 400 companies:

| Field | Present |
| --- | --- |
| `nafLabel` | 100% |
| `employeeRange` | 100% |
| `latitude` / `longitude` | 98% |
| at least one director | 95% |
| `companyCategory` | 95% |
| `vatNumber` | 87% |
| `financialYear` with `revenue` and `netResult` | 74% |
| `revenue` above zero | 46% |

`finances` is the patchy one and it gets patchier the smaller the company. Broad searches rank larger companies first, which is why the 74% above is optimistic; over a wider slice that reached further down the result pages, only 46% of companies carried a `finances` block at all. Sole traders, associations and recently created companies mostly file nothing. Never assume the field is there.

The latest filed year is not the same for everyone either — in that sample it ranged from 2025 back to 2016, so `financialYear` is always written next to the figures.

### Limits

**10 000 results per search, hard.** The register stops counting at 10 000, so `totalResults` of 10 000 means "at least 10 000" and `totalResultsCapped` is set to true. It also refuses to page past that point — `per_page` is capped at 25 and `page × per_page` must not exceed 10 000. Narrowing by department, postcode or NAF code is the only way through, and the summary row says so.

**`tranche_effectif_salarie` runs two to three years behind.** That is how INSEE publishes it. `employeeRangeYear` says which year the band refers to.

**Pre-2008 records carry NAF rév. 1 codes.** Establishments closed before the 2008 reclassification still show codes like `55.3A` or `74.1J`, which have no rév. 2 label. Those rows get the code with `nafLabel` empty rather than a wrong label.

**The host drops connections.** From some networks roughly half of new connections to this API are reset before any response, in bursts of eight or more in a row. The Actor retries each request up to twelve times on transport errors as well as on HTTP 429 and 503. A ten-search test run covering 326 companies completed in 23 seconds through a connection that was failing at that rate.

### Who uses this

Sales and prospecting teams building French target lists by activity, size band and territory. Marketplaces and platforms verifying that a seller's SIREN exists and is still active before onboarding. Credit, procurement and compliance teams checking legal form, filed turnover and company officers. Recruiters and researchers sizing a sector by NAF code. Local authorities and trade bodies mapping who is actually operating in a commune.

### Source and licence

**`recherche-entreprises.api.gouv.fr`**, published by the DINUM as part of the Annuaire des Entreprises. It aggregates INSEE's Sirene register (companies, establishments, addresses, activity codes, employee bands), the RNE business register held by INPI (company officers), the filed annual accounts, and a set of public certification registers. Free, keyless, French public-sector open data under the Licence Ouverte 2.0. Queried live on every run; nothing is cached or stored by this Actor.

Every row carries an `annuaireUrl` to the official public page for that company or establishment on `annuaire-entreprises.data.gouv.fr`.

### Frequently asked

**Why does my search say 10 000 matches when there are clearly more?**
The register saturates its own counter at 10 000 and will not page beyond it. `totalResultsCapped` marks that row. Split the search by department, postcode or NAF code.

**Why is a company outside my department in the results?**
`department` and `postcode` filter on establishments. The company has a site in your area even though its registered office is elsewhere. Turn on `includeEstablishments` to see which one.

**Why does a SIREN I asked for come back as ceased when `activeOnly` is on?**
Direct lookups by SIREN or SIRET are exact and the filters are not applied to them. Returning nothing would look like the number was wrong rather than the company closed.

**Why is `revenue` empty?**
Because that company has not filed accounts, or filed them without a turnover figure. Roughly half the register has no published turnover at all. `financialYear` is empty on exactly the same rows.

**Why are the NAF labels in French when the rest is in English?**
`nafLabel` is the registered wording of the activity in the French classification. Translating 732 sub-class names would invent labels the register does not use, and they would no longer match what the official directory shows. The 21-section level, which maps onto the European NACE classification, is given in English as `nafSectionLabel`.

**Can I search for a person?**
No. The upstream API offers it; this Actor does not expose it, by design.

**Does a search cost anything when it returns nothing?**
A search is charged once as `search-run` whether or not it matches. Companies are charged separately as `company-returned`, so a search that legitimately returns zero costs only the search.

# Actor input Schema

## `queries` (type: `array`):

One search per line. A company name, a trading name, an address fragment, or a bare SIREN (9 digits) or SIRET (14 digits) for a direct lookup. Leave the filters below empty and this searches the whole of France; combine it with a department or a NAF code to build a prospecting list.

## `sirens` (type: `array`):

Direct lookups, one identifier per line. A SIREN is the 9-digit company number; a SIRET is the 14-digit establishment number. Spaces and dots are stripped. Each one returns exactly one company or none, and the filters below are not applied to it.

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

French department code: two digits (75 for Paris, 69 for Rhone), 2A or 2B for Corsica, three digits for the overseas departments (971 Guadeloupe, 974 Reunion). Several are allowed, comma-separated. This filters on establishments, so a company headquartered elsewhere is returned when it has a site in the department.

## `postcode` (type: `string`):

Five-digit postcode, comma-separated for several. Like the department, this filters on establishments rather than on the headquarters alone.

## `nafSection` (type: `string`):

The broad activity section, the first level of the French NAF classification. Use this when you want a whole sector; use the NAF code below when you want one trade.

## `nafCode` (type: `string`):

Exact NAF (APE) code such as 10.71C for bakeries, 71.12B for engineering consultancy or 62.01Z for software development. Comma-separated for several. Narrower and far more useful than the section for prospecting.

## `legalStatus` (type: `string`):

INSEE legal category code, comma-separated for several. The common ones are 5710 (SAS), 5499 (SARL), 5720 (SASU), 5498 (EURL), 1000 (sole trader), 9220 (association) and 6540 (property partnership, SCI).

## `companyCategory` (type: `string`):

INSEE's official company size category, computed by INSEE from headcount, turnover and balance-sheet total. Coarser than the employee band but stated by the statistics office rather than derived.

## `employeeRange` (type: `string`):

INSEE employee band of the company. The code is what the register stores; the readable band is written back into every row as employeeRange. The figure is two to three years behind, which is how INSEE publishes it.

## `activeOnly` (type: `boolean`):

Keep only companies whose administrative state is A (active). Turn this off to include state C (ceased) — companies struck off, wound up or merged away. Without this filter the register returns both, so leaving it on is what you usually want.

## `minRevenue` (type: `integer`):

Filter on the latest filed turnover. Only companies that actually filed accounts can match, and that is well under half the register, so this silently excludes every company with no published figures.

## `maxRevenue` (type: `integer`):

Upper bound on the latest filed turnover. Same caveat as the minimum: companies with no filed accounts are excluded rather than treated as zero.

## `latitude` (type: `number`):

Centre point of a radius search. Set latitude, longitude and radius together to search around a location instead of by text. Geographic search accepts only the activity section and NAF code filters — department, size and revenue are ignored.

## `longitude` (type: `number`):

Longitude of the centre point. Required with latitude.

## `radiusKm` (type: `number`):

Search radius around the centre point, from 0.001 km to 50 km. A company matches when any of its establishments falls inside the circle, so a national chain can be returned with its headquarters far outside it.

## `includeDirectors` (type: `boolean`):

Add one row per company officer recorded in the national business register (RNE): surname, first names, role, nationality and year of birth. This is published French open data about people acting in a business capacity. Day and month of birth are deliberately dropped. If you keep or reuse these rows you are the data controller for them.

## `includeEstablishments` (type: `boolean`):

Add one row per establishment that matched the search, with its SIRET, address, coordinates and open or closed state. These are the sites the register matched, not the company's full site list; a direct SIREN lookup returns only the headquarters.

## `maxResultsPerQuery` (type: `integer`):

Cap on companies returned per search term. The register refuses to page beyond 10 000 results per search whatever this is set to, so narrow by department or NAF code rather than raising it.

## Actor input object example

```json
{
  "queries": [
    "boulangerie"
  ],
  "activeOnly": true,
  "radiusKm": 5,
  "includeDirectors": true,
  "includeEstablishments": false,
  "maxResultsPerQuery": 100
}
```

# Actor output Schema

# 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 = {
    "queries": [
        "boulangerie"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dalbian/french-company-register-search").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 = { "queries": ["boulangerie"] }

# Run the Actor and wait for it to finish
run = client.actor("dalbian/french-company-register-search").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 '{
  "queries": [
    "boulangerie"
  ]
}' |
apify call dalbian/french-company-register-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dalbian/french-company-register-search"
        }
    }
}
```

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/4FDZ4fNUalQR4zDkv/builds/jQ4sfaaNVdvs1yjbx/openapi.json
