# SeLoger, Leboncoin, Bien'ici, PAP & Logic-Immo Scraper (`cycha/france-real-estate-scraper`) Actor

French property listings from Leboncoin, SeLoger, Bien'ici, PAP and Logic-Immo in one run, one format: price, m², rooms, DPE, photos, agency, compared with real sale prices (DVF). Buy or rent, any city, postcode or département. Only-new mode for alerts.

- **URL**: https://apify.com/cycha/france-real-estate-scraper.md
- **Developed by:** [Ken Digital](https://apify.com/cycha) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 37 total users, 2 monthly users, 97.8% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 property listings

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

## SeLoger, Leboncoin, Bien'ici, PAP & Logic-Immo Scraper

French property listings from **Leboncoin**, **SeLoger**, **Bien'ici**, **PAP** and **Logic-Immo** in a single run and a single format. Every row has price, €/m², surface, rooms, bedrooms, floor, DPE energy class, photos, publication date and seller type. Each sale listing is also compared with the **real prices paid nearby**, from the government's DVF register of property sales. Search to buy or to rent, by city, postcode or département. Turn on **Only new listings** and schedule it for property alerts that never repeat a listing.

> **New name:** this actor is now `cycha/france-real-estate-scraper` (it was `joyouscam35875/france-real-estate-scraper` until 21 October 2026). If an API call or integration stopped working, update the name, or use the actor ID `u5Ywbqhs8BTWEOZKI`, which never changes.

*Annonces immobilières Leboncoin, SeLoger, Bien'ici, PAP et Logic-Immo en une seule recherche : prix, €/m², surface, pièces, DPE, photos, agence, comparées aux prix de vente réels (DVF). Achat ou location, par ville, code postal ou département. Mode « nouvelles annonces uniquement » pour des alertes.*

- **Five sites, one schema.** Same fields whatever the site; `source` tells you where each listing came from. A flat posted on several sites is returned once.
- **Market check included.** For sales, `marketPricePerSqm` is the median €/m² actually paid for the same type of home in the same postcode over the last two years, and `priceVsMarket` is this listing's €/m² divided by it (0.85 = 15% below the market). Viagers, bare-ownership sales and auctions list only part of the price: they are marked in `saleType` and get no `priceVsMarket`, so they never pose as bargains.
- **Real filters:** buy or rent, apartment / house / land / parking, price, surface, rooms.
- **Only new listings** remembers what earlier runs delivered, so scheduled runs return and bill only fresh listings.
- **No login, no account, no proxy setup.** The actor handles access to every site itself.

### Sample output

Five apartments for sale in Nantes from a real run (one per site). `vs market` is the listing's €/m² divided by the median €/m² actually paid in the same postcode (DVF): 0.85 means 15% below the market. Each row also has photos, floor, bedrooms, agency, coordinates and publication date.

| Site | City | Price | m² | €/m² | Rooms | DPE | Market €/m² | vs market |
|---|---|---|---|---|---|---|---|---|
| Leboncoin | Nantes 44000 | €322,090 | 76 | €4,238 | 2 | — | €3,781 | 1.12 |
| SeLoger | Nantes 44000 | €286,200 | 70.76 | €4,044 | 3 | C | €3,781 | 1.07 |
| Bien'ici | Nantes 44300 | €87,900 | 19.44 | €4,521 | 1 | E | €3,125 | 1.45 |
| PAP | Nantes 44000 | €730,000 | 140 | €5,214 | 4 | C | €3,781 | 1.38 |
| Logic-Immo | Nantes 44000 | €257,000 | 80.34 | €3,198 | 3 | D | €3,781 | 0.85 |

### Quick start

```json
{
  "location": "Lyon",
  "transactionType": "buy",
  "propertyTypes": ["apartment"],
  "maxPrice": 350000,
  "minSurface": 50,
  "maxResults": 200
}
```

**Daily alert:** add `"onlyNewListings": true`, save as a task, schedule it every morning, and connect Slack, email or Google Sheets from the task's Integrations tab.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `location` | string | required | City (`Lyon`, `Saint-Étienne`), postcode (`75011`, `69003`) or département (`33`, `Gironde`). One per line for several searches. |
| `transactionType` | string | `buy` | `buy` or `rent`. |
| `propertyTypes` | array | apartment, house | `apartment`, `house`, `land`, `parking`, `other`. |
| `minPrice` / `maxPrice` | integer | | Sale price, or monthly rent. |
| `minSurface` / `maxSurface` | integer | | Living area in m². |
| `minRooms` | integer | | Pièces (T3 = 3). |
| `sources` | array | all five | `leboncoin`, `seloger`, `bienici`, `pap`, `logicimmo`. |
| `maxResults` | integer | 100 | Per location, shared across the selected sites. `0` = everything (up to 5,000). |
| `marketComparison` | boolean | true | Add DVF market prices to sale listings. |
| `onlyNewListings` | boolean | false | Return only listings not delivered by earlier runs of the same searches (one found by two searches is sent once). |

Earlier inputs (`propertyType` as a single value) still work, and rows keep the earlier `location`, `dvfMedianPrice` and `opportunityScore` fields for existing integrations.

### Output

```json
{
  "listingId": "seloger:268MUDI8TF75",
  "source": "seloger",
  "url": "https://www.seloger.com/annonce/achat/auvergne-rhone-alpes/rhone-69/lyon-69000/268MUDI8TF75",
  "title": "Superbe 3 pièces",
  "transactionType": "buy",
  "propertyType": "apartment",
  "price": 189000,
  "pricePerSqm": 2739.13,
  "surface": 69,
  "rooms": 3,
  "bedrooms": 2,
  "floor": "2/5",
  "energyClass": "A",
  "newBuild": true,
  "city": "Lyon 8ème arrondissement",
  "postalCode": "69008",
  "departmentCode": "69",
  "description": "Lyon 8ème : Appartement T3 Neuf – Éclat et Confort à Proximité des Transports...",
  "photos": ["https://..."],
  "sellerType": "agency",
  "agencyName": "Example Immobilier",
  "publishedAt": "2026-10-01T09:12:00Z",
  "marketPricePerSqm": 4310,
  "marketSampleSize": 812,
  "marketScope": "postcode",
  "priceVsMarket": 0.636,
  "searchLocation": "Lyon",
  "scrapedAt": "2026-10-07T10:00:00+00:00"
}
```

Fields a site does not publish are `null`: Leboncoin and SeLoger give the most detail; PAP cards have no floor or agency, since PAP sellers are private individuals. `sellerType` is `agency` or `private`. Names of private sellers are never exported.

### Pricing

Pay per event: one `result` event per listing row, market comparison included, plus a tiny actor-start fee. With **Only new listings** on, a run with nothing new costs only the start fee.

### Use cases

- **Property alerts** for a city and budget, every morning, across five sites at once
- **Deal hunting for investors:** sort by `priceVsMarket` to see listings priced under what homes actually sold for nearby
- **Agencies and mandate hunters:** new private-seller listings (`sellerType: private`) from PAP and Leboncoin
- **Market studies:** asking prices vs. sale prices, €/m² by postcode, DPE mix, supply by site

### Integrations

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("cycha/france-real-estate-scraper").call(run_input={
    "location": "Bordeaux",
    "propertyTypes": ["apartment"],
    "maxPrice": 300000,
    "onlyNewListings": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["source"], row["price"], row["surface"], row["priceVsMarket"], row["url"])
```

Works with Make, Zapier, n8n, Google Sheets, schedules and webhooks, and as an MCP tool for AI agents.

### FAQ

**How is `priceVsMarket` computed?** From DVF, the public register of every property sale in France. The actor reads the two latest full years for the département, keeps sales of exactly one apartment or house, and takes the median €/m² for the listing's postcode (or its commune or département when the postcode has fewer than 5 sales). It is a first filter, not a valuation: condition, floor and view are not in DVF.

**Why do I sometimes get fewer listings from one site?** Real-estate sites protect their pages against automated traffic. The actor retries with fresh connections, but a site can still refuse a run now and then. When that happens the run still succeeds with the other sites, and the status message names the site that was unavailable. Re-running usually works.

**How are duplicates detected?** Same postcode, same price and same surface. When a listing is on several sites, the first site to return it wins.

**What if my run has a short timeout?** The actor stops shortly before it, keeps every listing already saved, and ends successfully with a message saying so.

**Is it legal?** The actor reads publicly visible listings and does not export private sellers' names or contact details. You are responsible for how you use the data and for complying with each site's terms and the GDPR.

### Feedback

Missing a field or a site? Open an issue on the actor's **Issues** tab. If this scraper saved you time, a short review on the Store page helps other people find it.

### Related actors by the same developer

| Actor | What it does |
|---|---|
| [Welcome to the Jungle, France Travail, Hellowork & Cadremploi](https://apify.com/cycha/france-job-scraper) | French job offers from four sites, only-new mode |
| [LinkedIn Jobs Scraper](https://apify.com/cycha/linkedin-jobs-scraper) | LinkedIn jobs with full descriptions and only-new mode |
| [Google Maps Scraper](https://apify.com/cycha/google-maps-scraper) | Businesses, ratings and contact details from Google Maps |

# Actor input Schema

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

City, département number or postcode. One per line for several searches. Examples: Lyon, Bordeaux, 33, 75011, Gironde.

## `transactionType` (type: `string`):

Properties for sale or for rent.

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

PAP has only apartments, houses and land.

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

Sale price, or monthly rent when renting.

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

Sale price, or monthly rent when renting.

## `minSurface` (type: `integer`):

Living area.

## `maxSurface` (type: `integer`):

Living area.

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

Rooms in the French sense: T3 = 3 pièces.

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

Which sites to search. All five by default.

## `maxResults` (type: `integer`):

Shared across the selected sites. 0 = everything the sites return (up to 5,000).

## `marketComparison` (type: `boolean`):

Adds the median €/m² actually paid nearby in the last two years, from the government's DVF register, and how this listing compares. Sales only.

## `onlyNewListings` (type: `boolean`):

Remember the listings delivered by earlier runs of the same searches and return only listings not delivered before, even when another search of the task found them. You only pay for new listings.

## Actor input object example

```json
{
  "location": "Lyon",
  "transactionType": "buy",
  "propertyTypes": [
    "apartment",
    "house"
  ],
  "sources": [
    "leboncoin",
    "seloger",
    "bienici",
    "pap",
    "logicimmo"
  ],
  "maxResults": 100,
  "marketComparison": true,
  "onlyNewListings": false
}
```

# Actor output Schema

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

One row per listing, same fields for every site.

# 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": "Lyon"
};

// Run the Actor and wait for it to finish
const run = await client.actor("cycha/france-real-estate-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": "Lyon" }

# Run the Actor and wait for it to finish
run = client.actor("cycha/france-real-estate-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": "Lyon"
}' |
apify call cycha/france-real-estate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cycha/france-real-estate-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/u5Ywbqhs8BTWEOZKI/builds/9QI4hL5Q4l7tGnh8G/openapi.json
