# ImmoScout24 Scraper - ImmobilienScout24.de Rent & Sale (`amitaviv/immoscout24-scraper`) Actor

Scrape ImmoScout24 (immobilienscout24.de) apartments and houses for rent and sale from a search URL or a place with filters. One record per listing: price, cold and warm rent, m², rooms, address, coordinates, features, energy data, photos, agency. New-listings monitoring. $0.60 per 1,000 on Bronze.

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

## Pricing

from $0.48 / 1,000 listing ($0.60 per 1,000 on bronze)s

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

## ImmoScout24 Scraper (immobilienscout24.de)

Returns rent and sale listings for apartments and houses from ImmoScout24 Germany, from search URLs you copy out of the browser or from a few filter fields. Plain HTTP with no browser, so a run of 100 listings with full details usually takes 5 to 35 seconds; apart from the start fee you pay only for delivered listings, and a run that delivers nothing because of an error ends as Failed, never as a green empty run.

**Not for re-publication.** ImmoScout24's listings are protected by database rights. This actor is for analysis, research and monitoring; re-publishing listings or building a competing listings database from the output is not permitted. See "Legal and responsible use".

### What you get

- Price, cold rent, warm rent, service charges, heating costs, deposit, commission, price per m²
- Living space, plot area, rooms, bedrooms, bathrooms, floor, construction year, condition, object type, availability
- Address as the advertiser published it (a hidden street stays hidden), postcode, city, district, federal state, coordinates
- Features (balcony, cellar, lift, fitted kitchen, ...), energy class, certificate type, consumption, heating type, energy sources
- Descriptions, all photo URLs (a video tour and the advertising slot the source puts into some galleries are not included), relative publication age with an estimated date
- Private/commercial flag; for commercial advertisers the company name, business phone numbers, profile URL, rating and logo
- Every labelled attribute of the listing under `attributes`, in the site's own German labels
- One record per listing, as JSON, CSV or Excel, or through the API
- A run summary (`OUTPUT_SUMMARY` in the run's key-value store): what was requested, delivered and charged; per search, how many results the site reports against how many were listed and delivered, and how many are missing after a whole read; which inputs failed or were ignored; warnings; why the run stopped

What it does not return: the contact person's name (never taken from the contact fields, for any advertiser; a sole trader whose business name is their own name appears under that name as `agencyName`); phone numbers and agency fields of private advertisers; anything behind a login; an exact publication date (the source gives only "vor 3 Tagen"); property types other than apartments and houses; Austria and Switzerland.

### How to use

1. Open immobilienscout24.de, make the search you want (region, radius or drawn area, any filters) and copy the URL from the browser.
2. Paste it into **Search URLs**. Several entries are fine. Or leave it empty and fill in **Location** with the filter fields.
3. Set **Max listings per search** and press Start.
4. Download the results from the Output tab, or read them from the API.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `startUrls` | list of text | none | Search URLs from the website (`/Suche/de/...`, `/Suche/radius/...`, `/Suche/shape/...`) for `wohnung-mieten`, `wohnung-kaufen`, `haus-mieten`, `haus-kaufen`. The URL's filters are forwarded unchanged. Of the URL's sort order only "newest first" (`sorting=2`) is applied; any other is replaced by the site's standard order, with a warning in the log and the summary (this matters only when the maximum is below the number of results). URLs without `https://` are accepted, duplicates are ignored, entries from other sites or of other property types are ignored and listed in the summary. A listing URL (`/expose/<id>`) returns that listing. |
| `location` | text | none | Instead of a URL: a city, district or federal state, e.g. `München`. Several separated by `;`. The first match of the site's own place lookup is used. Postcodes are not supported here. |
| `dealType`, `propertyType` | choice | rent, apartment | For `location`. |
| `priceMin`, `priceMax`, `roomsMin`, `roomsMax`, `areaMin`, `areaMax` | number | none | For `location`. Price is cold rent per month for rentals and purchase price for sales. Rooms may be written `2.5` or `2,5`. A value that is not a number, or a minimum above its maximum, fails the run before any request instead of being left out. |
| `maxItemsPerQuery` | number | 100 | Stop after this many listings for each URL or location. Set it above the number of results to take a whole search. |
| `includeDetails` | yes/no | yes | Yes: each listing is completed from its detail record (one extra request per listing). No: only what the result list shows; about 10 times faster. Same price. |
| `includeHomeBuilderOffers` | yes/no | no | House-for-sale searches also contain offers of prefabricated-house companies. Left out and counted in the summary by default. |
| `onlyNew` | yes/no | no | Monitoring: return and charge only listings that earlier runs have not delivered. See "Monitoring". |
| `monitorKey` | text | empty | Name of the monitor memory, to keep two schedules apart. |
| `proxyConfiguration` | proxy | off | Not needed in our tests. Turn on Apify Proxy (datacenter) only if a run reports blocking or rate limiting. |

```json
{
  "startUrls": ["https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?price=-1500.0&numberofrooms=2.0-&equipment=balcony"],
  "maxItemsPerQuery": 40
}
```

This input was run as `SjaWp5aEx8VQhLLyV` on 2026-10-13: 40 listings in 4.3 seconds, none above 1,500 EUR, none below 2 rooms, all 40 with a balcony or terrace.

### Example result

Taken from an earlier run of the same input (`X5c5xaoMLqRXpurZD`, 2026-10-13). The four description texts and the image list (5 URLs) are shortened here; nothing else is edited.

```json
{
  "id": "170106955",
  "url": "https://www.immobilienscout24.de/expose/170106955",
  "title": "Neubau Erstbezug * 2 Zimmer Wohnung im EG * Terrasse",
  "realEstateType": "apartmentrent",
  "dealType": "rent",
  "propertyType": "apartment",
  "price": 1216,
  "currency": "EUR",
  "pricePerSqm": 27.52,
  "coldRent": 1216,
  "warmRent": 1376,
  "serviceCharges": 80,
  "heatingCosts": 80,
  "deposit": "3.648,00 €",
  "commission": null,
  "priceRating": null,
  "livingSpace": 44.19,
  "plotArea": null,
  "rooms": 2,
  "bedrooms": 1,
  "bathrooms": 1,
  "floor": "0 von 6",
  "numberOfFloors": 6,
  "constructionYear": 2026,
  "condition": "Erstbezug",
  "objectType": "Erdgeschosswohnung",
  "availableFrom": "sofort",
  "address": "Pufendorfstraße 3A-3E, 10249 Berlin, Friedrichshain",
  "street": "Pufendorfstraße 3A-3E",
  "postcode": "10249",
  "city": "Berlin",
  "district": "Friedrichshain",
  "state": "Berlin",
  "latitude": 52.52193,
  "longitude": 13.43821,
  "features": [
    "Balkon/Terrasse",
    "Keller",
    "Personenaufzug",
    "Einbauküche"
  ],
  "energyEfficiencyClass": "B",
  "energyCertificateType": "Bedarfsausweis",
  "energyConsumption": 58,
  "heatingType": "Fernwärme",
  "energySources": "Fernwärme",
  "description": "PANDION MIDTOWN ist für alle da: für alle Lebensphasen, für alle Familiengrößen, für alle Wohnwünsche – eben einfach für alle Fälle. Größen von 1 bis 4 Zimmern …",
  "equipmentDescription": "Wohnzimmer mit offener Küche\n- Fensterfronten mit Süd-/Westausrichtung\n- Mehrsch…",
  "locationDescription": "Mitten in der Hauptstadt, mitten im Kiez, mitten im Leben: Für PANDION MIDTOWN i…",
  "otherDescription": "Wir haben Ihr Interesse geweckt? Dann senden Sie uns bitte eine Anfrage mit eini…",
  "imageUrl": "https://pictures.immobilienscout24.de/listings/90cd34c6-565d-4ab8-9db3-088713f3a599-2107024885.jpg/ORIG/resize/1500x1000/format/webp/quality/80",
  "images": [
    "https://pictures.immobilienscout24.de/listings/90cd34c6-565d-4ab8-9db3-088713f3a599-2107024885.jpg/ORIG/resize/1500x1000/format/webp/quality/80",
    "https://pictures.immobilienscout24.de/listings/81bd4800-a53a-41f0-8c0a-6f6adce24a5c-2107024882.jpg/ORIG/resize/1500x1000/format/webp/quality/80"
  ],
  "imageCount": 5,
  "publishedText": "vor 2 Monaten",
  "publishedDaysAgo": 60,
  "publishedAtEstimate": "2026-08-14",
  "isPrivate": false,
  "advertiserType": "commercial",
  "agencyName": "PANDION Servicegesellschaft mbH",
  "agencyPhones": [
    "+49 162 1774183",
    "+49 30 200074935"
  ],
  "agencyProfileUrl": "https://www.immobilienscout24.de/anbieter/pandion-servicegesellschaft-mbh/ac528eb13c96696d6d68c92",
  "agencyRating": 4.3,
  "agencyRatingCount": 109,
  "agencyLogoUrl": "https://pictures.immobilienscout24.de/usercontent/5b436368-d6d6-48cb-a54d-b5356279c6a2.PNG",
  "listingType": "XL",
  "isNewBuild": false,
  "isProject": false,
  "isHomeBuilderOffer": false,
  "onlyOnImmoScout24": false,
  "attributes": {
    "Hauptkriterien": {
      "Wohnungstyp": "Erdgeschosswohnung",
      "Etage": "0 von 6",
      "Etagenzahl": "6",
      "Schlafzimmer": "1",
      "Badezimmer": "1",
      "Bezugsfrei ab": "sofort",
      "Haustiere": "nach Vereinbarung",
      "Balkon/Terrasse": true,
      "Keller": true,
      "Personenaufzug": true,
      "Einbauküche": true,
      "Wohnfläche ca.": "44,19 m²"
    },
    "Kosten": {
      "Preis/m²": "27,52 €/m²",
      "Nebenkosten": "80 €",
      "Heizkosten": "80 €",
      "Heizkosten in Nebenkosten enthalten": "Nein",
      "Gesamtmiete": "1.376 €",
      "Kaution oder Genossenschaftsanteile": "3.648,00 €",
      "Kaltmiete (zzgl. Nebenkosten)": "1.216 €"
    },
    "Bausubstanz & Energieausweis": {
      "Baujahr": "2026",
      "Objektzustand": "Erstbezug",
      "Qualität der Ausstattung": "Gehoben",
      "Heizungsart": "Fernwärme",
      "Energieausweistyp": "Bedarfsausweis",
      "Energieausweis": "liegt vor",
      "Wesentliche Energieträger": "Fernwärme",
      "Endenergiebedarf": "58 kWh/(m²∙a)",
      "Baujahr laut Energieausweis": "2026"
    }
  },
  "detailsFetched": true,
  "query": "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?equipment=balcony&numberofrooms=2.0-&price=-1500.0",
  "scrapedAt": "2026-10-13T13:51:44.329Z"
}
```

| Field | Meaning |
|---|---|
| `id`, `url` | The site's own listing id (stable between runs) and the listing page. |
| `price` | Cold rent per month for rentals, purchase price for sales. EUR. `null` when the advertiser shows "Auf Anfrage" (price on request); such listings also come back from a search with a price filter (17 of 150 in run `46wTLsEhr9RZBBAYa`). |
| `coldRent`, `warmRent`, `serviceCharges`, `heatingCosts` | Rentals only, as numbers. `warmRent` needs `includeDetails`. |
| `deposit`, `commission`, `floor`, `availableFrom` | Text as the advertiser wrote it. |
| `address`, `street`, `postcode`, `city`, `district` | As published. `street` is `null` when the advertiser hides it, and `address` then ends with "(unvollständige Adresse)"; `latitude` and `longitude` are then `null` too if the source gives none. `city` is the advertiser's text and can include a district ("München / Solln", "Berlin - Spandau (Spandau)"); group by `postcode` for reliable aggregation. |
| `publishedText`, `publishedDaysAgo`, `publishedAtEstimate` | The site's relative age, the same as days, and the date that follows from it (exact to the day only for listings less than a week old). |
| `isPrivate`, `advertiserType` | `true` / `"private"` for a private advertiser, `false` / `"commercial"` for a company. `null` if the source does not say. |
| `agencyName`, `agencyPhones`, `agencyProfileUrl`, `agencyRating`, `agencyRatingCount`, `agencyLogoUrl` | Commercial advertisers only. `null` for private advertisers and when the flag is unknown. |
| `imageUrl`, `images`, `imageCount` | The first photo, all photos, and their number. Photos only: a video tour is not included. |
| `title`, the four description fields, text values in `attributes` | For private advertisers, phone numbers, e-mail addresses and names after "Herr", "Frau" or "Familie" written into these texts are replaced with `[removed]`. |
| `features` | The listing's ticked features, in German. |
| `attributes` | All labelled values of the listing, grouped as on the site. |
| `isHomeBuilderOffer` | `true` for a prefabricated-house offer (only with `includeHomeBuilderOffers`). |
| `detailsFetched` | `false` when the record holds list data only (`includeDetails` off, or the listing was removed between list and detail). |
| `query`, `scrapedAt` | The search this listing came from, and when. |

Fields the site does not provide for a listing are `null`, never missing.

### Pricing

Pay per event. You pay for what is delivered, not for time or memory.

| Event | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Actor start (once per run) | $0.0036 | $0.003 | $0.0027 | $0.0024 |
| Listing delivered (with or without details) | $0.00072 | $0.0006 | $0.00054 | $0.00048 |

Worked example on Bronze: one search, 500 listings with full details = 500 × $0.0006 + $0.003 = **$0.303**. A scheduled monitoring run that finds 5 new listings costs 5 × $0.0006 + $0.003 = $0.006; a run that finds nothing new costs $0.003.

- Listings that could not be delivered are not charged. A listing returned by two of your searches is delivered and charged once.
- The start event is charged by the platform when a run starts, also when the run then fails or finds nothing. Resurrecting a run charges it again.
- The maximum total charge you set for a run is respected: the actor stops before it would go over, keeps what was delivered, and says so in the status message. Run `RuUS4bf5bbHeNvWLZ` with a limit of $0.0102 delivered exactly 12 listings (12 × $0.0006 + $0.003). A limit below the price of one listing fails the run at once (`mT2sDfOJuEdi5EcOX`).

### Reliability and failure behaviour

| What happened | Run status | Status message |
|---|---|---|
| Listings delivered | Succeeded | `Scraped 800 listings from 1 query` |
| The site has no listings for your search | Succeeded | `0 results: ImmoScout24 has no listings for this query` |
| Some entries worked, some failed | Succeeded | `Scraped 26 listings from 3 queries — 1 of 3 queries failed ("…": …)` |
| A whole search was read and some reported results were never shown | Succeeded | `Scraped 229 listings from 1 query — 229 of the 230 results ImmoScout24 reports for … were met in two readings; its result pages shift while they are read` |
| Nothing delivered because of errors or blocking | **Failed** | `No listings delivered: ImmoScout24 blocked every attempt; try again later. No listings were charged (the start fee applies).` |
| Input the actor cannot use | **Failed**, within 2 seconds | `Nothing to do: … Add at least one entry to "startUrls", e.g. …` or `"priceMin" (900) is above "priceMax" (100), so no listing can match: …` |
| Maximum charge reached | Succeeded | `… — stopped at the maximum charge set for this run` |
| Run timeout close | Succeeded | `… — stopped just before the run timeout; raise the timeout to get the rest` (if the source was refusing requests at that moment, the message says so instead and advises to try again later) |
| The source answers a search with a server error | Succeeded if another search delivered, else **Failed** | `… 1 of 2 queries failed ("…": ImmoScout24 answered with an error (HTTP 500, 3 attempts))` |
| You abort the run | Aborted | Delivered listings are kept and charged; `OUTPUT_SUMMARY` has status `ABORTED` |

- Requests are retried with increasing pauses on network errors and HTTP 429 (rate limit). A server error (HTTP 5xx) is tried three times a few seconds apart; then that search fails by name and the next one runs.
- Listings are saved page by page. A run that is aborted keeps what was delivered and writes its summary; resurrected, it never delivers or charges the same listing twice (run `Bc2iHltQ0hLzXa1MD`: aborted at 100, summary written, resurrected, finished with 400 listings, 400 distinct, 400 charged; run `LajEtpPWkcEgPYKNw`: aborted, 200 delivered, 200 charged, summary status `ABORTED`).
- A filter value the source rejects fails that search with the source's own message instead of returning unfiltered data. A URL parameter the source does not know is ignored, logged, and listed in the summary under `ignoredUrlParameters`. An entry that is not a usable URL is ignored and listed; the other entries still run (`1oLOWT2xP3ezvyowx`).
- **Rate limit.** The source's search endpoint has one. From a datacenter address outside Apify, 84 result-page requests in 32 seconds were followed by HTTP 429 for about 5 minutes; listing details kept answering. From Apify's servers no 429 was met in any of our test runs on 2026-10-13, at up to 3.9 result pages a second and 2,522 requests in one run; where the threshold lies for Apify's addresses is not known. The actor leaves at least 0.3 seconds between result pages, and if it is rate-limited without a proxy it waits 20, 40, 80, 160 and 320 seconds before giving up on that search, which outlasts the block we measured. That waiting has run only in offline simulations, never on the platform. A search given up on is reported as failed; the run is Failed only if nothing at all was delivered.

### Complete snapshots

The source this actor reads has no result cap, so there is no splitting by price bands and none is needed: set `maxItemsPerQuery` above the number of results and the search is read to its last page. Whole searches of 19,769 and 19,791 results were read end to end through the actor (198 pages each); for a Germany-wide rental search reporting 85,801 results only single pages were checked by hand (pages 150, 250, 400 and the last, 859).

What does limit completeness is that the site's result pages shift while they are read: in our whole-search runs 0.6 to 1.3 listings per 1,000 were shown twice and as many were not shown at all. The actor handles this as follows.

- A listing shown twice is delivered and charged once, and does not count against your maximum.
- When a whole search has been read and fewer results were met than the site reports, the search is read once more in another order, until the count is reached or the second reading ends. Run `Z2UXEl5XmTid8Ywuh` (apartments for rent in Hessen): 6,408 of 6,412 after the first reading, 6,412 of 6,412 after 53 more pages; 6,412 delivered, 6,412 distinct, 6,412 charged.
- If results are still missing after the second reading, the status message says how many, and the summary has it per search: `reportedBySite`, `listed` (distinct listings met), `missing`, `readings`, `pushed`.
- Home-builder offers left out of a house-for-sale search are counted, not missing. Run `OeYdccWF2vfKwUQkm`: apartments for rent in Cologne, 909 reported, 909 delivered; houses for sale in Cologne, 1,108 reported = 774 delivered + 334 home-builder offers left out. Run `W5jV4UQLk7NxuJpZg` (houses for sale in Sachsen, 102 result pages, one of them holding home-builder offers only): 10,117 reported = 4,407 delivered + 5,710 home-builder offers left out, 0 missing. Builds before 0.1.12 ended such a search at the page that held only home-builder offers and delivered 4,009 of these listings without saying so; that is fixed.
- In **Only new listings** mode there is no second reading. A first monitoring run over a whole search of 19,791 results delivered 19,774 and said so in its message (`GWocTmBGXxM4Shcsn`).

Not tested: a second reading on a search above 6,412 results, and a whole search above 19,791 results. No live run has yet come up short after two readings, so that status message and the `missing` figure above 0 have run only in offline simulations.

### Limits

- Apartments and houses, rent and sale, Germany. Other types (rooms in shared flats, temporary living, plots, garages, commercial) are refused with a message.
- With `includeDetails` between about 180 and 1,300 listings per minute in our runs, depending on the search; 450 to 490 was typical on a large single search (800 in 98 s, `J9ZneiG2dE9ZNHE8h`; 100 in 4.7 s, `tgkBKtXI8LneeySqs`; 150 in 21.6 s, `46wTLsEhr9RZBBAYa`; 200 over two state-level searches in 66.5 s, `dHBcAJdjZpVbNEA95`). Without, about 4,000 to 8,000 per minute (6,412 with a second reading in 96 s; 2,500 in 17 s).
- `warmRent`, `features`, energy data other than the class, descriptions, the full photo list, `agencyName` and `agencyPhones` need `includeDetails`.
- Fields advertisers often leave empty stay `null`: in a sample of 40 Berlin rentals, 22 had no deposit, 10 no energy consumption and 3 no construction year.
- Whether a pasted URL returns exactly what the website shows for it could not be compared directly (the website does not answer automated requests). The filters tested (price, rooms, living space, equipment, construction year, new building, floor) changed the result count and the delivered listings as expected. A drawn-area URL (`/Suche/shape/...`) was run with a hand-made polygon over central Berlin, with the area written both plainly and in base64 (`Uqfts2mCMBoW77Euh`: 638 and 1,127 results reported, 20 delivered from each); a URL copied from the website after drawing an area has not been tested.
- Listings come in the site's standard order, or newest first for `sorting=2` and in monitoring mode. With a maximum below the number of results, a URL with another sort order therefore returns a different selection than the website shows first.
- `district` comes from the result list and can differ from the district named on the listing's own page.

### Monitoring: only new listings

1. Turn on **Only new listings** and save the input as a task.
2. Schedule the task (hourly or daily).
3. The first run delivers the newest listings up to the maximum; everything else on the result pages it read counts as seen. Every later run reads the search newest first, delivers and charges only listings it has not seen for the same search, and stops after the first page that holds a known listing. A run with nothing new ends as Succeeded with `0 new listings in 1 monitored query (no listings charged; the start fee applies)` and charges only the start event.

Two rules follow:

- **Later runs deliver what is newer than the first run's listings, not what its maximum cut off.** Runs `bbD9YxDQrvFUlgNgd` and `ZYFGBywPkOvJaSQ37` (Hamburg rentals, maximum 130, minutes apart): 130 delivered, then 0, although the search has 901 results. Runs `eXv5ru9c5eioCgO7E` and `MwPegGUnCXeaRDwQA` (Berlin rentals, maximum 20): 20 delivered, then 0. To start with the whole search, set the maximum above the number of results for the first run.
- **Set the maximum above the number of new listings you expect between two runs.** If a later run finds more new listings than the maximum (or than your charge limit pays for), it delivers the newest of them. The next run still delivers the rest if they are among the 100 newest listings of the search by then; otherwise they are not delivered. The status message says so when the maximum caused it.

The memory is a key-value store named `immoscout24-scraper-monitor` in your own account: one record per search and monitor name, holding the ids of the newest 10,000 listings delivered. That is enough for searches of any size: a first run over 19,791 results delivered 19,774 listings, and the run started right after delivered 5, all published 2 to 7 minutes earlier and none delivered before (`GWocTmBGXxM4Shcsn`, `bA6fr7zE6txY0Q4BM`). The sort order of a pasted URL does not matter: the same search has the same memory. Delete the store or change **Monitor name** to start over. To be notified, add an integration to the task (email, Slack, webhook) on "run succeeded".

Not included: detection of price changes or removed listings.

### FAQ

**Do I need a proxy?** Not in our tests: every test run without a proxy was answered from Apify's own addresses with no retry. The source does rate-limit its search endpoint (see "Reliability"), so if a run reports a rate limit, turn on Apify Proxy (datacenter); each retry then leaves from another address. It works (run `ibsai4HJcOaosojJj`) but is slower.

**Why did I get fewer results than the site shows?** `maxItemsPerQuery` (default 100) was reached, or home-builder offers were left out of a house-for-sale search (counted in the summary as `homeBuilderOffersSkipped`), or the same listing was already delivered for another of your searches, or a few results were never shown by the site's shifting result pages (`missing` in the summary, and named in the status message).

**Why is `agencyName` empty?** The advertiser is private (`isPrivate: true`), or `includeDetails` is off.

**Can I run it from code?** Yes: the API and the Apify clients for JavaScript and Python, or Make, Zapier and n8n through Apify's integrations. The Output tab shows the URLs.

**What happens when the source changes?** Runs fail loudly instead of returning empty data; report the run id under Issues.

### Legal and responsible use

- **Database rights and terms.** ImmoScout24 asserts database rights in its listings, and its terms of use forbid automated retrieval and commercial re-use of its data. Re-publishing listings, in whole or in substantial part, or building your own listings database or portal from them is not permitted. Use this actor for analysis, research and monitoring, and check that your use is lawful before you rely on it.
- **Personal data.** The actor returns listing data and business data. It never returns the name of a contact person. For private (non-commercial) advertisers it returns the `isPrivate` flag but no name, no phone number and no agency fields, and phone numbers, e-mail addresses and names after "Herr", "Frau" or "Familie" written into their title, description texts and attribute texts are replaced with `[removed]`. When the source does not say whether an advertiser is private, the listing is treated as private. There is no switch to turn this off. The private/commercial flag is the source's own: someone who advertises through a commercial account is treated as a business, with the name and phone number published for that account (sole traders and sales agents trade under their own name; in a sample of 1,693 commercial listings 18 had a person's name as `agencyName`). For home-builder offers the company name is returned without the sales contact the source appends to it. The address and coordinates of the advertised property are returned as published.
- **Your responsibility.** Titles and descriptions are free text written by advertisers and can still contain personal data the masking does not recognise: it finds phone numbers and e-mail addresses by their pattern, and a name that follows "Herr", "Frau" or "Familie"; a first name used as a sign-off, or any other name, stays. Commercial advertisers' texts are not masked. You are responsible for how you use the output: data-protection law (GDPR, BDSG), copyright in texts and photos, and the site's terms apply to you. Do not use the output for unsolicited marketing. If you are unsure, ask a lawyer before you build on it.

### Changelog

- 2026-10-13, 0.1: first version.
- 2026-10-13, build 0.1.13: a result page holding only home-builder offers no longer ends a house-for-sale search early; server errors fail a search after three tries instead of ten minutes of waiting; drawn-area URLs accept the area in base64; the summary of an aborted run says `ABORTED`; names after "Herr", "Frau", "Familie" are masked in private advertisers' texts; home-builder offers carry the company name without the sales contact.

### Related actors

- [Immowelt Scraper](https://apify.com/amitaviv/immowelt-scraper): Germany's other large property portal; it uses the same names for the main fields (price, warmRent, livingSpace, rooms, postcode, city, district, latitude, longitude, advertiserType, agencyName, url), so the two outputs stack into one table.
- [Kleinanzeigen Scraper](https://apify.com/amitaviv/kleinanzeigen-scraper): the property categories of Germany's largest classifieds site (rental flats, houses, flat shares), where many private landlords advertise instead of on the portals.
- [Property Listing Status Checker](https://apify.com/amitaviv/property-listing-status-checker): paste ImmoScout24 listing URLs (`/expose/<id>`) you already have and learn which are still online, which are gone, and whose price changed.
- [Idealista Scraper](https://apify.com/amitaviv/idealista-scraper): the same kind of listing data for Spain, Portugal and Italy.

### Support

Open an issue on the actor's **Issues** tab with the run id.

# Actor input Schema

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

ImmoScout24 search URLs copied from the browser's address bar, e.g. https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?price=-1500.0\&numberofrooms=2.0- (Berlin flats to rent, up to 1,500 EUR cold rent, 2 rooms or more). Each URL is one search; several are fine. Region (/Suche/de/…), radius (/Suche/radius/…) and drawn-area (/Suche/shape/…) searches for wohnung-mieten, wohnung-kaufen, haus-mieten and haus-kaufen. The URL's filters are applied as they are; of its sort order only "newest first" (sorting=2) is applied, any other is replaced by the site's standard order. URLs without https:// are accepted. A listing URL (…/expose/123456) returns that one listing. Default: empty. Leave empty to search by "location" instead; both can be used in one run.

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

Instead of (or as well as) a URL: a German city, district or federal state as you would type it on the site, e.g. München, Berlin Kreuzberg or Sachsen. Separate several with a semicolon (Hamburg; Köln); each is one search. The first match of the site's own place lookup is used. Postcodes are not supported: paste a search URL for those. Combined with the deal type, property type, price, rooms and living-space fields below. Default: empty.

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

For the places in "location" (a pasted URL keeps its own): rent (default) or buy.

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

For the places in "location" (a pasted URL keeps its own): apartment (default) or house.

## `priceMin` (type: `integer`):

Lowest price in whole euros for the places in "location", e.g. 800: cold rent per month for rentals, purchase price for sales. Default: no minimum.

## `priceMax` (type: `integer`):

Highest price in whole euros for the places in "location", e.g. 1500: cold rent per month for rentals, purchase price for sales. Default: no maximum. A value below priceMin fails the run before any request.

## `roomsMin` (type: `string`):

Minimum number of rooms for the places in "location", written as text, e.g. "2" or "2.5" ("2,5" is read the same; German room counts include the living room). Default: no minimum. A value that is not a number fails the run instead of being ignored.

## `roomsMax` (type: `string`):

Maximum number of rooms for the places in "location", written as text, e.g. "4". Default: no maximum. Must not be below roomsMin.

## `areaMin` (type: `integer`):

Minimum living space in square metres (m²) for the places in "location", e.g. 50. Default: no minimum.

## `areaMax` (type: `integer`):

Maximum living space in square metres (m²) for the places in "location", e.g. 90. Default: no maximum. A value below areaMin fails the run before any request.

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

Maximum number of listings delivered for each search (each URL and each place), from 1 to 300,000; default 100. Apart from the start fee you pay only per delivered listing, so this also caps the cost. To take a whole search, set this above the number of results the site shows; a whole search that comes up short of the site's count is read a second time for the missing listings, and nothing is charged twice.

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

On (default): each listing is completed from its detail record (warm rent, service charges, deposit, features, energy data, construction year, condition, descriptions, all photos, agency name, rating and business phone); one extra request per listing. Off: only what the result list shows (price, living space, rooms, address, coordinates, energy class, one image, private/commercial flag); about 10 times faster. The price per listing is the same either way.

## `includeHomeBuilderOffers` (type: `boolean`):

House-for-sale searches also contain offers of prefabricated-house companies ("Bauen mit …"), which are not existing properties. Off (default): they are left out and counted in the run summary. On: they are delivered with isHomeBuilderOffer = true.

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

Off (default): every run delivers the listings it finds. On: return and charge only listings that earlier runs of this actor in your account have not delivered for the same search, for scheduled monitoring. Searches are then read newest first and stop at the first page that holds a known listing. The first run delivers the newest listings up to the maximum and treats the rest of the pages it read as seen; later runs deliver only listings that appeared since, so set maxItemsPerQuery above the number of new listings you expect between two runs. The memory is a key-value store named immoscout24-scraper-monitor in your account; delete it to start over.

## `monitorKey` (type: `string`):

Only with onlyNew. A free name for the monitor memory, e.g. berlin-hourly. Runs with the same search and the same monitor name share one memory; give two schedules different names to keep their memories apart. Default: empty (one shared memory per search).

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

Default and recommended: no proxy. The source answered every request from Apify's own addresses in our tests. Its search endpoint does have a rate limit (seen from another datacenter address, never from Apify's). If a run reports that it was blocked or rate-limited, switch on Apify Proxy (datacenter is enough); each retry then goes out from a different address. Runs through the proxy are slower.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?price=-1500.0&numberofrooms=2.0-"
  ],
  "dealType": "rent",
  "propertyType": "apartment",
  "maxItemsPerQuery": 100,
  "includeDetails": true,
  "includeHomeBuilderOffers": false,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All delivered listings as JSON, one object per listing. Main fields: id, url, title, dealType (rent or buy), propertyType (apartment or house), price (EUR: cold rent per month for rentals, purchase price for sales), pricePerSqm, coldRent, warmRent, serviceCharges, heatingCosts, deposit, livingSpace (m²), plotArea, rooms, bedrooms, bathrooms, floor, constructionYear, condition, address, street, postcode, city, district, state, latitude, longitude, features, energyEfficiencyClass, energyConsumption, heatingType, description, imageUrl, images, publishedAtEstimate, advertiserType (private or commercial), agencyName, agencyPhones, attributes, detailsFetched, query, scrapedAt. A value the source does not give is null.

## `resultsCsv` (type: `string`):

All delivered listings as a CSV file, one row per listing, with the same fields as the JSON output (lists and the attributes object are flattened into columns).

## `summary` (type: `string`):

JSON record OUTPUT_SUMMARY: what was requested, delivered and charged; per search what the site reports against what was listed and delivered, and what is missing after a whole read; which inputs failed or were ignored and why; warnings; why the run stopped.

# 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?price=-1500.0&numberofrooms=2.0-"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("amitaviv/immoscout24-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?price=-1500.0&numberofrooms=2.0-"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("amitaviv/immoscout24-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?price=-1500.0&numberofrooms=2.0-"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call amitaviv/immoscout24-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,amitaviv/immoscout24-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/2fQKJdVYOYohJp7gK/builds/28YnWQibxbKf2dSII/openapi.json
