# SeLoger Scraper — Annonces, Prix & Agence (`noahadler/seloger-scraper`) Actor

Scrape SeLoger immobilier annonces (achat or location): price EUR, m², rooms and agency name. Search by city or postcode — a clean listing schema, not a pasted search URL. France residential proxy recommended.

- **URL**: https://apify.com/noahadler/seloger-scraper.md
- **Developed by:** [Noah Adler](https://apify.com/noahadler) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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 Scraper — Annonces Immobilier

**SeLoger scraper** for **seloger immobilier** annonces: price in euros, living area in m², rooms, agency name, agency profile and price drops. One Dataset row per listing, from a city, a postcode, or a SeLoger place id.

> Search pages on seloger.com already embed the card payload (price, m², agency, price history). This Actor reads that payload over HTTP. It does not paste a raw search URL and dump the page. **France residential proxy is the default** because SeLoger uses DataDome.

**seloger api** shape for buyers who want annonces, not a generic crawl: `price` is the asking price, `areaSqm` is the living area, `pricePerSqm` is computed from those two, and `agencyName` is the agency on the card.

### Table of contents

- [What you get](#what-you-get)
- [How it works](#how-it-works)
- [Features](#features)
- [Input](#input)
- [Output](#output)
- [Use cases](#use-cases)
- [API quick start](#api-quick-start)
- [Proxy](#proxy)
- [FAQ](#faq)
- [Limitations](#limitations)
- [Racimo](#racimo)
- [Keywords](#keywords)

### What you get

**Listing**

- `listingId`, `title`, `url` on seloger.com
- `transaction` (`buy` / `rent`) and `propertyType`
- `price` in EUR (not the €/m² string)
- `previousPrice`, `priceChangePercent`, `priceDropped` when SeLoger shows a price change
- `areaSqm`, `rooms`, `bedrooms`, `pricePerSqm`, `energyLabel` (DPE)

**Place**

- `city`, `zipcode`, `district`
- `placeId` (the SeLoger id that was actually searched, e.g. `AD08FR28808`)
- `locationQuery` (what you typed)

**Agence**

- `sellerType` (`agency` or `private`)
- `agencyName`, `agencyUrl` (professionnels-immobilier profile), `agencyPhone` when the card exposes it

A dedicated **seloger agence** lead Actor is a later step in the same racimo, after this hero has runs. This scraper already returns the agency printed on the annonce.

### How it works

| Step | Action |
|------|--------|
| 1 | Resolve `location` to a SeLoger place id. A city or postcode goes through the French communes API, then SeLoger's own city URL. A value like `AD08FR28808` is used as-is. |
| 2 | Open `classified-search` with transaction, property type, price, m², rooms and sort. |
| 3 | Read the embedded search JSON and map each card to one row. |
| 4 | Paginate until `maxItems` or the last page (~30 annonces per page, cap 300). |

### Features

| | |
|--|--|
| **Structured search** | City, postcode or place id. Filters for price, m² and rooms. |
| **Clean schema** | Price, m² and €/m² are separate fields. A price drop is a boolean plus the previous price. |
| **Agence on the card** | Agency name, profile URL and phone when SeLoger prints them on the result. |
| **Achat and location** | `buy` or `rent`. |
| **HTTP** | No Playwright. Residential FR proxy when DataDome blocks the IP. |

### Input

| Field | Required | Description |
|-------|----------|-------------|
| `location` | Yes | `Lyon`, `69003`, `AD08FR28808`, or a seloger.com URL that contains a place id |
| `transaction` | No | `buy` (default) or `rent` |
| `propertyType` | No | `apartment` (default), `house`, `parking`, `land`, `office`, `commercial`, `any` |
| `maxItems` | No | 1–300 (default 30) |
| `minPrice` / `maxPrice` | No | EUR. Monthly rent when `transaction` is `rent` |
| `minSurface` / `maxSurface` | No | Living area, m² |
| `minRooms` | No | Minimum pièces |
| `sort` | No | `relevance`, `newest`, `price_asc`, `price_desc` |
| `onlyPrivate` | No | Drop agency cards |
| `proxyConfiguration` | No | Default RESIDENTIAL + FR |

#### Example — Lyon apartments for sale

```json
{
  "location": "Lyon",
  "transaction": "buy",
  "propertyType": "apartment",
  "maxItems": 50,
  "minPrice": 150000,
  "maxPrice": 400000,
  "minSurface": 40,
  "sort": "newest",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "FR"
  }
}
```

#### Example — rentals by postcode

```json
{
  "location": "33000",
  "transaction": "rent",
  "propertyType": "apartment",
  "maxItems": 30,
  "maxPrice": 1200
}
```

### Output

```json
{
  "listingId": "26N55L7BPHGJ",
  "title": "Appartement à vendre",
  "url": "https://www.seloger.com/annonce/achat/nouvelle-aquitaine/gironde-33/bordeaux-33000/26N55L7BPHGJ",
  "transaction": "buy",
  "propertyType": "Appartement",
  "price": 235000,
  "previousPrice": null,
  "priceChangePercent": null,
  "priceDropped": false,
  "pricePerSqm": 3615.38,
  "areaSqm": 65,
  "rooms": 3,
  "bedrooms": 2,
  "energyLabel": "C",
  "city": "Bordeaux",
  "zipcode": "33100",
  "district": "La Bastide",
  "sellerType": "agency",
  "agencyName": "HOMKI",
  "agencyUrl": "https://www.seloger.com/professionnels-immobilier/Vfr29yp7tcCfp2xFQZvNBR",
  "agencyPhone": "04 13 68 02 02",
  "placeId": "AD08FR13100",
  "locationQuery": "33000",
  "error": false
}
```

| Field | Meaning |
|-------|---------|
| `price` | Asking price in euros. Sale or monthly rent. Never the €/m² line. |
| `pricePerSqm` | `price / areaSqm`, rounded. Empty when area is missing. |
| `priceDropped` | True when SeLoger shows a downward price arrow, or the previous price is higher. |
| `priceChangePercent` | Signed percent. Negative means a drop. |
| `agencyName` | Agency printed on the card, or the private-seller label. |
| `error` | `true` only on a hard failure (block or unknown location), with `errorMessage`. |

An empty search pushes one row with `error: false` and a short message. A DataDome block pushes `error: true` and tells you to use residential FR.

### Use cases

- Track **seloger annonces** in one city for pricing and new stock
- Spot **price drops** (`priceDropped`) for acquisition lists
- Attach an **agence** to each annonce without opening the detail page
- Feed a CRM with Lyon, Bordeaux or Paris listings on a schedule
- Compare achat vs location by running the Actor twice with `transaction`

### API quick start

```bash
apify call noahadler/seloger-scraper --input '{
  "location": "Lyon",
  "transaction": "buy",
  "propertyType": "apartment",
  "maxItems": 20
}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("noahadler/seloger-scraper").call(run_input={
    "location": "Lyon",
    "transaction": "buy",
    "propertyType": "apartment",
    "maxItems": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["price"], item["areaSqm"], item["agencyName"], item["url"])
```

### Proxy

SeLoger often answers a home IP and blocks a datacenter IP. The default input enables **Apify RESIDENTIAL** with **country FR**. If you clear the proxy and the run returns `error: true` mentioning DataDome, turn residential FR back on. Do not switch to a headless browser as a first fix.

### FAQ

**City or place id?** Either. `Lyon` and `69003` resolve to a place id. `AD08FR28808` skips resolution. Ambiguous names use the most populous commune.

**Is this a search-URL scraper?** No. You set city, transaction, type, price and m². A seloger.com URL is accepted only as a way to pass a place id.

**Where is the full description and every photo?** On the search card we keep the fields that are stable: price, m², rooms, DPE, agency, one photo URL. A detail Actor is the next piece of the racimo, after this one has runs.

**Rent prices look small.** They are monthly rents, not sale prices. `transaction` tells you which.

**Private sellers only?** Set `onlyPrivate`. Most SeLoger stock is agencies, so the result can be short.

### Limitations

- France, seloger.com annonces only. Sister brands linked from a card are skipped.
- Cap 300 rows per run (~10 pages).
- Phone and agency URL are whatever the search card shows. A full agency directory is a separate Actor.
- Strong antibot: residential FR is the supported setup.
- City resolution picks one commune. For a neighbourhood, pass its place id.

### Racimo

This is the hero. Same site, not built yet:

| Actor | When |
|-------|------|
| `seloger-scraper` | Now. Search annonces. Volume PPE. |
| `seloger-detail` | After this hero has runs (7–14 days). Full fiche. |
| `seloger-agences` | Same gate. Agency leads, higher PPE. |

### Keywords

seloger scraper, seloger api, seloger immobilier, seloger annonces, seloger agence

# Actor input Schema

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

French city (Lyon), 5-digit postcode (69003), SeLoger place id (AD08FR28808), or a seloger.com search URL. The largest matching commune is used when several cities share a name.

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

buy = achat / for sale. rent = location / to rent.

## `propertyType` (type: `string`):

SeLoger estate type. any leaves the type filter off.

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

Maximum listings to save (1–300). About 30 annonces per search page.

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

Optional minimum price in euros. Sale prices are the asking price; rent prices are monthly.

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

Optional maximum price in euros.

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

Optional minimum living area in square metres.

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

Optional maximum living area in square metres.

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

Optional minimum number of rooms (pièces), not bedrooms.

## `sort` (type: `string`):

SeLoger sort. newest maps to DateDesc.

## `onlyPrivate` (type: `boolean`):

Keep particulier listings and drop agency cards.

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

SeLoger sits behind DataDome. Default: Apify RESIDENTIAL, country France (FR). Turn the proxy off only for a local smoke test.

## Actor input object example

```json
{
  "location": "Lyon",
  "transaction": "buy",
  "propertyType": "apartment",
  "maxItems": 30,
  "sort": "relevance",
  "onlyPrivate": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}
```

# Actor output Schema

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

No description

# 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("noahadler/seloger-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("noahadler/seloger-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 noahadler/seloger-scraper --silent --output-dataset

```

## MCP server setup

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