# ImmoScout24.ch Scraper — Swiss Apartments & Houses (`studio-amba/immoscout24-ch-residential-scraper`) Actor

Scrape residential property listings from immoscout24.ch (Switzerland): apartments and houses for rent or sale. CHF prices, rooms, living space, address and coordinates.

- **URL**: https://apify.com/studio-amba/immoscout24-ch-residential-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 result scrapeds

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/platform/actors/running/actors-in-store#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

## ImmoScout24.ch Scraper — Swiss Residential Real Estate

Scrape residential real estate listings from [immoscout24.ch](https://www.immoscout24.ch), Switzerland's largest property portal (SMG Swiss Marketplace Group). Apartments and houses, for rent and for sale, across all 26 cantons.

This is the Swiss platform. It is a different company and a different website than German immobilienscout24.de.

**Residential only.** This actor covers apartments and houses. For offices, Gewerbe, storage and building land on the same site, use [immoscout24-ch-commercial-scraper](https://apify.com/studioamba/immoscout24-ch-commercial-scraper) instead — the two actors share a platform but not a search scope, and their outputs are not interchangeable.

### What you get

Structured JSON for every listing: title, description, CHF price with its billing interval, gross and net rent, rooms, living space, address with coordinates, canton, category tags, photos and the listing URL.

Price on application (Preis auf Anfrage) happens occasionally, most often on new-build or off-market listings. Those listings keep `price: null`. The scraper never invents a number.

### Use cases

- Track apartment and house rents or asking prices across Swiss cities
- Build a pipeline of available homes for a relocation search
- Monitor supply and price trends in a specific city or canton over time
- Feed listing data into a relocation, valuation or market research tool
- Compare furnished short-stay apartments against traditional unfurnished rentals

### How to scrape ImmoScout24 Switzerland data

1. Pick a location. Swiss city or canton names work in German, French or Italian spelling: `Zürich`, `Genève`, `Lugano`, `Bern`, `Basel`, `Kanton Waadt`.
2. Pick a listing type (rent or sale).
3. Set `maxResults` and run. The scraper resolves the location, walks the result pages (20 listings per page) and pushes each listing as one dataset item.

The site's anti-bot protection (DataDome) is handled automatically by the built-in unlocking service. You do not need to configure anything for it.

#### Example: apartments and houses for rent in Zürich

```json
{
    "searchQuery": "Zürich",
    "listingType": "rent",
    "maxResults": 100
}
```

#### Example: property for sale in Geneva, French spelling

```json
{
    "searchQuery": "Genève",
    "listingType": "sale",
    "maxResults": 50
}
```

#### Example: a whole canton

```json
{
    "searchQuery": "Kanton Bern",
    "listingType": "rent",
    "maxResults": 200
}
```

#### Example: your own filtered search URL

Set filters on immoscout24.ch (rooms, price band, living space, property type) and paste the result URL:

```json
{
    "startUrls": [{ "url": "https://www.immoscout24.ch/de/immobilien/mieten/kanton-zuerich?nr=3.5-&pf=1500&pt=3000" }],
    "maxResults": 200
}
```

### Output example

```json
{
    "listingId": "4002086141",
    "listingTitle": "City Pop - Cosy Studio Apartments close to Zürich centre",
    "description": "Neu eröffnet! Ab dem 10.04.2025 bieten wir zentral gelegene Apartments...",
    "transactionType": "rent",
    "propertyType": "Apartment",
    "categories": ["APARTMENT", "FLAT"],
    "price": 2042,
    "currency": "CHF",
    "priceInterval": "MONTH",
    "grossPrice": 2042,
    "netPrice": null,
    "rooms": 1,
    "areaM2": 17,
    "floor": null,
    "yearBuilt": 2025,
    "street": "Rotbuchstrasse 9",
    "postalCode": "8006",
    "location": "Zürich",
    "canton": "ZH",
    "latitude": 47.386589622021,
    "longitude": 8.548501805136,
    "agencyLogoUrl": "https://cdn.immoscout24.ch/t_customer_logo/logos/l_e335city_v2.png",
    "language": "de",
    "imageUrl": "https://cdn.immoscout24.ch/listings/v2/.../image/....jpg",
    "imageUrls": ["https://cdn.immoscout24.ch/listings/v2/.../image/....jpg"],
    "createdAt": "2025-04-07T14:34:53.213Z",
    "url": "https://www.immoscout24.ch/mieten/4002086141",
    "source": "immoscout24.ch",
    "scrapedAt": "2026-08-21T20:17:37.026Z"
}
```

### Price fields explained

| Field | Meaning |
|---|---|
| `price` | Gross rent (or net, if gross is missing) for rent listings; purchase price for sale listings |
| `priceInterval` | Rent billing interval: `MONTH`, `YEAR`, `WEEK` or `DAY`. `null` for sale listings |
| `grossPrice` | Bruttomiete (gross rent) or purchase price |
| `netPrice` | Nettomiete (net rent), where the lister publishes it separately |
| `null` price | Price on application (Preis auf Anfrage) |

### Property types

The `categories` field carries the site's own tags (e.g. `APARTMENT`, `FLAT`, `HOUSE`, `SINGLE_HOUSE`, `CASTLE`, `TERRACE_HOUSE`). `propertyType` is a human-readable version of the first tag. Filter by `categories` if you need apartments only or houses only from a mixed search.

### Input reference

| Field | Type | Description |
|---|---|---|
| `searchQuery` | string | Swiss city or canton (DE/FR/IT spelling). Empty = Zürich |
| `listingType` | string | `rent` or `sale` |
| `startUrls` | array | Full immoscout24.ch search URLs, overrides the fields above |
| `maxResults` | integer | Cap on returned listings (default 50) |
| `brightDataApiKey` | string | Optional own unlocker key, normally leave empty |
| `proxyConfiguration` | object | Not used for fetching, kept for platform compatibility |

### Cost of usage

You pay per result plus a small run start fee. One fetched page yields 20 listings, so a 100-listing run needs about 5 page fetches and typically finishes in under a minute.

A run's usage cost only settles after the run reports SUCCEEDED. Reading the dataset mid-run shows a partial cost that can be far lower than the final one.

### Good to know

- The site serves at most 1000 results per search. Searches over that cap get a log warning; split by city for full coverage.
- Listings are deduplicated by listing ID within a run, also across multiple start URLs.
- The listing's own `offerType` decides `transactionType` in the output, so a mixed start URL still labels every row correctly.
- Listing text comes in the lister's primary language (`language` field: de, fr, it or en).
- Long runs survive platform migrations: the scraper resumes from the last completed page instead of restarting.
- If Bright Data can't get past the site's anti-bot protection during a run, the run fails with a message that says so explicitly — it won't report success with zero listings.

### Legality

This scraper reads only publicly available listing data, the same information any visitor sees in a browser. It stores no personal data beyond what listers publish themselves (agency names and business contact details). For commercial reuse of the data, check the portal's terms and applicable law in your jurisdiction.

# Actor input Schema

## `searchQuery` (type: `string`):

Swiss city or canton to search. German, French or Italian spellings all work (e.g. 'Zürich', 'Genève', 'Lugano', 'Bern', 'Basel', 'Kanton Waadt'). Leave empty to search Zürich. For district-level searches, paste a full search URL into Start URLs instead.

## `listingType` (type: `string`):

Rent (Mieten) or buy (Kaufen).

## `startUrls` (type: `array`):

ImmoScout24.ch search result URLs, as an alternative to the Location field. Go to immoscout24.ch, set your filters (apartment/house, rooms, price, etc.), and paste the resulting URL(s) (e.g. https://www.immoscout24.ch/de/immobilien/mieten/ort-zuerich). Overrides Location/Listing Type when provided.

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

Hard cap on the number of listings returned (20 listings per fetched page). The site serves at most 1000 results per search — narrow the location for full coverage of large searches.

## `brightDataApiKey` (type: `string`):

Optional: your own Bright Data API key for the Web Unlocker zone. Leave empty to use the built-in unlocking service.

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

Not used for fetching — ImmoScout24.ch's DataDome anti-bot is handled automatically by the built-in unlocking service (same platform and protection as immoscout24-ch-commercial-scraper — plain proxy requests do not pass). Kept for platform compatibility.

## Actor input object example

```json
{
  "searchQuery": "Zürich",
  "listingType": "rent",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchQuery": "Zürich",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/immoscout24-ch-residential-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 = {
    "searchQuery": "Zürich",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/immoscout24-ch-residential-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 '{
  "searchQuery": "Zürich",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/immoscout24-ch-residential-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/immoscout24-ch-residential-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/xfjoYUbjgyJvPXKDo/builds/Df0VB28fKoEZfBCs1/openapi.json
