# French Companies Scraper (`axiomworks/french-companies-scraper`) Actor

Find and export French company records from the public registry search API. Results include SIREN, SIRET, legal form, NAF code, status, head-office address, establishment count, directors and available year-keyed finances. Search using names, identifiers, departments, postal codes or activity codes.

- **URL**: https://apify.com/axiomworks/french-companies-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

**Returns:** one row per French company with `siren`, `name`, `siret`, `legalForm`, `nafCode`, `status`, `address` and `sourceUrl`.
**Input:** `{"departements":["75"],"nafCodes":["62.01Z"],"maxItems":25}`
**Best for:** company research, local market maps, and building lists by industry and location.

```json
{
  "siren": "380474494",
  "name": "EURO INFORMATION DEVELOPPEMENTS (EID)",
  "siret": "38047449400016",
  "legalForm": "5710",
  "nafCode": "62.01Z",
  "status": "A",
  "city": "STRASBOURG"
}
```

### What does French Companies Scraper do?

French Companies Scraper searches the public French business registry search API and returns structured company records. It accepts company names, SIREN or SIRET identifiers, address text, departments, postal codes, NAF activity codes, legal form codes, workforce bands, and company size categories. The Actor combines the supplied filters, walks the API's pages, and writes one dataset row per unique SIREN. It does not need a login.

The source is the official `recherche-entreprises.api.gouv.fr` search endpoint. This Actor is an independent tool and is not affiliated with the French administration. The `sourceUrl` on each row records the exact API request that returned that company, so downstream work can trace a record to its source.

Search filters apply to the API result, which may match an establishment other than a company's head office. The output's `siret`, `address`, `postalCode`, `city`, `latitude`, and `longitude` describe the **head office** (`siege`) supplied in the API response. For example, a company found through a Paris department filter can have its head office in another department. A department match can describe a local establishment while the displayed address identifies its head office.

Non-diffusible records are skipped. Missing directors, coordinates or finances appear as `null`, never invented.

### What data can you get?

Each output row has a stable `id`, equal to its SIREN, and the endpoint `sourceUrl`. The remaining fields map directly to the API's company object or its head-office object. Codes stay as codes, which makes joins to other French open datasets straightforward. Financial data is grouped by reporting year exactly as returned.

| Field | Meaning |
| --- | --- |
| `id` | Stable company key, equal to `siren`. |
| `sourceUrl` | Search API URL that supplied this row. |
| `siren` | Nine-digit company identifier. |
| `name` | Full company name. |
| `siret` | SIRET of the head office. |
| `legalForm` | INSEE `nature_juridique` code. |
| `nafCode` | Company's primary activity code. |
| `headcountBand` | Employee-count band code when supplied. |
| `companyCategory` | Size category such as PME, ETI, or GE. |
| `creationDate` | Company's creation date. |
| `status` | Administrative status code, `A` (active) or `C` (closed). |
| `address` | Full head-office address. |
| `postalCode` | Head-office postal code. |
| `city` | Head-office city name. |
| `latitude` | Head-office latitude when available. |
| `longitude` | Head-office longitude when available. |
| `establishmentCount` | Number of establishments reported for the company. |
| `vatNumber` | Intra-community VAT number, when the registry lists one. |
| `openEstablishmentCount` | Number of currently open establishments. |
| `closureDate` | Date the company ceased activity, when closed. |
| `lastUpdated` | Registry timestamp of the last update. |
| `acronym` | Registered acronym (sigle), when present. |
| `nafCodeNaf25` | Main activity code in the NAF 2025 nomenclature, when supplied. |
| `headcountBandLabel` | Plain-language label for `headcountBand` (for example "50 to 99 employees"), when the band is known. |
| `matchingEstablishments` | Establishments that matched your filters (for example the Paris sites of a company headquartered elsewhere), with SIRET, address, NAF code and status. `null` when the API returns none. |
| `isSocialEconomy` | True or false for the social and solidarity economy flag. |
| `isAssociation` | True or false for the association flag. |
| `collectiveAgreementIds` | IDCC collective agreement codes, when listed. |
| `directors` | Director objects from the API, when available. |
| `finances` | Year-keyed financial figures such as `ca` and `resultat_net`, when available and requested. |

A legal form code identifies a legal form in the INSEE classification; the Actor does not guess a human-readable label. A workforce band is also a code, not an exact employee count. Financial figures can be absent even for a valid company. Director records can include people or legal entities, with different properties for each kind. Consumers should handle `null` fields and inspect the director objects they use.

### How to use

Open the Actor's input form and enter at least one search query or filter. A common search is a department plus a NAF code. Set `maxItems` to the number of unique companies you want. Run the Actor, then open the dataset to view or export the rows. If you only need a short sample, use a small `maxItems` value; the Actor stops as soon as that many records have been saved.

For a name search, use `searchQueries`. It accepts names, SIREN or SIRET strings, and address text. For location research, use `departements` or `postalCodes`. For industry research, use `nafCodes`. Multiple entries in a list are searched separately and combined in one output. When you supply different filter lists, the Actor searches their combinations. The same SIREN is returned once even if several combinations match it.

`activeOnly` defaults to true and sends the API's active-status filter. Set it to false if you also want closed company results. For an exact nine-digit SIREN or fourteen-digit SIRET query, the API performs a direct lookup and ignores the other filters, including active status. The Actor logs a warning in that case. `includeFinances` controls whether the Actor includes the finances field in its output; when false, `finances` is `null`. It does not turn missing figures into zero. The endpoint includes directors and available finances in its normal response, so the Actor does not need to visit a company detail page for each row.

The search endpoint caps large result sets. The Actor requests at most 25 entries per API page, using a smaller fixed page size when `maxItems` is below 25 and follows pages until it reaches `maxItems` or the API result boundary. The Actor saves qualifying records from the first page before splitting, and stops immediately if that page satisfies `maxItems`. For a very broad search that reaches the API's 10,000-result cap, it splits by department, then by postal code when necessary. A very narrow postal-code query that still reaches the cap should be split further by a NAF code in the input. Requests are paced at no more than two search calls per second in the normal path, below the API's documented limit.

### Input

| Input | Description | Default |
| --- | --- | --- |
| `searchQueries` | Company name, identifier, or address terms. | Empty list |
| `departements` | French department codes, for example `75` or `69`. | Empty list |
| `postalCodes` | Five-digit French postal codes. | Empty list |
| `nafCodes` | NAF activity codes, for example `62.01Z`. | Empty list |
| `legalForms` | `nature_juridique` legal form codes. | Empty list |
| `headcountBands` | Employee band codes. | Empty list |
| `directorNames` | Director or officer names to search (e.g. `Dupont`). | Empty list |
| `minRevenue` / `maxRevenue` | Latest reported revenue range in euros. Companies without published figures are excluded when set. | Not set |
| `minNetResult` / `maxNetResult` | Latest net result range in euros (negative values allowed). | Not set |
| `companyCategory` | PME, ETI, or GE. | No category filter |
| `activeOnly` | Restrict search to active companies. | `true` |
| `includeFinances` | Include available financial data. | `true` |
| `maxItems` | Maximum unique rows, from 1 to 10,000. | `50` |
| `proxyConfiguration` | Apify proxy settings if needed. | No proxy |

This example searches active software-development companies with a matching presence in department 75 and returns up to 25 unique companies:

```json
{
  "departements": ["75"],
  "nafCodes": ["62.01Z"],
  "activeOnly": true,
  "includeFinances": true,
  "maxItems": 25
}
```

The Actor requires at least one nonempty search or filter list, or a revenue/net-result bound. Company category and output options alone are insufficient. `maxItems` is an exact ceiling: if seven qualifying unique records exist and you set it to seven, the dataset contains seven rows. If fewer qualify, the dataset contains the available rows. A well-formed search that matches nothing finishes successfully with an empty dataset. Its final status suggests removing a location, NAF, director or financial filter, trying an exact SIREN/SIRET, or setting `activeOnly` to false for closed companies. Single-digit department codes are padded with a leading zero, and Corsican codes are accepted in either letter case (for example, `1` becomes `01` and `2a` becomes `2A`). Department entries may contain comma-separated or semicolon-separated codes. Unsupported department targets are skipped with a clear log message; other department targets continue, and a run containing only unsupported departments succeeds with zero results. Invalid postal or NAF formats still fail input validation instead of producing placeholder records.

### Output

This is an excerpt of a real item from the current local prefill run (`departements: ["75"]`, `nafCodes: ["62.01Z"]`, `maxItems: 25`). Address fields describe the head office, even when a different establishment matched the filters.

```json
{
  "id": "380474494",
  "sourceUrl": "https://recherche-entreprises.api.gouv.fr/search?departement=75&activite_principale=62.01Z&etat_administratif=A&page=1&per_page=25",
  "siren": "380474494",
  "name": "EURO INFORMATION DEVELOPPEMENTS (EID)",
  "siret": "38047449400016",
  "legalForm": "5710",
  "nafCode": "62.01Z",
  "headcountBand": "51",
  "companyCategory": "GE",
  "creationDate": "1991-01-01",
  "status": "A",
  "address": "4 RUE FREDERIC-GUILLAUME RAIFFEISEN 67000 STRASBOURG",
  "postalCode": "67000",
  "city": "STRASBOURG",
  "latitude": 48.600490458,
  "longitude": 7.7573257675,
  "establishmentCount": 61
}
```

Rows are company-level, not one row per establishment; the head-office SIRET is not necessarily the establishment that matched a location filter.

### How much does it cost?

This Actor is charged per result saved to the dataset. A result is charged once when its row is written. Repeated SIRENs across pages or search combinations are skipped and do not create additional result rows. The `maxItems` limit is enforced before writing and charging another row. Check the Actor's **Pricing** tab for the current terms; this README deliberately does not quote an amount because Store terms can change.

An empty run has no result rows. Reducing `maxItems` is useful when validating a new filter combination, because the Actor stops collecting after the requested number of unique rows. API pages can contain duplicates or non-diffusible records, so the Actor may request more than one page to gather the requested count. The dataset row count, rather than the number of search requests, describes the output you receive.

### Use with AI agents (MCP)

Apify's MCP server can expose this Actor to an AI agent. Configure the MCP endpoint with the Store path, then ask for a search with explicit filters and a row limit:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=axiomworks/french-companies-scraper"
    }
  }
}
```

Example prompts are “Find up to 20 active French software companies with a presence in department 75 and include their SIRENs and legal forms” and “Search for boulangerie in department 69, return the company names, head-office cities, and source URLs.” An agent can use the field descriptions in the input schema to pick filters. It should state `maxItems` when a bounded result set matters. It should also explain the distinction between the matching search location and the displayed head-office address when presenting local search results.

Because the output includes stable identifiers and provenance, an agent can deduplicate records, cite the `sourceUrl`, and join the company data with another approved workflow. Fields such as workforce band and legal form are codes, so an agent should avoid presenting them as exact employee counts or legal-form labels unless it has a separate authoritative mapping. `null` in a finance field means the API did not return a figure, not that the figure is zero.

### Integrations and API

Use the Actor from an Apify workflow or call it through the Apify API. The examples below submit the same input and ask for dataset items. Supply your Apify credentials through your normal client environment; do not place them in a public script. The Actor itself reads the public registry endpoint without a target-site login.

Python with the Apify client:

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/french-companies-scraper").call(run_input={
    "departements": ["75"], "nafCodes": ["62.01Z"], "maxItems": 25
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["siren"], item["name"])
```

JavaScript with the Apify client:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/french-companies-scraper').call({
  departements: ['75'], nafCodes: ['62.01Z'], maxItems: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) process.stdout.write(`${item.siren} ${item.name}\n`);
```

cURL using an environment token:

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/axiomworks~french-companies-scraper/run-sync-get-dataset-items' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"departements":["75"],"nafCodes":["62.01Z"],"maxItems":25}'
```

Datasets export from Apify Console as JSON, CSV or Excel.

### FAQ

**Can I filter by revenue or by director?** Yes. Set `minRevenue`/`maxRevenue` or `minNetResult`/`maxNetResult` in euros, or list names in `directorNames`. The registry applies them to the latest figures it holds, so companies with no published finances are left out of revenue filters. The `finances` and `directors` fields show what matched.

**Can I search without a company name?** Yes. Supply a department, postal code, NAF code, legal-form code, or another supported filter. At least one search or filter value is needed. Broad searches can be large, so set `maxItems` deliberately.

**Can the same company appear twice?** The Actor uses SIREN as the stable ID and returns each SIREN only once per run, even if different pages or filters find it.

**What happens when a query finds nothing?** The run succeeds with zero dataset items and a warning. It does not write an error object as if it were a company.

**Does the Actor need a proxy?** The default is direct access to this public API. The optional `proxyConfiguration` input lets users configure Apify Proxy. Blocked or rate-limited requests are retried with backoff and fresh proxy sessions when a proxy is configured.

### Is it legal to scrape French companies?

The source is a public French government company search API based on open data. The Actor requests publicly available fields and does not access login-protected information. You remain responsible for your own use of the resulting data, including applicable privacy, attribution, and retention requirements. Public availability does not make every downstream use appropriate. Director information can concern identifiable people, so assess your purpose before storing or distributing it. This Actor is independent of the registry operator and does not claim official endorsement.

### Feedback

If a search filter appears to return unexpected records, include the input JSON and a `sourceUrl` from an affected row when reporting it. If a field is missing, note the SIREN and which field you expected, while avoiding unnecessary personal details. Reports with a reproducible input help distinguish API coverage limits from Actor mapping issues. You can also suggest additional company-level fields that are present in the public response and useful for analysis. The Actor's output schema and README can then be updated to match any verified change.

# Actor input Schema

## `searchQueries` (type: `array`):

Free-text terms to search, one per entry: company names ('boulangerie'), 9-digit SIREN ('380474494'), 14-digit SIRET or address text. An exact SIREN/SIRET does a direct lookup and ignores other filters. Max 200 characters each. Combine with departements/nafCodes to narrow. Optional if another filter is set.

## `departements` (type: `array`):

French department codes, e.g. 75, 01, 2A or 971; comma-separated codes also work. Single digits are padded and letters uppercased. Unsupported codes are skipped; if none match, the run succeeds with zero results. Combine with NAF or name filters.

## `postalCodes` (type: `array`):

Five-digit French postal codes, e.g. \['75001','69003']. Each code is searched separately and results are de-duplicated by SIREN. A malformed code fails the run with an input error.

## `nafCodes` (type: `array`):

NAF/APE activity codes in the form NN.NNL, e.g. \['62.01Z' (software development), '56.10A' (restaurants)]. Each code is searched separately and results are de-duplicated by SIREN. A malformed code fails the run with an input error.

## `legalForms` (type: `array`):

INSEE legal-form (nature juridique) codes, 4 digits, e.g. \['5710' (SAS), '5499' (SARL), '9220' (association)]. Companies matching any listed code are returned. Optional.

## `headcountBands` (type: `array`):

INSEE workforce band codes as used by the API, e.g. \['11' (10-19 employees), '12' (20-49), '21' (50-99)]. Each code is searched separately. Optional.

## `directorNames` (type: `array`):

Names of directors/officers to search, e.g. \['Dupont']. Returns companies where a listed director matches; each entry is searched separately. Optional; counts as a filter on its own.

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

Only companies whose latest reported revenue is at least this many euros, e.g. 10000000. Companies without published figures are excluded when set. Optional; counts as a filter on its own.

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

Only companies whose latest reported revenue is at most this many euros, e.g. 20000000. Companies without published figures are excluded when set. Optional.

## `minNetResult` (type: `integer`):

Minimum latest reported net result in euros, e.g. -100000 to include losses down to that amount. Requires a published net-result figure; companies lacking one do not match. Optional; combine with maxNetResult for a range.

## `maxNetResult` (type: `integer`):

Only companies whose latest net result is at most this many euros, e.g. 0 to find loss-making companies. Optional.

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

Company size category, e.g. 'PME': 'PME' (small/medium), 'ETI' (mid-cap), or 'GE' (large). Omit for all sizes. Supply at least one searchQueries entry, another filter list, or a financial bound too; category alone is insufficient.

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

Whether to restrict searches to administratively active companies: true (default) filters to status 'A'; false includes closed companies ('C'). Ignored for exact SIREN/SIRET lookups. At least one query or company filter is still required.

## `includeFinances` (type: `boolean`):

Whether to include available yearly financial figures: true (default) copies the finances object; false returns finances: null. Missing figures remain null. This output option does not disable revenue or net-result search filters.

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

Maximum unique companies across all filter combinations, 1-10000, default 50; e.g. 7 returns at most seven rows and charges only saved results. Fewer are returned when matches run out. Use 1-25 for a quick test.

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

Apify Proxy settings. Default: direct requests, which work for this public API. Enable Apify Proxy only if requests are blocked (the run then says so in its status message).

## Actor input object example

```json
{
  "searchQueries": [],
  "departements": [
    "75"
  ],
  "postalCodes": [],
  "nafCodes": [
    "62.01Z"
  ],
  "legalForms": [],
  "headcountBands": [],
  "directorNames": [],
  "activeOnly": true,
  "includeFinances": true,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset with one item per result, in the order found.

# 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 = {
    "departements": [
        "75"
    ],
    "nafCodes": [
        "62.01Z"
    ],
    "activeOnly": true,
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/french-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 = {
    "departements": ["75"],
    "nafCodes": ["62.01Z"],
    "activeOnly": True,
    "maxItems": 25,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/french-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 '{
  "departements": [
    "75"
  ],
  "nafCodes": [
    "62.01Z"
  ],
  "activeOnly": true,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/french-companies-scraper --silent --output-dataset

```

## MCP server setup

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