# ImmobilienScout24 Scraper - Germany Real Estate Listings (`nice_dev/immobilienscout24-listings-scraper`) Actor

Scrape ImmobilienScout24.de listings for the whole of Germany, rent or sale, 16 property types: price, costs, area, rooms, address, GPS, energy data, photos and the agent's phone and e-mail. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/nice\_dev/immobilienscout24-listings-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.54 / 1,000 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

### 🏠 What is ImmobilienScout24 Scraper?

**ImmobilienScout24 Scraper** extracts **property listings from [ImmobilienScout24.de](https://www.immobilienscout24.de)**, Germany's largest real estate portal: **price, rent, area, rooms and full address with GPS, plus (tick **Extract details**, off by default) all costs, the energy certificate, all photos, and the agent's phone number and e-mail** — apartments and houses for rent or sale, plots, garages, offices, retail, investment properties and foreclosures, anywhere in Germany. It works as an **ImmobilienScout24 API alternative**: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.

Choose a **property type** and a **city**, or paste any ImmobilienScout24 search URL, click **Start**, and download the listings in JSON, CSV or Excel. No login, nothing to set up, and a whole city or the whole of Germany in one run — there is no page limit.

### 📋 What data can you extract from ImmobilienScout24?

One item per listing, 120 fields:

| Category | What you get |
| --- | --- |
| 🏷️ **Listing** | title, link, Scout-ID, property type, rent or sale, private or agency, new-build project — `Helle 3-Zimmer-Wohnung mit Balkon` |
| 💶 **Price and costs** | price, cold rent, total rent, service charge, heating costs, deposit, purchase price, price per m², commission, purchase costs (notary, land transfer tax), price reduction — `1,451.52 € / month` |
| 📐 **Size** | living space, plot, floor space, rooms, bedrooms, bathrooms, floor — `66 m², 1 room, 5th floor` |
| 🏗️ **Building and energy** | year built, condition, heating, energy class, energy certificate and consumption — `2026, A, district heating` |
| 🛋️ **Features** | balcony, garden, lift, cellar, fitted kitchen, guest toilet, step-free access, pets, parking — `balcony: true` |
| 📍 **Location** | address, street and number, postal code, city, district, federal state, latitude / longitude — `12559 Berlin, Köpenick` |
| 📝 **Descriptions** | description, location, equipment, other notes — the owner's full texts |
| 📷 **Photos and documents** | every photo in large size, floor plans and energy certificates as PDF |
| 📞 **Contact** | agent name, company, **phone numbers**, **e-mail**, legal notice, rating, profile — `+49 30 23632550` |
| 🕒 **Dates** | publication date (as precise as the site's "x hours / days ago", exact to the second for the listings in the site's early access), days on the market |
| 🔎 **Search** | which search found it and its rank |

Every field, with an example, is listed in the **Output** section below.

Contact, costs, energy data, descriptions and all photos come from the listing page: they are filled when you tick **Extract details** (off by default). Left off, you get a quicker search-card scrape (price, area, rooms, address, coordinates, first photos, date).

### ✅ Why use ImmobilienScout24 Scraper?

- 🇩🇪 **The whole of Germany, no page limit**: a search returns every listing the site has — about 83,000 apartments for rent, 230,000 houses for sale.
- 📞 **Phone and e-mail**: a phone number on about 9 house sales in 10, 3 offices in 4 and 2 to 4 apartment rentals in 10 (runs of September 2026), charged only for the listings that show one (tick **Extract details** and **Extract phone numbers** to get them); the agency's e-mail comes from its legal notice, included in the details.
- 🏢 **16 property types**: apartments, houses, plots, garages, flat-share rooms, furnished temporary living, offices, retail, gastronomy, halls, special properties, investment properties, foreclosures, prefab houses, commercial plots, assisted living.
- 🎯 **30+ search filters of the site**: price, total rent, rooms, living space, plot, floor space, year built, floor, energy class, equipment, apartment and house types, new builds, commission-free, pets, internet speed, keyword — checked at the start of the run against the property type you chose, and listed in the form for each filter.
- 🗂️ **Several searches in one run**: property types × cities × keywords, a radius around a point, or your own search URLs, with a cap per search.
- 🔔 **Monitoring built in**: tick **Only new listings**, schedule the Actor, and each run returns (and charges) only the listings it has never delivered before.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape ImmobilienScout24

1. Create a free Apify account.
2. Open **ImmobilienScout24 Scraper**, choose a **Property type** (apartment, house, office…), **Rent** or **Buy**, and type a **Location** (`Berlin`, `München`, `Prenzlauer Berg`, `Bayern`).
3. Or paste your own ImmobilienScout24 URLs into **Start URLs**: any search results page (every filter set on the site is kept) or single listing pages.
4. Set **Max listings** (100 by default, 0 = no limit) — and **Max listings per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape ImmobilienScout24?

This Actor uses **pay per event** pricing, cheaper on higher Apify plans (Free → Bronze → Silver → Gold and above): **$0.90 → $0.78 → $0.66 → $0.54 per 1,000 listings**, plus **$0.39 → $0.36 per 1,000 listings read with their details** (only when you tick **Extract details**, so $1.29 per 1,000 listings with contact, costs and photos on the Free plan, $0.90 on Gold; $0.90 without), plus **$4.49 → $4.46 per 1,000 listings delivered with a phone number** (`contact-phone`, only when you tick **Extract phone numbers**, which needs **Extract details**: a listing that shows no phone costs nothing more), plus **$0.01 per run start** (at the default memory; a run given more than 1 GB counts one start per GB). Examples on the Free plan: 10,000 apartments for rent with **Extract details** ticked ≈ $12.90, plus $4.49 for each 1,000 of them that show a phone with **Extract phone numbers** ticked too (about 3 in 10: ≈ $13.47); the same without phones ≈ $12.90. Platform usage (compute, proxy) is included in the price. With **`requirePhone`** or **`requireEmail`**, a listing page read and then dropped because it shows no phone / no e-mail costs **$0.19 → $0.16 per 1,000** (`filtered-listing`): 1,000 apartments for rent with a phone on the Free plan (both options ticked) ≈ $1.29 + $4.49 for the phones + 1.9 pages dropped per listing kept × $0.19 / 1,000 ≈ **$6.15**. The filters the Actor applies itself on the search card (`postedAfter` / `postedBefore`, `excludeKeywords`, `privateSellersOnly`, `earlyAccessOnly`, `postalCodes`, and `excludeNewBuildProjects` outside apartments and houses for sale, where the site applies it itself) are checked on every listing they read, kept or not: each listing checked is charged a filter check (`filter-check`, $0.09 → $0.06 per 1,000). With `requireEmail` alone, a private landlord dropped on the search card is not charged.

### ⚙️ Input

```json
{
    "propertyType": "apartment",
    "offerType": "rent",
    "location": "Berlin",
    "maxPrice": 1500,
    "minRooms": 2,
    "maxItems": 200
}
```

Several property types and cities, a cap per search, only recent listings, only the ones not delivered before:

```json
{
    "propertyType": "apartment",
    "propertyTypes": ["house"],
    "offerType": "buy",
    "locations": ["Hamburg", "Köln"],
    "equipment": ["cellar"],
    "maxItemsPerQuery": 50,
    "postedAfter": "7 days",
    "onlyNew": true,
    "stateKey": "hamburg-koeln-sale"
}
```

Or with your own URLs, and listings by Scout-ID:

```json
{
    "startUrls": [
        { "url": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?price=-1500.0&numberofrooms=2.0-" },
        { "url": "https://www.immobilienscout24.de/expose/171143307" }
    ],
    "listingIds": ["171123122"],
    "maxItems": 500
}
```

| Field | Notes |
| --- | --- |
| `propertyType`, `propertyTypes` | `apartment`, `house`, `plot`, `garage`, `flatshare`, `temporaryLiving`, `office`, `retail`, `gastronomy`, `industry`, `specialPurpose`, `investment`, `foreclosure`, `prefabHouse`, `commercialPlot`, `assistedLiving`; `propertyTypes` adds more types (one search each). |
| `offerType` | `rent`, `buy` or `any` (both). Ignored by the types that exist one way only. |
| `location`, `locations` | German city, district, town quarter or federal state as typed in the site's search box, or a region path (`/de/berlin/berlin`); empty = the whole of Germany. Every type and keyword is searched in every location (max 500 searches per run). |
| `latitude`, `longitude`, `radiusKm` | A radius search around a point (km), instead of a location. |
| `query`, `searchQueries` | Keyword searched in the listings (`Kamin`, `Altbau`); `searchQueries` adds more keywords. |
| `startUrls` | ImmobilienScout24 search results pages (region, radius or map-area searches — filters kept, pagination automatic) or listing pages. When set, the search fields above are ignored. |
| `listingIds` | Scout-IDs or listing URLs, always read on their own page. |
| `maxItems` | Stop after this many listings for the whole run (`0` = unlimited). |
| `maxItemsPerQuery` | Cap for EACH search (type × location × keyword, or search URL). 0 = no per-search cap. |
| `extractDetails` | Read each listing page: contact with e-mail, all costs, energy data, texts and all photos (default off). |
| `extractPhone` | Add the contact's phone numbers (`phone`, `phones`), read on the listing page (needs `extractDetails`: ticked alone, no phone comes out and the run log says so; default off). Charged only for a listing that shows one. Off: no phone in the output, and the numbers of the agent's legal notice (`imprint`) read `[phone hidden]`. Always on with `requirePhone`. |
| `sortBy` | `newest` (default), `oldest`, `priceAsc`, `priceDesc`, `areaAsc`, `areaDesc`, `standard` (the site's own order). Not every type has every order (no area order for plots or garages for sale, no price order for foreclosures): such a search stops at once, naming the sort. |
| `minPrice`, `maxPrice`, `minRooms`, `maxRooms`, `minLivingSpace`, `maxLivingSpace`, `minPlotArea`, `maxPlotArea`, `minFloorArea`, `maxFloorArea`, `minYearBuilt`, `maxYearBuilt`, `minFloor`, `maxFloor` | Ranges sent to the site. A filter the site does not offer for the chosen property type stops the run at its start, before any page is read, and the message lists the types it works for (the form lists them for each filter). |
| `priceType` | `coldRent` or `totalRent`: the rent the price range reads, for apartments to rent. |
| `equipment` | The site's equipment: `balcony`, `garden`, `builtinkitchen`, `lift`, `cellar`, `guesttoilet`, `parking`, `handicappedaccessible` (all must be present). |
| `energyEfficiencyClasses` | `a_plus`, `a`, `b` … `h`. |
| `apartmentTypes` | `apartment`, `loft`, `maisonette`, `penthouse`, `terracedflat`, `groundfloor`, `raisedgroundfloor`, `roofstorey`, `halfbasement`, `other`. |
| `buildingTypes` | House types: `singlefamilyhouse`, `semidetachedhouse`, `midterracehouse`, `endterracehouse`, `multifamilyhouse`, `bungalow`, `villa`, `farmhouse`, `castlemanorhouse`, `specialrealestate`. |
| `newBuildingOnly`, `excludeNewBuildProjects`, `noCommissionOnly`, `petsAllowed`, `excludeRented`, `minInternetSpeed` | New builds only, no developer projects, commission-free only, pets allowed, not currently let, lowest internet speed (Mbit/s). |
| `postedAfter`, `postedBefore` | Publication date range: `2026-09-01`, or a period before now (`7 days`, `2 weeks`, `1 month`, `24 hours`). |
| `postalCodes`, `excludeKeywords`, `privateSellersOnly`, `earlyAccessOnly`, `requirePhone`, `requireEmail` | Keep these postal codes (5 digits or a prefix such as `101`), drop titles with these words, private landlords only, the site's newest early-access listings only, only with a phone number / an e-mail. |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the listings never delivered under this memory key; `resetState` forgets the memory. |
| `includeRaw` | Add the site's own data of each listing, as received — for JSON or the API only: with `extractDetails` it adds hundreds of columns per listing, and a CSV or Excel export keeps only the first 2,000 columns (other columns would be missing from 3 listings on). |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

One real item of a run (shortened: some columns and the long texts are cut here):

```json
{
    "id": "171123122",
    "url": "https://www.immobilienscout24.de/expose/171123122",
    "title": "SCHLOSSBERG TWO - Premium-WG-Zimmer im Neubau",
    "propertyType": "apartmentrent",
    "offerType": "rent",
    "isPrivate": false,
    "isPlusExclusive": false,
    "publishedAt": "2026-09-23T13:36:19.977Z",
    "publishedAtPrecision": "hour",
    "publishedAgo": "vor 11 Stunden",
    "price": 1451.52,
    "priceText": "1.452 €",
    "priceInterval": "month",
    "currency": "EUR",
    "pricePerSqm": 21.99,
    "baseRent": 1451.52,
    "totalRent": 1681.52,
    "serviceCharge": 113.2,
    "heatingCosts": 116.8,
    "livingSpace": 66,
    "rooms": 1,
    "floor": 5,
    "yearBuilt": 2026,
    "energyEfficiencyClass": "A",
    "balcony": true,
    "features": ["Balkon/Terrasse", "Keller", "Personenaufzug", "Einbauküche", "Stufenloser Zugang", "WG-geeignet"],
    "address": "Am Schloßberg 1A, 12559 Berlin, Köpenick",
    "street": "Am Schloßberg",
    "houseNumber": "1A",
    "postalCode": "12559",
    "city": "Berlin",
    "district": "Köpenick",
    "latitude": 52.44326,
    "longitude": 13.58496,
    "hasFullAddress": true,
    "description": "Schlossberg Two – zwei Bewohner. Ein außergewöhnliches Zuhause. …",
    "images": ["https://pictures.immobilienscout24.de/listings/a2d442f1-e720-4598-af1b-501fd5bd5f5c-2098436291.jpg/ORIG/resize/1500x1000/format/webp/quality/80"],
    "documents": [],
    "tags": [],
    "contactName": "TEAM - Vermietung | Verkauf",
    "companyName": "IMMS Immobilien Management & Services GmbH",
    "phone": "+49 30 23632550",
    "phones": [{ "type": "landline", "number": "+49 30 23632550" }],
    "email": "info@imms-immobilien.de",
    "searchRank": 44,
    "detailsExtracted": true,
    "scrapedAt": "2026-09-24T00:36:19.977Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### All 120 fields

| Fields | What you get |
| --- | --- |
| `id`, `url`, `title`, `propertyType`, `offerType` | **Listing**: `171123122`, the listing page, the title, `apartmentrent`, `rent` / `buy` |
| `isPrivate`, `builderName`, `isProject`, `isNewBuilding`, `isNewListing`, `listingTier`, `tags` | private landlord or agency, the house builder of a builder's offer, new-build project, new build, the site's "new" badge, paid tier S–XL, badges |
| `isPlusExclusive`, `earlyAccessEndsAt`, `publishedAt`, `publishedAtPrecision`, `publishedAgo`, `daysOnMarket` | **Dates**: in the site's early access for its members, its end, publication date and its precision, as shown (`vor 2 Stunden`), days online |
| `price`, `priceText`, `priceInterval`, `currency`, `pricePerSqm`, `previousPrice`, `priceReductionPercent` | **Price**: `1451.52`, `1.452 €`, `month`, `EUR`, per m², the price before a reduction and the % |
| `baseRent`, `totalRent`, `serviceCharge`, `heatingCosts`, `heatingCostsIncluded`, `deposit` | cold rent, total rent, service charge, heating, whether heating is in the service charge, deposit as written |
| `purchasePrice`, `maintenanceFee`, `rentalIncomePerYear`, `commission`, `hasCommission`, `purchaseCosts` | purchase price, Hausgeld, rental income, commission as written and whether one is due, purchase costs (notary, land transfer tax, land registry, total) |
| `fairPriceRating`, `priceRange` | the site's price rating and the price range of the area per m² |
| `marketValue`, `minimumBid`, `auctionDate` | foreclosures: market value, minimum bid, auction date |
| `livingSpace`, `usableArea`, `floorSpace`, `plotArea`, `rooms`, `bedrooms`, `bathrooms`, `floor`, `numberOfFloors` | **Size**, in m² and counts |
| `yearBuilt`, `lastRefurbishment`, `condition`, `interiorQuality`, `apartmentType`, `heatingType`, `energySources` | **Building**: `2026`, last modernisation, `Erstbezug`, `Gehoben`, `Etagenwohnung`, `Fernwärme`, `Gas` |
| `energyCertificate`, `energyCertificateType`, `energyConsumption`, `energyEfficiencyClass` | **Energy**: certificate available, its type, kWh/m²·a, `A+` … `H` |
| `balcony`, `garden`, `lift`, `cellar`, `builtInKitchen`, `guestToilet`, `barrierFree`, `petsAllowed`, `parkingSpaces`, `parkingType`, `isRented`, `availableFrom`, `internetSpeed`, `features` | **Features**: true / false / unknown, pets `yes` / `no` / `negotiable`, parking, currently let, available from, internet speed, every ticked feature |
| `address`, `street`, `houseNumber`, `postalCode`, `city`, `district`, `region`, `latitude`, `longitude`, `hasFullAddress` | **Location**: street and number only when the owner shows them (`hasFullAddress`), coordinates when the site gives them |
| `description`, `locationDescription`, `equipmentDescription`, `otherDescription` | **Descriptions**: the owner's texts, line breaks kept |
| `imageUrl`, `images`, `imageCount`, `hasVideoTour`, `documents`, `floorplanUrl`, `virtualTourUrl`, `videoUrl` | **Photos and documents**: large photos, PDF documents (`{name, url}`), the floor plan, the 360° tour and the video when there is one |
| `contactName`, `companyName`, `phone`, `phones`, `email`, `imprint` | **Contact**: `TEAM - Vermietung`, the agency, `+49 30 23632550`, every number with its type, the agency e-mail, its legal notice |
| `agentProfileUrl`, `agentLogoUrl`, `agencyId`, `agentRating`, `agentReviewCount`, `isVerifiedAgent`, `externalId` | the agency's page, logo, id, rating out of 5 and number of reviews, verified badge, the agent's own reference number |
| `attributes`, `rawAttributes` | every label → value of the listing page (German, as shown) and the site's raw values |
| `searchUrl`, `searchQuery`, `searchLocation`, `searchRank` | **Search**: the search that found it, its keyword, region, and the rank of the listing |
| `detailsExtracted`, `raw`, `scrapedAt` | whether the listing page was read, the site's data as received (`includeRaw`), ISO timestamp |

### 💡 Tips

#### How to get more results

Leave **Location** empty for the whole of Germany and set `maxItems` to `0`: there is no page limit, a search returns every listing the site has. Split a very large market by city, price range or property type to run searches side by side.

#### How to reduce costs

The price is per listing, so the levers are `maxItems`, `maxItemsPerQuery`, the site filters (a listing the site filters out is never downloaded), the post-filters (each listing a card filter checks is charged `filter-check`, kept or not; one that `requirePhone` / `requireEmail` drops after its page was read costs $0.19 → $0.16 / 1,000) and `onlyNew` for recurring runs (you never pay twice for the same listing). Leaving `extractDetails` off (default) saves the details price when the search card is enough; leaving `extractPhone` off (default) saves the phone price when you only need the listings.

#### Several searches in one run

Fill `propertyTypes`, `locations` and / or `searchQueries`: the Actor runs one search per property type × location × keyword, up to 500 per run; `offerType: "any"` searches both rent and sale. A listing found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget. You can also paste several search URLs into `startUrls`: each one is a search of its own, with the same cap.

#### Monitoring: only the new listings

Tick **Only new listings** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the listings already delivered: they are not saved, not charged, and their page is not even opened. The memory lives in a named key-value store of your account (`immobilienscout24-listings-scraper-seen`, up to 150,000 listings per key) and is only updated with listings that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's listings), and tick `resetState` once to start over. With the default sort (newest first), a search stops once it meets a run of listings you already have — as many in a row as your cap per search or per run, 100 at most.

#### Filter by publication date

`postedAfter` and `postedBefore` take a date (`2026-09-01`, the whole day is included, German time) or a period before now (`7 days`, `2 weeks`, `1 month`; via the API also `24 hours` or a full ISO date-time). The filter reads `publishedAt`, which is as precise as the site's "x hours / days / months ago" (`publishedAtPrecision`), exact to the second for the listings in the site's early access (about 1 in 15 of the listings under 3 days old). The site rounds that text to the nearest unit ("3 days ago" = 2.5 to 3.5 days ago, "a month ago" = 26 to 45 days ago): a listing that may be inside the range is kept, so listings up to one unit outside it can come back (a day for "3 days ago", a month for "2 months ago": check `publishedAgo`) — none inside is dropped. A listing without a publication date is dropped as soon as a date bound is set. A filtered-out listing is not saved and does not count in `maxItems`; each listing the date filter checks is charged `filter-check`, kept or not. With the default sort, a search stops at the first page that is entirely too old.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per ImmobilienScout24 listing. Actor id: `nice_dev/immobilienscout24-listings-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/immobilienscout24-listings-scraper`.

Smallest input, for a cheap first call:

```json
{
    "propertyType": "apartment",
    "offerType": "rent",
    "location": "Berlin",
    "maxItems": 10
}
```

Key output fields: `url`, `title`, `price`, `livingSpace`, `rooms`, `address`, `phone`, `publishedAt`.

Cost on the Free plan (lower on paid plans): $0.90 per 1,000 listings (search-card fields), $1.29 per 1,000 listings with their details (`extractDetails: true`), plus $4.49 per 1,000 listings delivered with a phone number (`extractPhone: true`, with `extractDetails`), plus $0.01 per run start at the default memory; `requirePhone`, `requireEmail` and the filters cost extra, see the pricing section above. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape ImmobilienScout24?

The Actor only reads what ImmobilienScout24 shows publicly to any anonymous visitor. It logs in to nothing and solves no captcha. Results can contain personal data (the names, phone numbers and e-mails of agents, the names of private landlords), which is protected by GDPR: do not store it without a legitimate reason. You are responsible for using the data in compliance with ImmobilienScout24's Terms of Use and applicable law. This Actor is not affiliated with ImmobilienScout24 or Scout24 SE.

#### Does it need a login or a proxy?

No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request the site turns away is retried at once on a new proxy session (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).

#### Is the data safe to open in Excel or to show on a web page?

Titles and descriptions are the owners' own words, copied as they are, line breaks kept. A text can begin with `-`, `+`, `=` or `@`, and every phone number starts with `+`: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. Every URL field holds an http(s) URL or nothing. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- The site shows a listing's publication only as "x hours / days / months ago": `publishedAt` is as precise as that text (`publishedAtPrecision`: the minute or the hour for a listing of the last 21 hours, then the day, the month…), exact to the second only for the listings in the site's early access (about 1 in 15 of the listings under 3 days old).
- Most private rentals show no phone number (about 1 in 5 does); a phone number the advertiser writes inside the description stays in the description, whatever `extractPhone` says; street and number are empty when the owner hides the address (`hasFullAddress: false`).
- The site does not filter every property type the same way: a filter it does not offer for your type stops the run at its start, and the message lists the types it works for. For gastronomy, commercial plots and assisted living, the site cannot search the rentals alone: a rent search returns the sales too, told apart by `offerType` (a sale search returns sales only).
- `onlyNew` remembers listing ids, not their content: a listing whose price changed is not returned again.
- Two runs sharing the same `stateKey` at the same time may both return the same new listing.

**A run the platform stops without warning** (out of memory, run timeout)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the listings already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved once a minute: resurrect the stopped run and the listings it had saved meanwhile join the memory; leave it stopped for good, and the next run may return up to a minute of them once more.

#### Something doesn't work?

The last line of the log counts the listings saved, filtered out and no longer on ImmobilienScout24 (removed while the run was reading them), and the requests that failed after every retry. Those requests and the removed listings are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause (an unknown location or a filter the site refuses says so, instead of "run it again"). A run that saved some listings fails too when at least as many requests failed for good as were read — the first results page read, the rest blocked: a green run with a short dataset would hide the outage. One failed request among many is only a warning.

If ImmobilienScout24 changes its data, you are told instead of paying for blank rows. A results page that counts listings but gives none the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet "No listings found". If the first 20 listings read all lack their title, publication date or postal code — or, with `extractDetails`, the raw values of their listing page — the run saves nothing more, stops and fails, and its last message names the missing field: at most those first listings are charged. A listing that `postedAfter` / `postedBefore` drops because it has no date at all counts among those 20.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Changelog

This Actor's version history is a separate document: https://apify.com/nice\_dev/immobilienscout24-listings-scraper/changelog.md

# Actor input Schema

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

ImmobilienScout24.de search URLs (`https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?price=-1500.0`, radius and map-area searches too — every filter set on the site is kept, pagination is automatic) or listing URLs (`https://www.immobilienscout24.de/expose/171143307`). When this list is not empty, the search fields below (property type, keywords, locations) are ignored; site filters set here are added to those of the URL, post-filters, caps and monitoring still apply. Max 1 000 URLs.

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

What to search. Combined with **Offer type** (rent / buy).

## `offerType` (type: `string`):

Rent, buy, or both (both = two searches for homes, one unfiltered search for commercial property). Ignored for the types that only exist one way (flat-share, temporary living: rent; investment, foreclosure, prefab house: buy). Gastronomy, commercial plots, assisted living: the site cannot search their rentals alone — a rent search returns their sales too (told apart by the `offerType` column).

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

Several property types in one run (same values as **Property type**: `apartment`, `house`, `plot`, `garage`, `flatshare`, `temporaryLiving`, `office`, `retail`, `gastronomy`, `industry`, `specialPurpose`, `investment`, `foreclosure`, `prefabHouse`, `commercialPlot`, `assistedLiving`). Added to **Property type**; each one is searched in every location with every keyword.

## `query` (type: `string`):

Free-text search in the listings (the site's `fulltext` search), e.g. `Kamin` or `Altbau`. Empty = no keyword.

## `searchQueries` (type: `array`):

Several keywords in one run: one search per keyword (times each location and property type). Added to **Search keyword**; listings found by several searches are saved once.

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

German city, district, town quarter or federal state, as typed in the site's search box (`Berlin`, `München`, `Prenzlauer Berg`, `Bayern`), or an ImmoScout24 region path (`/de/berlin/berlin`). The best match of the site's own location search is used and written in the log. Empty = the whole of Germany.

## `locations` (type: `array`):

Several locations in one run: every keyword and property type is searched in every location (3 keywords × 4 locations = 12 searches, max 500). Added to **Location**.

## `latitude` (type: `number`):

Centre of a radius search, with **Longitude** and **Radius**. When set, it replaces **Location**.

## `longitude` (type: `number`):

Centre of a radius search, with **Latitude** and **Radius**.

## `radiusKm` (type: `integer`):

Radius around **Latitude** / **Longitude**, in km (the site's radius search).

## `listingIds` (type: `array`):

Fetch these listings directly, by Scout-ID (`171143307`) or listing URL. Always added to the searches above; each one costs one request, is not affected by the site filters, and is charged the **Extract details** price (it is read on its own page).

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

Maximum number of listings to save for the whole run (after deduplication and filters). 0 = no limit — a single search can return every listing of Germany (≈ 83 000 apartments for rent), there is no page limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (property type × location × keyword, or search URL), so that the first search cannot use up the whole **Max listings** budget. 0 = no per-search cap.

## `extractDetails` (type: `boolean`):

Open each listing (1 extra request per listing) for the full description, all costs (service charge, heating, deposit, commission, purchase costs), energy certificate, building data, all photos, the contact's name, company and e-mail (phone numbers: **Extract phone numbers**). Off (default) = the search-card fields only (title, price, area, rooms, address, coordinates, first photos, date): faster and cheaper.

## `extractPhone` (type: `boolean`):

Add the contact's phone numbers (`phone`, `phones`: mobile and landline) read on the listing page (needs **Extract details**: ticked alone, it delivers no phone and the run log says so). Charged only for a listing that shows at least one number; a listing without a phone costs nothing more. Off (default) = no phone in the output: `phone` / `phones` empty, the numbers of the agent's legal notice (`imprint`) replaced by `[phone hidden]`. Always on with **Only with a phone number**.

## `sortBy` (type: `string`):

Order in which the site returns the listings. Newest first is the one used to stop early on **Posted after** / **Only new listings**. `standard` = the site's default order (paid listings first). Not every type has every order (no area order for plots or garages for sale, no price order for foreclosures): such a search stops at once, naming the sort.

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

Lowest price: monthly rent for rentals (cold rent unless **Price type** says total rent), purchase price for sales. Not for: offices, retail, gastronomy, halls, special properties, foreclosures, commercial plots, assisted living.

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

Highest price (same rules as **Min price**).

## `priceType` (type: `string`):

Which rent the price filter reads for apartments for rent: cold rent (Kaltmiete, the site's default) or total rent including service charges (Warmmiete).

## `minRooms` (type: `number`):

Lowest number of rooms (half rooms allowed: `2.5`). Works for: apartments, houses, temporary living.

## `maxRooms` (type: `number`):

Highest number of rooms.

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

Lowest living space. Works for: apartments, houses, flat-share rooms, prefab houses.

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

Highest living space.

## `minPlotArea` (type: `integer`):

Lowest plot area. Works for: plots, commercial plots.

## `maxPlotArea` (type: `integer`):

Highest plot area.

## `minFloorArea` (type: `integer`):

Lowest net floor space. Works for: offices, retail, halls, investment property.

## `maxFloorArea` (type: `integer`):

Highest net floor space.

## `minYearBuilt` (type: `integer`):

Earliest construction year. Works for: apartments, houses.

## `maxYearBuilt` (type: `integer`):

Latest construction year.

## `minFloor` (type: `integer`):

Lowest floor (0 = ground floor). Works for: apartments.

## `maxFloor` (type: `integer`):

Highest floor.

## `equipment` (type: `array`):

Keep the listings that have ALL of these (the site's equipment filter). Each one works for some property types only — Balcony / terrace: apartments, assisted living. Garden: apartments, assisted living. Fitted kitchen: apartments, houses for rent. Lift: apartments, halls. Cellar: apartments, houses, temporary living, retail, gastronomy, special properties. Guest toilet: apartments, houses, temporary living. Garage / parking space: apartments, houses, temporary living, assisted living. Step-free access: apartments, houses, flat-share rooms, temporary living, offices, assisted living.

## `energyEfficiencyClasses` (type: `array`):

Keep the listings of these energy classes (energy certificate). Not for: plots, garages, prefab houses, commercial plots, assisted living.

## `apartmentTypes` (type: `array`):

The site's apartment categories. Works for: apartments.

## `buildingTypes` (type: `array`):

The site's house categories. Works for: houses, prefab houses. The site files mid- and end-terrace houses under one category (either value returns both), and castles / manors with special properties.

## `newBuildingOnly` (type: `boolean`):

Only new-build listings (Neubau). Works for: apartments, houses.

## `excludeNewBuildProjects` (type: `boolean`):

Drop the listings that are units of a developer's new-build project. Sent to the site for apartments and houses for sale; applied to the results for the other types.

## `noCommissionOnly` (type: `boolean`):

Only the listings without a buyer's / tenant's commission (provisionsfrei). Not for: foreclosures, prefab houses, assisted living.

## `petsAllowed` (type: `boolean`):

Only the rentals where pets are allowed. Works for: apartments for rent, houses for rent, flat-share rooms, temporary living, assisted living.

## `excludeRented` (type: `boolean`):

Drop the properties that are currently let (vermietet). Works for: apartments for sale, houses for sale.

## `minInternetSpeed` (type: `integer`):

Lowest internet speed available at the address, as given by the site. Not for: plots, garages, prefab houses, commercial plots, assisted living.

## `postedAfter` (type: `string`):

Only listings published on or after this date: `2026-09-01`, or a period before now such as `7 days`, `2 weeks` (via the API also `24 hours` or a full ISO date-time). The date read is `publishedAt`: derived from the site's “x hours / days / months ago” (precision in `publishedAtPrecision`), exact to the second for the listings still in the site's early access (about 1 in 15 of the listings under 3 days old). The site rounds (“3 days ago” = 2.5 to 3.5 days ago): a listing that may be inside the range is kept, never dropped.

## `postedBefore` (type: `string`):

Only listings published on or before this date (the whole day is included), or older than a period such as `30 days`.

## `postalCodes` (type: `array`):

Keep only the listings in these postal codes (5 digits, or a prefix such as `101` for 101xx). Combine with a **Location** that contains them, e.g. Berlin.

## `excludeKeywords` (type: `array`):

Drop the listings whose title contains one of these words (case and accents ignored).

## `privateSellersOnly` (type: `boolean`):

Keep only the listings of private persons (no agencies). Read on the search card: no extra request.

## `requirePhone` (type: `boolean`):

Keep only the listings whose contact shows a phone number (needs **Extract details**). The phone is on the listing page: each page read and then dropped for lack of one costs $0.45 / 1,000 (apartments for rent: about 2 dropped per listing kept). Turns **Extract phone numbers** on: the phone of each listing kept is delivered and charged.

## `requireEmail` (type: `boolean`):

Keep only the listings whose agent publishes an e-mail in the legal notice (needs **Extract details**; private persons never do: dropped on the search card, without reading their page). An agency listing page read and then dropped for lack of one costs $0.45 / 1,000.

## `earlyAccessOnly` (type: `boolean`):

Keep only the listings still in the site's early access for paying members (Suchen+, the first 2 to 5 days of some listings: about 1 in 15 of the listings under 3 days old), with a publication time exact to the second. Read on the search card: no extra request.

## `onlyNew` (type: `boolean`):

Skip the listings that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their page is not even opened. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new listings**. Give each schedule / task its own key (e.g. `berlin-rentals`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every listing again. Untick it afterwards.

## `includeRaw` (type: `boolean`):

Add `raw`: the site's search card and listing page exactly as received (≈ 20-50 KB per listing). For your own parsing in JSON or through the API; the other fields already hold every value. Leave it off for a CSV or Excel export: with **Extract details**, `raw` adds hundreds of columns per listing, and those exports keep only the first 2,000 columns — other columns would be missing.

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

Apify Proxy or your own proxies. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Global request rate. The site limits the requests per IP address; the Actor already changes IP when it is slowed down. Lower it if the log keeps showing HTTP 429.

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

Retries per request before it is marked as failed.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "startUrls": [],
  "propertyType": "apartment",
  "offerType": "rent",
  "propertyTypes": [],
  "searchQueries": [],
  "location": "Berlin",
  "locations": [],
  "radiusKm": 10,
  "listingIds": [],
  "maxItems": 50,
  "maxItemsPerQuery": 0,
  "extractDetails": false,
  "extractPhone": false,
  "sortBy": "newest",
  "priceType": "coldRent",
  "equipment": [],
  "energyEfficiencyClasses": [],
  "apartmentTypes": [],
  "buildingTypes": [],
  "newBuildingOnly": false,
  "excludeNewBuildProjects": false,
  "noCommissionOnly": false,
  "petsAllowed": false,
  "excludeRented": false,
  "postalCodes": [],
  "excludeKeywords": [],
  "privateSellersOnly": false,
  "requirePhone": false,
  "requireEmail": false,
  "earlyAccessOnly": false,
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "includeRaw": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 4,
  "maxRequestsPerMinute": 120,
  "maxRequestRetries": 8,
  "debugLog": false
}
```

# 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 = {
    "propertyType": "apartment",
    "offerType": "rent",
    "location": "Berlin",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/immobilienscout24-listings-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 = {
    "propertyType": "apartment",
    "offerType": "rent",
    "location": "Berlin",
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/immobilienscout24-listings-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 '{
  "propertyType": "apartment",
  "offerType": "rent",
  "location": "Berlin",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/immobilienscout24-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/immobilienscout24-listings-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/gzMhwmVwJdXyuqmHD/builds/LaV88iDap5Xlcw0F7/openapi.json
