# Immobilienscout24 Scraper (`automation-lab/immoscout24-property-scraper`) Actor

Extract public ImmoScout24 sale and rental listings for property price and inventory analysis.

- **URL**: https://apify.com/automation-lab/immoscout24-property-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/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

## ImmobilienScout24 Scraper

Extract public ImmoScout24 sale and rental listings from Germany into structured datasets for property price research, inventory monitoring, and recurring market analysis.

Provide one or more `immobilienscout24.de/Suche/` URLs and the Actor returns stable listing IDs, prices, areas, rooms, locations, public advertiser details, images, timestamps, and source provenance. Apply filters on ImmoScout24 first; the Actor preserves the scope represented by each search URL.

### What does ImmobilienScout24 Scraper do?

ImmobilienScout24 Scraper reads the public listing model embedded in ImmoScout24 search-result pages.

It can:

- Extract rental and sale listing cards from German ImmoScout24 searches
- Follow result pagination up to a configurable page limit
- Stop at a global maximum number of unique listings
- Preserve rent/sale, property type, price, area, room, and location data
- Capture public advertiser name, company, and phone when present
- Keep listing publication, creation, and modification timestamps
- Return stable expose IDs and canonical listing URLs
- Record the source search URL, page number, search ID, and scrape timestamp
- Process multiple city or property searches in one run

The Actor does not log in, fill contact forms, or scrape private account pages.

### Who is this ImmoScout24 data for?

This Actor is useful for:

- Real-estate analysts tracking asking prices and available inventory
- Proptech teams building German market dashboards
- Investors comparing rental and sale opportunities
- Brokerages monitoring public competitor inventory
- Researchers studying neighborhood-level housing supply
- Data teams enriching internal property datasets
- Journalists working with repeatable public market snapshots
- Relocation teams comparing current listings across cities

### Why use this Actor?

Manual property research becomes difficult when the same searches must be repeated across cities and dates.

This Actor provides:

- Typed JSON rows instead of copied listing cards
- CSV, Excel, XML, and other Apify dataset exports
- Stable `listingId` values for downstream comparisons
- Pagination without manual next-page navigation
- Multiple search URLs in one run
- Configurable image retention to keep output focused
- Source and timestamp fields for auditability
- Direct HTTP extraction without a browser or automatic residential proxy fallback
- Non-zero failure behavior when no useful listings can be extracted

### How does the scraper work?

The Actor uses an HTTP-first extraction route.

1. It validates every URL as a public HTTPS ImmobilienScout24 search-result URL.
2. It requests the public search HTML using a bot identity allowed by the source robots policy.
3. It locates the inline `resultListModel` data structurally.
4. It parses property cards and the source-provided next-page URL.
5. It normalizes listing fields into stable dataset records.
6. It deduplicates records by ImmoScout24 expose ID.
7. It charges only for unique records saved to the default dataset.

Transient network, rate-limit, challenge, and server responses are retried with a bounded backoff. The Actor fails rather than reporting a false successful empty dataset when every route fails.

### Getting started

1. Open [ImmobilienScout24.de](https://www.immobilienscout24.de/).
2. Choose rent or buy, a location, and any property filters you need.
3. Copy the resulting URL containing `/Suche/`.
4. Paste it into **ImmoScout24 search URLs**.
5. Set **Maximum listings** and **Maximum pages per search**.
6. Click **Start**.
7. Open the default dataset to inspect or export results.

A useful first run is:

```json
{
  "startUrls": [
    {
      "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
    }
  ],
  "maxItems": 20,
  "maxPages": 1,
  "maxImages": 3,
  "maxRequestRetries": 3
}
```

### Input parameters

| Field | Type | Default | Description |
| --- | --- | ---: | --- |
| `startUrls` | array | Berlin apartment rentals | Public `immobilienscout24.de/Suche/` URLs. Search filters encoded in each URL remain in effect. |
| `maxItems` | integer | `50` | Maximum unique listings saved across all searches. Range: 1–10,000. |
| `maxPages` | integer | `5` | Maximum result pages followed per start URL. Range: 1–100. |
| `maxImages` | integer | `5` | Maximum public image URLs retained per listing. Range: 0–25. |
| `maxRequestRetries` | integer | `3` | Attempts per page for transient upstream failures. Range: 1–5. |

Only German ImmobilienScout24 search pages are supported. Detail/expose URLs, account pages, and other domains fail input validation.

### What data does the Actor extract?

Each dataset row represents one public property listing observed in a search.

| Field group | Included fields |
| --- | --- |
| Identity | `listingId`, `listingUrl`, `title` |
| Market type | `transactionType`, `propertyType` |
| Price | `price`, `currency`, `priceInterval`, `pricePerSqm` |
| Rent details | `baseRent`, `totalRent`, `serviceCharge`, `deposit` |
| Property attributes | `livingAreaSqm`, `plotAreaSqm`, `rooms`, `floor`, `totalFloors`, `yearBuilt` |
| Building data | `condition`, `heatingType`, `energyClass`, `energyConsumptionKwh` |
| Location | `address`, `street`, `houseNumber`, `city`, `district`, `postalCode`, `latitude`, `longitude` |
| Media and features | `features`, `imageUrls` |
| Advertiser | `advertiserName`, `advertiserCompany`, `advertiserPhone`, `privateOffer`, `companyCustomerId` |
| Source timestamps | `publishedAt`, `createdAt`, `updatedAt` |
| Provenance | `searchId`, `sourcePageNumber`, `sourceSearchUrl`, `sourceDomain`, `scrapedAt` |

Fields are optional because individual listings expose different data. For example, private offers may not include a company, and some properties do not publish an energy class or exact street address.

### Example output

This example reflects the current result shape with identifying details anonymized:

```json
{
  "listingId": "123456789",
  "listingUrl": "https://www.immobilienscout24.de/expose/123456789",
  "title": "Bright 2-room apartment with balcony",
  "transactionType": "RENT",
  "propertyType": "Apartment",
  "price": 1250,
  "currency": "EUR",
  "priceInterval": "MONTH",
  "pricePerSqm": 20.83,
  "livingAreaSqm": 60,
  "rooms": 2,
  "address": "Sample Street 12, Mitte, Berlin",
  "city": "Berlin",
  "district": "Mitte",
  "postalCode": "10115",
  "features": ["Balcony", "Elevator"],
  "advertiserCompany": "Sample Immobilien GmbH",
  "privateOffer": false,
  "publishedAt": "2025-01-15T12:00:00.000+01:00",
  "sourcePageNumber": 1,
  "sourceSearchUrl": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten",
  "sourceDomain": "www.immobilienscout24.de",
  "scrapedAt": "2025-01-16T10:00:00.000Z"
}
```

### How much does it cost to scrape ImmoScout24 property listings?

The Actor uses pay-per-event pricing:

- **Actor start:** $0.001 once per run
- **Property listing saved:** tiered per unique dataset row

| Plan tier | Price per saved listing |
| --- | ---: |
| FREE | $0.001104 |
| BRONZE | $0.00096 |
| SILVER | $0.0007488 |
| GOLD | $0.000576 |
| PLATINUM | $0.000384 |
| DIAMOND | $0.0002688 |

Example BRONZE charges:

- 1 saved listing: about **$0.00196** including the start event
- 20 saved listings: about **$0.0202** including the start event
- 100 saved listings: about **$0.097** including the start event

Failed, duplicate, or rejected records are not charged as listing events. Apify platform usage limits can still stop a run before the requested maximum is reached.

### Common property-market workflows

#### Track Berlin rental inventory

Schedule the same Berlin rental search daily. Compare `listingId`, `price`, `publishedAt`, and `updatedAt` with previous datasets to identify additions, removals, and changed asking prices.

#### Compare rent and sale markets

Provide separate rental and sale URLs. Group rows by `transactionType`, `city`, `district`, and `propertyType` in your downstream analysis.

#### Monitor multiple German cities

Submit several search URLs in one run, for example Berlin rentals, Munich house sales, and Hamburg apartment sales. Use `sourceSearchUrl` to preserve each record's source scope.

#### Build price-per-square-meter dashboards

Use `price`, `livingAreaSqm`, `pricePerSqm`, `rooms`, `district`, and `postalCode` in a BI tool. Treat asking prices as listing data, not completed transaction prices.

#### Research public advertiser inventory

Group public records by `advertiserCompany` or `companyCustomerId`. Some private or limited listings will not expose advertiser company data.

### Integrations and exports

Apify datasets can feed:

- Google Sheets for review and comparison
- Airtable for property research workflows
- BigQuery, Snowflake, or PostgreSQL for longitudinal analysis
- Power BI, Tableau, or Looker Studio dashboards
- Webhooks that trigger after scheduled runs
- Make, Zapier, or n8n workflows
- Internal property, brokerage, or research applications

You can download the dataset as JSON, CSV, Excel, XML, RSS, or HTML from Apify Console or the dataset API.

### API usage

Run `automation-lab/immoscout24-property-scraper` from any Apify API client.

#### JavaScript

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/immoscout24-property-scraper').call({
  startUrls: [
    { url: 'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten' },
  ],
  maxItems: 50,
  maxPages: 3,
  maxImages: 3,
});

console.log(`Dataset: ${run.defaultDatasetId}`);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/immoscout24-property-scraper').call(run_input={
    'startUrls': [
        {'url': 'https://www.immobilienscout24.de/Suche/de/bayern/muenchen/haus-kaufen'}
    ],
    'maxItems': 50,
    'maxPages': 3,
    'maxImages': 2,
})

print(run['defaultDatasetId'])
```

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~immoscout24-property-scraper/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [
      {"url": "https://www.immobilienscout24.de/Suche/de/hamburg/hamburg/wohnung-kaufen"}
    ],
    "maxItems": 40,
    "maxPages": 2,
    "maxImages": 0
  }'
```

Fetch results after completion:

```bash
curl \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  "https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json"
```

### MCP integration

Expose the Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/immoscout24-property-scraper"
```

#### Claude Desktop setup

Add this server to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/immoscout24-property-scraper"
    }
  }
}
```

#### Cursor setup

Add the same `mcpServers.apify` entry to Cursor's MCP settings and restart the MCP client.

#### VS Code setup

Add the same HTTP MCP URL to your VS Code MCP configuration, then enable the `apify` server for your chat session.

Example prompts:

- "Extract 30 current ImmobilienScout24 Berlin apartment rentals and summarize median asking rent per square meter."
- "Collect Munich houses for sale from this ImmoScout24 search URL and group them by room count."
- "Run my Berlin and Hamburg ImmoScout24 searches and return stable IDs, prices, timestamps, and source URLs for inventory comparison."

### Tips for reliable runs

- Start with 20 listings and one page while validating a new search URL.
- Apply all required filters on ImmobilienScout24 before copying the URL.
- Keep `maxImages` at 0–3 when your workflow is price or inventory analysis.
- Use several focused URLs rather than one extremely broad national search.
- Keep `maxPages` bounded for scheduled monitoring jobs.
- Deduplicate historical datasets with `listingId`.
- Use `sourceSearchUrl` to distinguish overlapping searches.
- Treat optional fields as nullable in downstream pipelines.

### Limitations

- Only public German `immobilienscout24.de/Suche/` result pages are supported.
- Austrian and Swiss ImmoScout24 sites are not included in this version.
- Detail/expose URLs are not accepted as start URLs.
- The Actor extracts fields present in public search-page data; it does not enrich every listing from its detail page.
- Descriptions, full image galleries, floor plans, and every detail-page field are not promised.
- Exact address and advertiser phone data may be absent or intentionally limited by the source.
- Search ranking and inventory can change between paginated requests.
- The Actor creates snapshots; change detection is performed by comparing datasets downstream.
- Source markup or access policy changes can require an Actor update.

### Responsible use and legality

This Actor extracts publicly available listing information. You are responsible for ensuring that your collection and use comply with applicable law, ImmoScout24 terms, database rights, privacy rules, and contractual obligations.

Use personal contact information only for a lawful purpose. Avoid unsolicited outreach, profiling, discrimination, or attempts to re-identify people. Collect only the fields and volume necessary for your workflow, protect exported datasets, and honor deletion or correction obligations that apply to you.

This Actor is not affiliated with or endorsed by Immobilien Scout GmbH.

### Troubleshooting and FAQ

#### Why did my URL fail validation?

The Actor accepts HTTPS URLs on `immobilienscout24.de` whose path starts with `/Suche/`. Open the filtered search results and copy that URL. An `/expose/` detail page or account URL is intentionally rejected.

#### Why are some fields missing?

Search listings expose different fields. A private offer may have no company, some listings hide the exact address, and many results omit energy or building details. Missing optional fields are not extraction errors.

#### Why did I receive fewer rows than `maxItems`?

`maxItems` is a ceiling, not a guarantee. The search may end, records may repeat across pages or URLs, a page may fail after retries, or Apify run limits may stop processing.

#### Does the Actor detect new or changed listings?

It produces stable, timestamped snapshots. Schedule recurring runs and compare `listingId`, `price`, `publishedAt`, and `updatedAt` in your database, spreadsheet, or automation workflow.

#### Does it require residential proxies?

No. The shipped route uses direct HTTP and does not expose an automatic proxy fallback. This keeps cost and behavior predictable.

#### Can it scrape ImmobilienScout24 Austria or ImmoScout24 Switzerland?

No. This version intentionally supports Germany only. Similar brand names do not guarantee the same page structure or data contract.

#### What happens when ImmoScout24 blocks a page?

The Actor retries transient challenge and server responses with bounded backoff. It logs failed pages and fails non-zero if no useful listing can be produced.

### Related automation-lab property Actors

For other public property markets, consider:

- [SeLoger Property Listings Scraper](https://apify.com/automation-lab/seloger-property-listings-scraper)
- [Trade Me Property Listing Monitor](https://apify.com/automation-lab/trade-me-property-listing-monitor)
- [StreetEasy NYC Listing Monitor](https://apify.com/automation-lab/streeteasy-nyc-listing-monitor)
- [Realtor.ca Property Listings Scraper](https://apify.com/automation-lab/realtor-ca-property-listings-scraper)
- [Zillow Scraper](https://apify.com/automation-lab/zillow-scraper)

### Changelog

See [`.actor/CHANGELOG.md`](.actor/CHANGELOG.md) for customer-visible release notes.

# Actor input Schema

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

One or more public ImmobilienScout24.de search-result URLs. Apply location, rent/sale, property type, price, room, and other filters on ImmoScout24, then paste the resulting /Suche/ URL here.

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

Maximum number of unique property listing records saved across all search URLs.

## `maxPages` (type: `integer`):

Maximum number of result pages followed for each start URL. Each page normally contains about 20 listing cards.

## `maxImages` (type: `integer`):

Maximum listing image URLs retained in each result. Use 0 when images are not needed.

## `maxRequestRetries` (type: `integer`):

Maximum attempts for a search page when ImmoScout24 returns a transient block or network error.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
    }
  ],
  "maxItems": 20,
  "maxPages": 5,
  "maxImages": 5,
  "maxRequestRetries": 3
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing all extracted property listing records.

# 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": [
        {
            "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
        }
    ],
    "maxItems": 20,
    "maxPages": 5,
    "maxImages": 5,
    "maxRequestRetries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/immoscout24-property-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": [{ "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten" }],
    "maxItems": 20,
    "maxPages": 5,
    "maxImages": 5,
    "maxRequestRetries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/immoscout24-property-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": [
    {
      "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten"
    }
  ],
  "maxItems": 20,
  "maxPages": 5,
  "maxImages": 5,
  "maxRequestRetries": 3
}' |
apify call automation-lab/immoscout24-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/immoscout24-property-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/J3q44F5OEx6kcZEGx/builds/VEU6pD9mXSevMhtcQ/openapi.json
