# France Companies Scraper (`normdata/france-companies-scraper`) Actor

Scrape France's SIRENE and RNE company register with no API key. Search 30M companies by name, director, location, NAF code, revenue range or certificationsn look up SIREN/SIRET in batch; or list companies near a GPS point. Clean rows with directors and multi-year revenue and net income.

- **URL**: https://apify.com/normdata/france-companies-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.85 / 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?

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

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 🇫🇷 France Companies Scraper

Scrape the **French company register** (SIRENE and RNE) with no API key and no login. Search
30 million French companies by name, by director, by location or by structured filters, look up
a batch of SIREN or SIRET numbers, or list every company near a GPS point. Get clean structured
**company data for KYB, compliance, credit screening and B2B lead generation**: legal form, NAF
activity, employee band, head-office address with coordinates, VAT number, the full **board and
directors**, and **multi-year revenue and net income**, all in one request.

Here is one real row (trimmed), for Danone:

```json
{
  "siren": "552032534",
  "name": "DANONE",
  "active": true,
  "status": "active",
  "created_date": "1955-01-01",
  "age_years": 71,
  "legal_form_code": "5599",
  "legal_form": "SA (other)",
  "company_category": "GE",
  "naf_code": "70.10Z",
  "naf_label": "Head office and management consultancy activities",
  "employee_range": "1000 to 1999",
  "is_employer": true,
  "establishments_total": 19,
  "hq_address": "59-61 RUE LA FAYETTE 75009 PARIS",
  "hq_postal_code": "75009",
  "hq_city": "PARIS",
  "hq_department": "75",
  "hq_latitude": 48.8763540066087,
  "hq_longitude": 2.34353640229216,
  "collective_agreements": ["9999"],
  "officers_count": 13,
  "officers": [
    { "type": "person", "name": "ANTOINE BERNARD DE SAINT AFFRIQUE", "role": "Directeur Général", "birth_date": "1964-12" }
  ],
  "finances": [{ "year": "2024", "revenue": 27376000000, "net_result": 0 }],
  "last_revenue": 27376000000,
  "last_revenue_year": "2024",
  "query": null,
  "error": null,
  "url": "https://annuaire-entreprises.data.gouv.fr/entreprise/552032534",
  "scraped_at": "2026-09-08T19:52:24.000Z"
}
```

### What it does

Reads the official French business registry (SIRENE, held by INSEE, and the RNE company data),
served as open data by the state. Three modes:

- **Search companies** by name and any of: director name, department, region, commune, postal
  code, NAF activity code or section, legal form, size class, employee band, revenue range, net
  income range, administrative status, and certification labels. Filters combine with AND.
- **Look up by SIREN or SIRET**: paste a batch of nine or fourteen-digit numbers, get the full
  record for each. Numbers that do not resolve come back as a row with `error: "not found"`, so
  the output always has one row per input. The KYB / CRM-refresh workflow.
- **Companies near a point**: every company with an establishment inside a radius (up to 50 km)
  of a latitude and longitude, optionally narrowed by NAF code.

Every row carries the directors, the filed establishments and multi-year revenue and net income
**in the same request**. There are no per-company enrichment calls and no add-on charges.

Legal form, size class, status, employee band and NAF division are decoded to readable labels.
Missing source values are returned as `null`, never invented.

### Why this scraper

- **No API key, no login, no captcha.** Public open data, delivered clean and flat.
- **Filters no other France scraper on Apify has:** revenue and net-income range, director name
  and birth-date range, geographic radius search, and certification labels (RGE, Qualiopi, ESS,
  organic, societe a mission, SIAE, EPV).
- **Directors and multi-year financials on every row**, not behind a paid add-on.
- **Region, commune and multi-establishment aware.** The department and postal filters match
  companies with any establishment there, and the matching establishments come back in the row.
- **One flat price.** No per-attempt contact-finder fees, no AI upsells.

### How it compares

| Capability | This actor | Other France registry scrapers on Apify |
|---|:--:|:--:|
| Name / SIREN / SIRET search and lookup | yes | yes |
| Department, NAF, legal form, status filters | yes | yes |
| **Revenue range and net-income range filters** | **yes** | **no** |
| **Director name and birth-date search** | **yes** | **no** |
| **Geographic radius (near a point) search** | **yes** | **no** |
| **Certification / label filters (RGE, Qualiopi, ESS, ...)** | **yes** | **no** |
| Directors and multi-year financials on every row | yes | add-on or partial |
| Readable labels for legal form, NAF, size, employee band | yes | some |
| Region / commune filters, multi-department in one run | yes | no |
| Declared dataset schema + free-plan preview | yes | rare |
| Flat price, no AI or contact-finder add-ons | yes | no |

### Use cases

- **B2B lead generation.** Target by NAF activity, department or region, size class and
  **revenue band** ("SAS in Ile-de-France, computer services, turnover above 5M EUR"), with
  head-office address and coordinates.
- **KYB and compliance.** Verify a French counterparty by SIREN, capture legal form, status,
  directors and financials for the onboarding file.
- **Credit and risk screening.** Filter or sort by filed revenue and net income, pull the
  multi-year `finances` series for a portfolio.
- **Due diligence on people.** Find every company where a named director is on record, narrowed
  by birth-date range.
- **Local market mapping.** Use near-a-point mode to list every restaurant, retailer or
  workshop within 2 km of an address.
- **Segment by label.** Build lists of RGE (green building), Qualiopi (training), ESS or
  organic-certified companies.

### Quickstart

```json
{
  "mode": "search",
  "query": "Danone",
  "maxItems": 10
}
```

Computer-services companies in Paris with turnover above 5M EUR:

```json
{
  "mode": "search",
  "department": "75",
  "nafCode": "62.01Z",
  "revenueMin": 5000000,
  "maxItems": 200
}
```

Every company where a director named Bernard Arnault is on record:

```json
{ "mode": "search", "personName": "Arnault", "personFirstName": "Bernard" }
```

Refresh a list of companies by number:

```json
{ "mode": "lookup", "ids": ["552032534", "77567227200015"] }
```

Restaurants within 2 km of central Paris:

```json
{ "mode": "near", "latitude": "48.8566", "longitude": "2.3522", "radiusKm": 2, "nafCode": "56.10A" }
```

### Input reference

| Field | Applies to | Description |
|---|---|---|
| `maxItems` | all | Ceiling on rows written. |
| `mode` | all | `search`, `lookup` or `near`. |
| `query` | search | Full-text over name, trade name, address and directors. Most relevant first. |
| `department` / `region` / `communeCode` / `postalCode` | search | Location. Department and postal match on establishments. |
| `nafCode` / `nafSection` | search, near | Full NAF (APE) code (e.g. `62.01Z`), or a single-letter section (e.g. `J`) for a whole sector. |
| `legalForm` | search | INSEE legal category code (5710 SAS, 5499 SARL, ...). |
| `companyCategory` | search | `PME`, `ETI` or `GE`. |
| `employeeRange` | search | INSEE headcount band. |
| `revenueMin` / `revenueMax` | search | Filed turnover range, EUR. |
| `netResultMin` / `netResultMax` | search | Filed net income range, EUR (can be negative). |
| `status` | search | `active`, `ceased` or any. |
| `personName` / `personFirstName` | search | Director name search. |
| `personBornAfter` / `personBornBefore` | search | Director birth-date range, YYYY or YYYY-MM-DD. |
| `labels` | search | Keep only companies with every selected label (RGE, Qualiopi, ESS, ...). |
| `sortBySize` | search | Biggest companies first. |
| `ids` | lookup | Nine-digit SIREN or fourteen-digit SIRET numbers. |
| `latitude` / `longitude` / `radiusKm` | near | Centre point and radius (1 to 50 km). |

### Output reference (selected)

Columns are ordered for reading: identity, classification, size, head office, people,
financials, labels, establishments, provenance.

| Field | Description |
|---|---|
| `siren` | Nine-digit company number. |
| `name` / `legal_name` / `acronym` | Names as filed. |
| `active` / `status` | Whether the legal unit is still active. |
| `legal_form` / `legal_form_code` | Legal category, decoded and raw. |
| `company_category` | INSEE size class: PME, ETI, GE. |
| `naf_code` / `naf_label` / `naf_section` | Main activity, code and English label. |
| `employee_range` / `employee_range_code` | Headcount band. |
| `is_employer` | Whether the company employs staff. |
| `establishments_total` / `establishments_open` | Establishment counts. |
| `vat_number` | Intra-EU VAT number where derivable. |
| `hq_address` ... `hq_longitude` | Head-office address, split, with coordinates. |
| `hq_naf_code` / `hq_naf_label` / `hq_trade_name` / `hq_signs` | Head-office activity and trade names. |
| `collective_agreements` | Collective-agreement IDs (IDCC) at the head office. |
| `officers` / `officers_count` | Directors: type, name, role, birth date, nationality, and SIREN for corporate officers. |
| `finances` | Array of `{ year, revenue, net_result }`, newest first. |
| `last_revenue` / `last_revenue_year` / `last_net_result` | Most recent filed figures. |
| `certifications` | Human list derived from the label flags. |
| `is_rge` / `is_qualiopi` / `is_ess` / `is_bio` / `is_mission_company` / `is_training_org` / `is_work_integration` / `is_living_heritage` / `is_association` / `is_sole_trader` / `is_public_body` / `is_local_authority` | Label flags. |
| `association_id` | RNA number for associations. |
| `establishments` | Matching establishments (sample): SIRET, address, department, coordinates, activity, HQ flag, status. |
| `updated_at` / `updated_at_insee` / `updated_at_rne` | Source update timestamps. |
| `query` | In Look up mode, the SIREN or SIRET you asked for. `null` on search and near rows. |
| `error` | `null` on a normal row. `"not found"` on a Look up row whose number did not resolve (every other field is then `null`). |
| `url` | Link to the public annuaire-entreprises page. |
| `scraped_at` | ISO 8601 timestamp of when the row was collected. |

### Run via API and CLI

```bash
curl -X POST "https://api.apify.com/v2/acts/USERNAME~france-companies-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode":"search","department":"75","nafCode":"62.01Z","revenueMin":5000000,"maxItems":200}'
```

```bash
apify call USERNAME/france-companies-scraper --input '{"mode":"lookup","ids":["552032534"]}'
```

### Fetch results

```bash
## JSON
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=json"
## CSV
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
## Paginate large datasets
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&offset=1000&limit=1000"
```

`<DATASET_ID>` is `defaultDatasetId` on the run object.

### Billing and limits

- **Pay per result.** Billed per company row written to the dataset. The current rate is on the
  Actor's Pricing tab. Directors and financials are included, not billed separately.
- **No charge on failure.** A run that produces zero rows fails with a message and is not billed.
- A Look up number that does not resolve still writes one `error: "not found"` row and is billed
  like any other row, so your output count matches your input list.
- **Free Apify plans** run the built-in 10-row sample only. Upgrade to run your own settings.
- Very large segments are capped at about 25,000 rows per distinct query. Split the query (by
  department, NAF code or a date facet) to go past that.
- Department and postal-code filters match on establishments, so a result's head office can be
  in another department. The matching establishments are in the `establishments` array.
- The registry is French government open data (Licence Ouverte / Etalab 2.0), which permits
  commercial reuse and redistribution. This Actor adds the filtering, decoding and structure;
  it stores nothing and needs no account.

### FAQ and troubleshooting

**Do I need an API key or login?** No. The French company registry is public open data, no key,
no login, no captcha.

**Why did a department filter return a company whose head office is elsewhere?** The department
and postal filters match any establishment, not just the head office. Check the `establishments`
array for the site that matched. This is intended: you also catch large companies with a branch
in your target area.

**Why is `finances` empty?** The company has not filed accounts. Many sole traders, associations
and small companies do not. Setting a revenue or net-income filter excludes non-filers.

**Why is `legal_form` null but `legal_form_code` set?** The code is outside the common set this
actor decodes. The raw INSEE code is always there.

**A number in my Look up list did not resolve. What happens?** You still get a row for it, with
`query` set to the number you gave, `error` set to `"not found"`, and every other field `null`.
That keeps one row per input so you can join the output back to your list. It is billed like a
normal row.

**Can I search by a company's director?** Yes. Use `personName` (last name) and optionally
`personFirstName` and a birth-date range. Note that a plain `query` also matches directors, so
it can pull in companies whose officer has that name.

**How current is the data?** It reflects SIRENE and the RNE at run time. `updated_at`,
`updated_at_insee` and `updated_at_rne` show when each source last changed the record.

**Is this an official INSEE tool?** No. Independent, not affiliated with INSEE, INPI or the
French government. It reads only data published as open data.

### Local development

```bash
bun install
bun test              # offline: input parsing and normalisation against synthetic fixtures
bun run src/main.ts   # reads storage/key_value_stores/default/INPUT.json
```

# Actor input Schema

## `maxItems` (type: `integer`):

Caps how many company rows this run writes. Starts at 10 for a quick sample; raise it for a full run.

## `mode` (type: `string`):

Search filters the whole registry. Look up takes exact SIREN or SIRET numbers. Near returns companies with an establishment within a radius of a GPS point.

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

Full-text search over company name, trade name, address and directors. Most relevant matches come first. Leave empty to search the whole registry with the filters below, or use Look up mode for an exact number.

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

Two or three-digit French department, e.g. 75 (Paris), 13 (Bouches-du-Rhone), 2A (Corse-du-Sud), 971 (Guadeloupe). Matches companies with at least one establishment there; the head office may be elsewhere (see the establishments array).

## `region` (type: `string`):

Administrative region. Like the department filter, this matches on establishments.

## `communeCode` (type: `string`):

Five-character INSEE commune code (not the postal code), e.g. 75056 for Paris, 69123 for Lyon.

## `postalCode` (type: `string`):

Five-digit French postal code. Like the department filter, this matches on establishments.

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

Full NAF (APE) code, e.g. 62.01Z for computer programming, 10.71C for bakeries. Must be the complete 5-character code. For a whole sector, use the NAF section field instead.

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

Whole NAF sector. Use this instead of a code to keep a broad segment.

## `legalForm` (type: `string`):

INSEE legal category code: 5710 SAS, 5720 SASU, 5499 or 5410 SARL, 5426 EURL, 5510 SA, 6540 SCI, 5202 SNC, 1000 sole trader, 9220 declared association, 9260 foundation.

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

INSEE size class.

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

INSEE headcount band of the company.

## `revenueMin` (type: `integer`):

Only companies with filed turnover at or above this. Non-filers (many sole traders and associations) are excluded when this is set.

## `revenueMax` (type: `integer`):

Only companies with filed turnover at or below this.

## `netResultMin` (type: `integer`):

Only companies with filed net income at or above this. Can be negative.

## `netResultMax` (type: `integer`):

Only companies with filed net income at or below this. Can be negative.

## `status` (type: `string`):

Filter by whether the legal unit is still active.

## `personName` (type: `string`):

Last name of a director, officer or elected representative. Returns every company where that person is on record.

## `personFirstName` (type: `string`):

First name to go with the director last name.

## `personBornAfter` (type: `string`):

YYYY-MM-DD or YYYY. Narrows a director search to people born on or after this date.

## `personBornBefore` (type: `string`):

YYYY-MM-DD or YYYY. Narrows a director search to people born on or before this date.

## `labels` (type: `array`):

Keep only companies that carry every selected label.

## `sortBySize` (type: `boolean`):

Return the biggest companies (most establishments) first instead of by relevance.

## `ids` (type: `array`):

Nine-digit SIREN or fourteen-digit SIRET numbers. Spaces and dots are stripped.

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

Decimal latitude of the centre point, e.g. 48.8566 for Paris.

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

Decimal longitude of the centre point, e.g. 2.3522 for Paris.

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

Search radius around the point, 1 to 50 km. Also accepts the NAF code or section fields above.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "search",
  "query": "Danone",
  "region": "",
  "nafSection": "",
  "companyCategory": "any",
  "employeeRange": "",
  "status": "any",
  "sortBySize": false,
  "radiusKm": 5
}
```

# Actor output Schema

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

One dataset row per company.

# 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 = {
    "maxItems": 10,
    "mode": "search",
    "query": "Danone",
    "companyCategory": "any",
    "status": "any"
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/france-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 = {
    "maxItems": 10,
    "mode": "search",
    "query": "Danone",
    "companyCategory": "any",
    "status": "any",
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/france-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 '{
  "maxItems": 10,
  "mode": "search",
  "query": "Danone",
  "companyCategory": "any",
  "status": "any"
}' |
apify call normdata/france-companies-scraper --silent --output-dataset

```

## MCP server setup

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