# Immowelt Scraper — German Buy & Rent Listings (`khadinakbar/immowelt-all-in-one-scraper`) Actor

Scrape Immowelt.de buy and rent listings by city, district, or search URL. Returns flat MCP-ready rows: price, rooms, m², address, agency phone, images. HTTP-only SERP extract, cookieless, no Immowelt login.

- **URL**: https://apify.com/khadinakbar/immowelt-all-in-one-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 property scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Immowelt All-in-One Scraper — German Buy & Rent Listings

Immowelt All-in-One Scraper is an Apify Actor for collecting public Germany real-estate listings from Immowelt.de. It accepts a German city or district name, or a pasted Immowelt `/liste` or `/suche` search URL, and returns one structured record per listing. Each record can include asking price, rooms, living space in m², address, city, ZIP, agency name, agency phone, gallery image URLs, and the canonical expose URL. It runs over HTTP (Cheerio + SSR extract) and is usable through Apify MCP.

### Best fit and connected workflows

This Actor fits workflows centered on German residential inventory from Immowelt:

- Rent-side research from `mieten` searches, with cold rent, rooms, m², and agency contact fields
- Buy-side research from `kaufen` searches, with purchase price and size fields
- URL-driven collection when you already filtered on Immowelt and want the Actor to follow that search
- Location-driven collection when you want the Actor to resolve a city such as Berlin or München and run buy or rent filters
- CRM and spreadsheet import where one flat row per listing is the next step

If your workflow centers on another property market, these verified related Actors provide natural routing options:

- Then use [Idealista Scraper](https://apify.com/khadinakbar/idealista-scraper) to extend Immowelt All-in-One Scraper with a neighboring Idealista source when the brief calls for Idealista data
- Then use [Rightmove All-in-One Scraper](https://apify.com/khadinakbar/rightmove-all-in-one-scraper) to extend Immowelt All-in-One Scraper with a neighboring UK BUY/RENT/SOLD source when the brief calls for Rightmove data
- Then use [Fotocasa All-in-One Scraper](https://apify.com/khadinakbar/fotocasa-all-in-one-scraper) to extend Immowelt All-in-One Scraper with a neighboring Spain buy/rent source when the brief calls for Fotocasa data

Immowelt All-in-One Scraper — German Buy & Rent Listings is designed as a focused standalone workflow for Immowelt Germany.

### Practical scenario

Jonas is comparing Berlin apartment rentals for a relocation client. He sets `location` to `Berlin`, `operation` to `rent`, `estateType` to `apartment`, and `maxItems` to `10`. The dataset returns fields such as `price`, `rooms`, `livingSpaceSqm`, `city`, `agencyPhone`, and `url`. Jonas sorts by cold rent, shortlists three districts, and opens each `url` to review photos before sharing a shortlist with the client. For more than about 30 cards in one city, he adds district `startUrls` such as Berlin-Mitte and Charlottenburg.

### Input

Use either an Immowelt URL in `startUrls` or a location-based search with `location` and `operation`.

| Field | Type | Purpose |
|---|---|---|
| `startUrls` | array | Immowelt `/liste` or `/suche` search URLs. District URLs expand coverage beyond one SSR page. |
| `location` | string | German city or district when `startUrls` is empty (for example Berlin, München, Frankfurt). |
| `operation` | string | `rent` or `buy` for location mode. |
| `estateType` | string | `apartment`, `house`, `plot`, `commercial`, or `garage`. |
| `minPrice` / `maxPrice` | integer | Client-side EUR filters applied to the SSR page cards. |
| `minRooms` / `maxRooms` | number | Client-side Zimmer filters. |
| `minSpace` / `maxSpace` | number | Client-side living-space filters in m². |
| `maxItems` | integer | Cap on returned rows and property event charges. |
| `proxyConfiguration` | object | Datacenter default; Apify Residential DE when Immowelt returns DataDome blocks. |

Focused input example:

```json
{
  "location": "Berlin",
  "operation": "rent",
  "estateType": "apartment",
  "maxItems": 10
}
```

### Output

Each dataset item is one flat JSON record per listing.

| Field | Type | Meaning |
|---|---|---|
| `listingId` / `legacyId` | string | Immowelt identifiers. |
| `url` | string | Canonical expose URL. |
| `operation` | string | `RENT` or `BUY`. |
| `title` | string or null | Public listing title. |
| `price` | number or null | Asking price in EUR. |
| `priceCurrency` | string | Usually EUR. |
| `priceFormatted` | string or null | Localized price label from the SERP card. |
| `rooms` | number or null | Room count when published. |
| `livingSpaceSqm` | number or null | Living space in square metres. |
| `address` / `city` / `zipCode` | string or null | Location fields when published. |
| `agencyName` / `agencyPhone` | string or null | Publisher contact when shown on the SERP card. |
| `imageUrls` | array | Gallery image URLs when present. |
| `scrapedAt` | string | Collection timestamp for the row. |

Illustrative JSON record:

```json
{
  "listingId": "264C9FHP3E4H",
  "url": "https://www.immowelt.de/expose/5ea9bbf0-2214-4886-adca-4b54a78b77c6",
  "operation": "RENT",
  "title": "Wohnung zur Miete auf Zeit - Erstbezug",
  "price": 1799,
  "priceCurrency": "EUR",
  "priceFormatted": "1.799 €/Monat",
  "rooms": 3,
  "livingSpaceSqm": 87.66,
  "city": "Lichtenberg",
  "zipCode": "10315",
  "agencyName": "STRATEGIS AG",
  "agencyPhone": "030 44353300",
  "source": "immowelt",
  "scrapedAt": "2026-09-17T12:00:00.000Z"
}
```

### How it works

The Actor builds `/liste/{city}/{estate}/{mieten|kaufen}` from `location`, or uses pasted Immowelt search URLs. It fetches the HTML over HTTP, decompresses the SSR `__UFRN_FETCHER__` lz-string blob for `classified-serp-init-data`, and flattens about 30 listing cards per URL. Client-side price, room, and space filters trim that page. Terminal runs write `OUTPUT` and `RUN_SUMMARY` with an explicit outcome such as `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, or `INVALID_INPUT`. v1 focuses on SERP card fields from the Immowelt search page; detail-page enrichment can be added later when a stable expose path is available.

### Pricing

This Actor uses Apify Pay per event plus standard Apify platform usage (passed through to the caller). Charged events:

- Actor start — $0.00005
- Property scraped — $0.004 per returned listing

Open the live Pricing tab in the Apify Console for the current source of truth. A run that returns ten listings charges the start event once and the property-scraped event ten times, plus platform usage for compute and proxy.

### Use with AI agents (MCP)

This Actor is available through Apify MCP as `apify--immowelt-all-in-one-scraper`. Exact Actor identity: `khadinakbar/immowelt-all-in-one-scraper`.

Tool shape: resolve a German city or Immowelt URL, return flat listing rows with price, rooms, m², agency phone, and URL for CRM or agent reasoning.

> Search Immowelt for apartments for rent in Berlin, return price, rooms, livingSpaceSqm, city, agencyPhone, and url for each listing. Cap at 10 rows and summarize cold-rent ranges.

Agent readback guidance:

- Dataset rows are the primary result store
- `OUTPUT` / `RUN_SUMMARY` carry the run outcome and counts
- `url` plus `scrapedAt` keep provenance inspectable
- `maxItems` bounds both yield and PPE charges
- Cost maps one returned row to one `property-scraped` event; check the Pricing tab for live amounts alongside platform usage
- Immowelt SSR returns about 30 cards per URL — pass multiple district URLs when you need broader city coverage

### Apify API example

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor("khadinakbar/immowelt-all-in-one-scraper").call({
  location: "München",
  operation: "buy",
  estateType: "apartment",
  maxItems: 10
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Best results and outcome guidance

Prefer Apify Residential Germany when datacenter requests hit DataDome. Segment large cities by district URL instead of one oversized `maxItems`. Paste a ready-made Immowelt `/liste` URL when filters are already set on the site. Client-side price and room filters refine the SSR page cards that Immowelt already returned. Unknown or retired location slugs finish with a clear `VALID_EMPTY` outcome and zero property charges.

### Design note

While probing Immowelt, I learned the search HTML already embeds the listing cards inside an lz-string SSR blob (`classified-serp-init-data`), so Cheerio can return price, rooms, m², and agency phone without opening each expose page. City aliases such as Frankfurt → `frankfurt-am-main` keep location mode aligned with Immowelt's live slugs; when a slug is retired, the Actor records a clear `VALID_EMPTY` outcome so callers can retry with a district URL instead of treating it as a transport outage.

### FAQ

**How do I scrape purchases instead of rentals?**\
Set `operation` to `buy`, or paste a `/kaufen` search URL into `startUrls`.

**How do I get more than 30 listings in Berlin?**\
Pass several district `startUrls` (for example `berlin-mitte`, `berlin-charlottenburg`) and raise `maxItems`.

**How do I keep agency outreach fields?**\
Use the default SERP path; `agencyName` and `agencyPhone` are returned when Immowelt publishes them on the card.

**How do I bound cost?**\
Set `maxItems` to the number of listings you need; each accepted row maps to one property-scraped event.

### Responsible use

This Actor collects public listing fields from Immowelt.de. Callers are responsible for complying with Immowelt / AVIV terms, German and EU law, and their own data-protection obligations. Keep request volume appropriate to the research scope, and review agency contact fields before any outreach automation.

Immowelt and Immowelt.de are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by Immowelt or AVIV Germany.

# Changelog

This Actor's version history is a separate document: https://apify.com/khadinakbar/immowelt-all-in-one-scraper/changelog.md

# Actor input Schema

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

Immowelt search URLs to scrape. Supports /liste/{city}/{wohnungen|haeuser|…}/{mieten|kaufen} and /suche/{mieten|kaufen}/… paths. Auto-paginated SSR first page (~30 cards) per URL. For broader coverage, paste multiple district URLs (e.g. berlin-mitte, berlin-charlottenburg). Detail /expose URLs are detected but skipped in v1 (DataDome). Non-immowelt.de hosts are rejected.

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

German city or district used when startUrls is empty. Slugified into an Immowelt /liste URL (e.g. Berlin → berlin, München → muenchen, Berlin-Mitte → berlin-mitte). Prefer district slugs for large cities when you need more than one SSR page of results.

## `operation` (type: `string`):

Buy or rent when building a search from location. Ignored when startUrls already encode mieten/kaufen. Defaults to rent.

## `estateType` (type: `string`):

Property type when building a search from location. Maps to Immowelt path segments (wohnungen, haeuser, grundstuecke, gewerbe, garagen). Ignored when startUrls already encode the estate type.

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

Client-side minimum price filter in EUR applied after the SSR page is parsed. Does not change Immowelt's server ranking. Leave empty for no minimum.

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

Client-side maximum price filter in EUR applied after the SSR page is parsed. Leave empty for no maximum.

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

Client-side minimum room count filter (Zimmer). Leave empty for any.

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

Client-side maximum room count filter (Zimmer). Leave empty for any.

## `minSpace` (type: `integer`):

Client-side minimum living space in square meters. Leave empty for any.

## `maxSpace` (type: `integer`):

Client-side maximum living space in square meters. Leave empty for any.

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

Maximum dataset rows to return and charge. Immowelt SSR returns about 30 listings per search URL; use multiple startUrls for more. Defaults to 30. Hard cap 500.

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

Proxy settings. Immowelt search SERP pages usually work with Apify datacenter proxies. Switch to RESIDENTIAL + country DE if you see DataDome blocks.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.immowelt.de/liste/berlin/wohnungen/mieten"
    }
  ],
  "location": "Berlin",
  "operation": "rent",
  "estateType": "apartment",
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Default dataset with one Immowelt property per row.

## `OUTPUT` (type: `string`):

Terminal outcome record (COMPLETE, PARTIAL, VALID\_EMPTY, INVALID\_INPUT, UPSTREAM\_FAILED).

## `RUN_SUMMARY` (type: `string`):

Same terminal outcome as OUTPUT for agent-friendly readback.

# 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.immowelt.de/liste/berlin/wohnungen/mieten"
        }
    ],
    "location": "Berlin",
    "operation": "rent",
    "estateType": "apartment",
    "maxItems": 3,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/immowelt-all-in-one-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.immowelt.de/liste/berlin/wohnungen/mieten" }],
    "location": "Berlin",
    "operation": "rent",
    "estateType": "apartment",
    "maxItems": 3,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/immowelt-all-in-one-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.immowelt.de/liste/berlin/wohnungen/mieten"
    }
  ],
  "location": "Berlin",
  "operation": "rent",
  "estateType": "apartment",
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call khadinakbar/immowelt-all-in-one-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/immowelt-all-in-one-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/qnlGfpWLv2wAuTIcr/builds/v7sGydBizRKHoimbL/openapi.json
