# ImmobilienScout24 Scraper - ImmoScout24 Germany Listings (`s-r/immobilienscout24-scraper`) Actor

Scrape German ImmoScout24 rental and sale listings with prices, addresses, areas, rooms, agents, photos and coordinates. For investors, proptech teams and agents. Optional expose details.

- **URL**: https://apify.com/s-r/immobilienscout24-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.19 / 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

## ImmobilienScout24 Scraper

ImmobilienScout24 Scraper exports German property listings for rent and sale from ImmoScout24 into a clean dataset for investors, proptech teams, researchers and estate agents. Export listing IDs, prices with their interval, addresses, living areas, rooms, broker names, photos and coordinates, with optional expose details.

The actor accepts search URLs copied from ImmobilienScout24 or a German city or district with filters. It walks result pages and returns one dataset row per unique listing. Grouped development units can be included as separate properties, each linked to its parent listing. This makes the output useful for housing supply analysis, property research, portfolio sourcing and regular comparisons of rental and purchase markets.

### What the ImmobilienScout24 scraper returns

- **Identity:** expose ID, expose URL, title, rent or sale, property type and collection time.
- **Price:** numeric price in EUR with `price_interval` (`MONTH` for cold rent, one-time for purchases), warm rent where shown, and the original price text.
- **Size:** living area and lot area in square metres, and the total room count.
- **Location:** street and house number when the portal releases them, postcode, city, quarter, latitude and longitude with a precision flag.
- **Advertiser:** broker name and ID, professional contact name and phone where shown, and a private-advertiser flag.
- **Media and features:** main photo, all photo URLs, floor plans, energy class, construction year, balcony, garden, kitchen, cellar, lift and portal tags.
- **Optional details:** description texts, bedrooms, bathrooms, floor, service charge, deposit, condition and pet policy.

### How to scrape ImmobilienScout24 with this actor

1. Open a search on ImmobilienScout24 in your browser, set the filters you need and copy the URL from the address bar. Alternatively, type a German city or district into **Location**.
2. Choose rent or buy and the property type when you search by location.
3. Set **Max items** to the number of listings you want.
4. Enable **Include details** if you need descriptions, bedrooms, bathrooms or costs.
5. Start the run and download the dataset as JSON, CSV, Excel or through the Apify API.

### ImmobilienScout24 Scraper input

Provide `startUrls`, `location`, or both. Search URLs must come from the German portal and use its `/Suche/de/` or `/Suche/radius/` search pages. URLs from other countries and individual expose pages are outside this actor's input scope. Filters already present in a URL are preserved. Page number and page size are managed automatically.

For a location search, enter a city or district such as Berlin. The first matching searchable place is used. The returned `query` keeps your location input; check `search_url` when a place name could refer to several locations. For URL searches, both fields contain the normalized search URL. A postcode alone may not identify a searchable place; in that case, use the city or copy a radius search URL from the portal.

`dealType` is `rent` or `buy`, defaulting to rent. `propertyType` is `apartment`, `house` or `plot`, defaulting to apartment. Plots support purchase searches. These options apply to a location search; an explicit search URL retains the property and transaction types encoded in its path.

Optional `minPrice`, `maxPrice`, `minRooms`, `maxRooms`, `minLivingSpace` and `maxLivingSpace` apply to location searches. Price means monthly cold rent for rentals and purchase price for sales. Living space is measured in square metres. Room filters refer to total rooms, as defined by the portal, rather than bedrooms. Each minimum must be no greater than its corresponding maximum. `sorting: 2` requests newest listings first; omitting sorting uses the portal's normal order.

`maxItems` limits the total unique listings across all supplied searches. It defaults to 100 and accepts values from 1 to 5,000. `includeGroupedUnits` defaults to true. `includeDeactivated` defaults to false, excluding properties that the portal labels deactivated. `includeDetails` defaults to false and adds descriptions, bedroom and bathroom counts, floor information and further costs where available. `cursor` is for direct API users who continue a previous search page by page.

| Field | Type | Default | Meaning |
|---|---|---|---|
| `startUrls` | list of URLs | – | German ImmobilienScout24 search URLs |
| `location` | text | – | German city or district, used with the options below |
| `dealType` | `rent` / `buy` | `rent` | Transaction type for a location search |
| `propertyType` | `apartment` / `house` / `plot` | `apartment` | Property type for a location search |
| `minPrice`, `maxPrice` | integer | – | Cold monthly rent or purchase price in EUR |
| `minRooms`, `maxRooms` | integer | – | Total rooms |
| `minLivingSpace`, `maxLivingSpace` | integer | – | Living area in m² |
| `sorting` | integer | portal order | `2` = newest first |
| `maxItems` | integer | 100 | Unique listings across all searches (1–5,000) |
| `includeGroupedUnits` | boolean | true | Return units of a development as their own rows |
| `includeDeactivated` | boolean | false | Keep listings labelled deactivated |
| `includeDetails` | boolean | false | Fetch the expose for extra fields |
| `cursor` | text | – | Continue from `next_cursor` of a previous response |

Example input for rental apartments in Berlin:

```json
{
  "startUrls": ["https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"],
  "maxItems": 3,
  "includeGroupedUnits": false
}
```

### ImmobilienScout24 Scraper output

Each dataset row contains the listing's `listing_id`, `url`, `title`, `listing_type`, `property_type`, `source`, `platform` and UTC `fetched_at`. `listing_type` distinguishes `for_rent` from `for_sale`. IDs are strings so they remain stable identifiers when exported to spreadsheets or databases. `position` records the row's place in the collected results.

Prices are numeric values in `currency`. Rental `price` is cold monthly rent, with `price_interval: MONTH`. Purchase prices use a one-time interval. `total_rent` is warm rent when the portal supplies it. A price shown as a range or as “Auf Anfrage” produces a null numeric price and preserves the original text in `price_display`. Treating those offers as zero-priced properties would distort comparisons.

`living_area` and `lot_area` are square metres, identified by their unit fields. `rooms` is the total room count and can include half rooms. `bedrooms` and `bathrooms` are populated only from optional detail data. They are not estimated from rooms or floor area.

Address fields are limited to what the portal releases. `street` combines street and house number; it is null when the exact address is withheld. Map coordinates carry `coordinate_precision: exact` or `approximate`, so approximate locations can be excluded from precise distance calculations. Photos are returned in `image_urls`, with floor plans in a separate `floorplan_urls` list.

Professional broker contact details may be included. Private advertisers are marked by `is_private`; their contact name and telephone number are withheld. Grouped units contain `grouped_under`, and development names and links appear when supplied. `total_results` is the portal's listing count for that search page. It is not a guarantee of the number exported: grouped units, deactivated offers, overlaps between searches and the requested item limit affect the actual delivered count.

#### Example row

The first row of a real run with the Berlin input above (collected 5 October 2026; the photo list is shortened to two of nine URLs and empty detail fields are left out):

```json
{
  "source": "immobilienscout24-scraper",
  "platform": "immobilienscout24",
  "fetched_at": "2026-10-05T16:05:26Z",
  "listing_id": "168986451",
  "url": "https://www.immobilienscout24.de/expose/168986451",
  "title": "Wohnen mit Herz – wie geschaffen für zwei mit WBS 220",
  "listing_type": "for_rent",
  "property_type": "ApartmentRent",
  "price": 592.94,
  "price_display": "592,94 €",
  "currency": "EUR",
  "price_interval": "MONTH",
  "total_rent": 798.47,
  "living_area": 51.56,
  "living_area_unit": "m2",
  "rooms": 2,
  "address": "Hellersdorfer Straße 91B, Hellersdorf, Berlin",
  "street": "Hellersdorfer Straße 91B",
  "house_number": "91B",
  "postal_code": "12619",
  "city": "Berlin",
  "quarter": "Kaulsdorf (Hellersdorf)",
  "country_code": "DE",
  "lat": 52.52485,
  "lng": 13.58695,
  "coordinate_precision": "exact",
  "broker": "GESOBAU AG",
  "broker_id": "001.559854",
  "is_private": false,
  "contact_name": "Gesobau Vermietungsteam Neubau",
  "image_url": "https://pictures.immobilienscout24.de/listings/3231b800-98bb-4861-8000-5ba140fdae9a-2105579394.jpg",
  "image_urls": [
    "https://pictures.immobilienscout24.de/listings/3231b800-98bb-4861-8000-5ba140fdae9a-2105579394.jpg",
    "https://pictures.immobilienscout24.de/listings/9e36591f-23dd-440d-a261-dbc3568621c3-2105579397.jpg"
  ],
  "floorplan_urls": [
    "https://pictures.immobilienscout24.de/listings/a042f7d8-7d77-4189-a7ec-69428a314cbb-2105579427.jpg"
  ],
  "energy_class": "B",
  "construction_year": 2026,
  "balcony": true,
  "garden": false,
  "built_in_kitchen": false,
  "listing_tier": "XXL",
  "tags": ["Balkon/Terrasse", "Aufzug"],
  "project_id": "147913",
  "project_name": "Cecilien-Carré",
  "project_url": "https://www.immobilienscout24.de/neubau/gesobau-ag/cecilien-carr/147913.html",
  "is_deactivated": false,
  "published_at": "2026-07-01T13:57:08.000+02:00",
  "modified_at": "2026-10-02T18:33:48.164+02:00",
  "query": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten",
  "search_url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten",
  "position": 1,
  "page": 1,
  "total_results": 11939,
  "detail_fetched": false
}
```

With `includeDetails` enabled, the same listing gained these fields in a real run on the same day: `bedrooms: 1`, `bathrooms: 1`, `floor: 1`, `number_of_floors: 6`, `service_charge: 128.91`, `deposit: 1778.82`, `deposit_display: "1.778,82 €"`, `heating_costs_included: false`, `detail_fetched: true` and the full German description text.

### Detail collection and completion

When details are requested, `detail_fetched` reports whether the matching expose was successfully collected. A failed detail request keeps the search row and produces a warning. Fields absent from the source remain null. A deposit expressed as months of rent is retained in `deposit_display`; a numeric `deposit` is returned only when the source states an amount.

The actor follows continuation pages automatically. Direct API users can continue with `next_cursor` while keeping the original search options. The run output record reports completion and warnings. Inspect `partial` before treating the dataset as a complete search, especially when a requested enrichment phase could not finish. Results are a snapshot of a changing marketplace; pagination does not freeze the source's ranking or availability.

A search URL that no longer exists is skipped with a numbered warning, and the actor continues with the next URL. Listings already collected are retained. Skipped searches remain visible in `partial` and warnings, including when the requested row limit is reached. If every search is empty or unavailable, the run returns no listings.

### Use cases

- **Rental and purchase price analysis:** compare cold rent or purchase price per square metre by city, quarter or postcode, using `price`, `living_area` and `postal_code`.
- **Investment sourcing:** run a filtered search on a schedule, keep the newest listings with `sorting: 2` and pass new expose IDs to your deal pipeline.
- **Supply monitoring:** track how many listings a search returns over time with `total_results`, and follow new-build developments through `project_id` and `grouped_under`.
- **Agent and developer research:** see which brokers and developers are active in an area through `broker`, `broker_id` and `project_name`.
- **Maps and location models:** plot listings with `lat` and `lng`, filtering out rows whose `coordinate_precision` is approximate.

### ImmobilienScout24 API or scraper?

ImmobilienScout24 offers an official API for registered partners, mainly agents and software vendors who publish and manage their own listings. It is not a public feed of the whole market. This actor works from the public search results that any visitor sees, needs no ImmobilienScout24 account and returns analysis-ready rows instead of raw portal objects.

Compared with writing your own scraper, you do not maintain parsers for search pages, page counts, grouped developments, price ranges or expose pages; field names and units stay the same between runs. Other ImmobilienScout24 actors in the Apify Store cover more countries or add their own analytics. This actor focuses on the German portal and on explicit data: price intervals are stated, unknown prices stay null instead of zero, coordinate precision is flagged, and you pay only for rows that are delivered.

### Pricing

The listing event counts each delivered unique property once. The listing detail event counts only delivered rows whose `detail_fetched` value is true. Failed enrichments do not incur the detail event, and an empty result has no listing or detail charges. Check the actor's current pricing panel for event rates and platform execution costs. Non-paying users receive up to ten rows per run, with detail collection available within that limit. `maxItems` caps what a single run can cost.

### FAQ

#### Does this actor support Austria or Switzerland?

It supports the German ImmobilienScout24 portal. Austrian and Swiss URLs are rejected. Use a German search URL or a location that the German portal recognises.

#### Why is the price sometimes null?

The portal can display a price range or ask prospective buyers to request the price. The actor preserves that text in `price_display` and leaves `price` null instead of choosing an amount that was never advertised.

#### Why are there fewer rows than total_results?

The item limit, repeated listings across searches, deactivated offers and changes during collection can reduce delivered rows. Grouped development units can also increase the number of collected properties relative to the portal's main listing count.

#### Can I collect bedrooms and property descriptions?

Enable `includeDetails`. The actor returns these fields when the matching expose supplies them. Check `detail_fetched` and run warnings to distinguish unavailable source fields from an unsuccessful enrichment.

#### Do I need an ImmobilienScout24 account or API key?

No. The actor reads public search results and expose pages. You only need an Apify account to run it.

#### Can I scrape a single expose URL?

Not as input. Search for the area that contains the listing, or run a search and enable `includeDetails` to enrich every returned listing with its expose data.

#### Are private landlords' phone numbers included?

No. Rows from private advertisers are marked with `is_private: true`, and their contact name and phone number are withheld. Contact details appear only for professional advertisers where the portal shows them.

# Actor input Schema

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

German ImmoScout24 search URLs, as strings or URL objects. Existing filters are preserved; page size and page number are managed automatically.

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

German city or district, resolved to the first searchable location. May be combined with startUrls.

## `dealType` (type: `string`):

Transaction type for the location search. Explicit search URLs keep their own transaction type.

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

Property type for the location search. Plots require dealType buy.

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

Maximum unique listings across all searches, including grouped units.

## `sorting` (type: `string`):

Sort code for location searches. 2 requests the newest listings first; omit for the portal default.

## `includeGroupedUnits` (type: `boolean`):

Include individual units grouped under development listings. Each unit has grouped_under.

## `includeDeactivated` (type: `boolean`):

Include listings marked deactivated by the portal.

## `includeDetails` (type: `boolean`):

Fetch expose descriptions, bedrooms, bathrooms, floor and additional costs for each delivered listing.

## `cursor` (type: `string`):

Opaque next_cursor from the previous response. Keep the original search options and repeat maxItems, or send the remaining volume.

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

Minimum cold monthly rent or purchase price in EUR for location searches.

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

Maximum cold monthly rent or purchase price in EUR for location searches.

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

Minimum total rooms, not bedrooms for location searches.

## `maxRooms` (type: `integer`):

Maximum total rooms, not bedrooms for location searches.

## `minLivingSpace` (type: `integer`):

Minimum living area in square metres for location searches.

## `maxLivingSpace` (type: `integer`):

Maximum living area in square metres for location searches.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
  ],
  "dealType": "rent",
  "propertyType": "apartment",
  "maxItems": 10,
  "includeGroupedUnits": true,
  "includeDeactivated": false,
  "includeDetails": false
}
```

# Actor output Schema

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

One row per unique listing.

## `output` (type: `string`):

Counts, completion status and warnings.

# 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 = {
    "startUrls": [
        "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/immobilienscout24-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 = {
    "startUrls": ["https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/immobilienscout24-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 '{
  "startUrls": [
    "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
  ],
  "maxItems": 10
}' |
apify call s-r/immobilienscout24-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/immobilienscout24-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/6WUjGQDK3LjzTpmSV/builds/DvS6WsdF8Xakoxy9y/openapi.json
