# French Real Estate Aggregator — Bien'ici, Notaires, C21, iad (`cyrilfaia/french-realestate-scraper`) Actor

Une recherche, cinq sources immobilières françaises (Bien'ici, notaires, Century 21, iad, Orpi) : annonces normalisées (prix, prix/m², surface, pièces, DPE, distance), doublons fusionnés, recherche par ville avec rayon, arrondissement, code postal, département ou région ; fiche complète en option.

- **URL**: https://apify.com/cyrilfaia/french-realestate-scraper.md
- **Developed by:** [Cyril Faia](https://apify.com/cyrilfaia) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 listings

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 Real Estate Aggregator — Bien'ici, Notaires, Century 21, iad, Orpi

One search, five French real-estate sources, one clean schema. The Actor queries **Bien'ici** (national portal, professional and private listings), **Immobilier des notaires** (notary offices, including interactive auctions and off-market sales), **Century 21**, **iad** and **Orpi** (agency networks) for the same place and filters, then returns **normalised listings**: price, price per m², surface, land, rooms, bedrooms, property type, postcode, distance from the searched place, energy class, seller type, exclusivity, photos, publication date. **The same property advertised on several boards is merged** (`alsoOn`, `alsoOnUrls`).

Search by **city with a radius** ("Marseille", "Aix-en-Provence"), **arrondissement** ("Marseille 8e", "Paris 11e"), **postcode** ("13008"), **département** ("13", "Gironde") or **region** ("Île-de-France"), sale or rental, with price, surface and rooms filters. Detail mode opens each listing for the **full description, DPE, floor, year built, charges, property tax, features, agency and phone where published**.

### Who uses it

- **Agencies and mandataries ("pige")**: what comes on the market in a sector, across networks, every morning.
- **Investors and buyers' agents**: price per m² by postcode, price drops, exclusivities, notary sales below market.
- **Proptech, valuation and data teams**: a single normalised French feed instead of five scrapers.
- **Local media, economic development, researchers**: market depth and price levels per commune.
- **AI agents**: "3-room flats under 300 000 € within 5 km of Aix-en-Provence, sorted by distance, with DPE".

### Output example

```json
{
  "source": "century21",
  "id": "11570864838",
  "url": "https://www.century21.fr/trouver_logement/detail/11570864838/",
  "title": "Appartement F3 à vendre",
  "transaction": "buy",
  "propertyType": "flat",
  "price": 159000,
  "pricePerSquareMeter": 4035.53,
  "surface": 39.4,
  "rooms": 3,
  "city": "MARSEILLE",
  "postcode": "13010",
  "department": "13",
  "energyClass": "C",
  "greenhouseGasClass": "C",
  "sellerType": "professional",
  "sellerName": "CENTURY 21 Longchamp Immobilier",
  "sellerPhone": "04 91 86 44 24",
  "reference": "1064",
  "isExclusive": true,
  "floor": 6,
  "charges": 213,
  "propertyTax": "2526",
  "hasElevator": true,
  "description": "13010 / CAPELETTE En plein cœur du 10e arrondissement…",
  "descriptionIsFull": true,
  "alsoOn": ["bienici"],
  "alsoOnUrls": ["https://www.bienici.com/annonce/ag130-123456"],
  "scrapedAt": "2026-09-17T18:40:00.000Z"
}
```

Bien'ici rows add GPS coordinates, DPE and district; notary rows add the office phone, fees and an `isAuction` flag; iad rows add the advisor; Orpi rows add the price-per-m² as published and the neighbourhood.

### Input

| Field | Type | Description |
|---|---|---|
| `location` | string | City, arrondissement, postcode, département or region (required). |
| `radiusKm` | integer | Around a city (default 10). |
| `transaction` | `buy` / `rent` | |
| `propertyTypes` | string\[] | `flat`, `house`, `land`, `parking`, `building`, `commercial`. |
| `minPrice`, `maxPrice` | integer | EUR (monthly rent for rentals). |
| `minArea`, `maxArea`, `minRooms` | integer | |
| `sources` | string\[] | `bienici`, `notaires`, `century21`, `iad`, `orpi` (default all). |
| `maxItemsPerSource` | integer | Default 100. |
| `maxItems` | integer | Default 300, 0 = unlimited. |
| `dedupe` | boolean | Merge the same property across boards (default true). |
| `fetchDetails` | boolean | Full listings (Bien'ici, Century 21, iad). |

Examples:

```json
{ "location": "Marseille 8e", "transaction": "buy", "propertyTypes": ["flat"], "maxPrice": 400000, "minRooms": 3, "fetchDetails": true }
```

```json
{ "location": "Aix-en-Provence", "radiusKm": 15, "propertyTypes": ["house"], "minArea": 100, "sources": ["bienici", "notaires", "iad"] }
```

```json
{ "location": "Gironde", "transaction": "rent", "propertyTypes": ["flat"], "maxItemsPerSource": 300, "maxItems": 0 }
```

### Pricing

Pay per event: one **listing** event per exported row, one **listing detail** event per row when `fetchDetails` is on, plus a small **Actor start** fee. The boards are read through their public pages and JSON endpoints: no browser, no residential proxies, a city search finishes in under a minute.

### Notes

- Places are resolved with the French government geo API; the radius uses commune centroids for boards without coordinates and exact GPS for Bien'ici.
- Century 21 is read by postcode pages, iad by département pages, Orpi by city and arrondissement pages (about 30 listings per page), the notaries through their public listings API.
- Private sellers are never named or identified; professional sellers (agencies, networks, notary offices) are named as published. No personal contact data is collected.
- Listings belong to the boards and their advertisers; use the output for research, monitoring and prospecting in compliance with each site's terms.

# Actor input Schema

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

City ("Marseille", "Aix-en-Provence"), arrondissement ("Marseille 8e", "Paris 11e"), postcode ("13008"), département ("13", "Gironde") or region ("Île-de-France"). Resolved through the French government geo API.

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

Around a city: neighbouring communes within this distance are included (ignored for a postcode, département or region).

## `transaction` (type: `string`):

Sale or rental.

## `propertyTypes` (type: `array`):

flat, house, land, parking, building, commercial.

## `minPrice` (type: `integer`):

Sale price or monthly rent.

## `maxPrice` (type: `integer`):

Sale price or monthly rent.

## `minArea` (type: `integer`):

Living surface.

## `maxArea` (type: `integer`):

Living surface.

## `minRooms` (type: `integer`):

Number of rooms (pièces).

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

Bien'ici (portal, pros and private sellers), Immobilier des notaires (notary offices, incl. auctions), Century 21, iad and Orpi (agency networks).

## `maxItemsPerSource` (type: `integer`):

Stop reading a board after this many kept listings.

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

Overall cap after merging (0 = no cap).

## `dedupe` (type: `boolean`):

Same property (postcode, surface, price, rooms) seen on several boards is exported once with `alsoOn` and `alsoOnUrls`.

## `fetchDetails` (type: `boolean`):

Open each listing for the complete description, DPE, floor, year built, charges, tax, features, agency and phone where published (one 'listing-detail' event per row instead of 'listing').

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

Datacenter proxies are enough for these boards.

## Actor input object example

```json
{
  "location": "Marseille 8e",
  "radiusKm": 10,
  "transaction": "buy",
  "propertyTypes": [
    "flat",
    "house"
  ],
  "sources": [
    "bienici",
    "notaires",
    "century21",
    "iad",
    "orpi"
  ],
  "maxItemsPerSource": 100,
  "maxItems": 300,
  "dedupe": true,
  "fetchDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Dataset items, one per listing (JSON).

## `listingsCsv` (type: `string`):

Same dataset as CSV.

# 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 = {
    "location": "Marseille 8e",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("cyrilfaia/french-realestate-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 = {
    "location": "Marseille 8e",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("cyrilfaia/french-realestate-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 '{
  "location": "Marseille 8e",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call cyrilfaia/french-realestate-scraper --silent --output-dataset

```

## MCP server setup

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