# Immowelt Scraper (`automation-lab/immowelt-property-listings-agents-scraper`) Actor

Export German sale and rental listings with property details and displayed agent or agency metadata from Immowelt search URLs.

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

## Pricing

from $0.72 / 1,000 item extracteds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Immowelt Scraper

Export current German sale and rental listings from Immowelt with normalized property details and the agent or agency metadata displayed in search results.

Use this Actor for recurring inventory research, price analysis, property sourcing, or public advertiser lead qualification. Supply real Immowelt search URLs, optionally narrow the returned records with keywords and numeric filters, and receive integration-ready JSON, CSV, Excel, XML, or RSS through the Apify dataset.

### What does the Immowelt Scraper do?

The Actor reads the current server-rendered result page for each supplied `immowelt.de/suche/` URL.

For every accepted listing it can return:

- stable Immowelt and legacy listing IDs;
- canonical listing URLs and publication timestamps;
- listing headline and search-result description;
- sale or rental intent and property type;
- price, price per square meter, rooms, and floor area;
- public location fields and energy class;
- all image URLs exposed in the structured search data;
- displayed contact and agency names;
- advertiser type and private-owner flag;
- public agency profile, website, address, phone numbers, logo, and badge;
- source-search provenance and extraction timestamp.

Agent fields remain empty when Immowelt does not display them for a listing.

### Who is this Immowelt data extractor for?

#### Real-estate analysts

Take repeatable snapshots of filtered German inventory and compare price, supply, location, or property attributes in your own warehouse.

#### Buyers and acquisition teams

Collect a focused set of properties for review without copying result cards manually.

#### Agencies and lead researchers

Identify the public advertiser context attached to relevant listings, then qualify agencies using your own compliant workflow.

#### Data and automation teams

Schedule searches, export records to a spreadsheet or database, and trigger downstream jobs through Apify integrations or webhooks.

### Why use this Actor?

The extraction route consumes Immowelt's structured search payload rather than only scraping visible text fragments.

That provides richer, typed records including source IDs, timestamps, multiple images, and displayed provider metadata. The Actor also applies the same keyword, intent, property-type, and price filters to every supplied URL.

It is intentionally bounded and transparent:

- direct anonymous HTTP is the default;
- an Apify Proxy is optional, not an automatic paid fallback;
- duplicates are removed by source identity;
- malformed or unsupported URLs fail early;
- a challenged response is reported as an extraction failure;
- deep pagination and detail-page crawling are not claimed.

### What Immowelt data can you extract?

| Group | Fields |
| --- | --- |
| Identity | `listingId`, `legacyId`, `listingUrl`, `status` |
| Property | `title`, `description`, `intent`, `propertyType` |
| Price | `price`, `priceFormatted`, `pricePerSquareMeter`, `currency` |
| Attributes | `rooms`, `livingAreaSquareMeters`, `plotAreaSquareMeters`, `floor`, `energyClass` |
| Location | `country`, `city`, `district`, `postcode`, `street`, `addressPublished` |
| Media | `imageUrls` |
| Dates | `createdAt`, `updatedAt`, `scrapedAt` |
| Agent | `agentName`, `agencyName`, `advertiserType`, `isPrivateOwner` |
| Agency | `agencyProfileUrl`, `agencyWebsite`, `agencyAddress`, `agencyPhoneNumbers`, `agencyLogoUrl`, `agencyBadge` |
| Provenance | `sourceSearchUrl`, `sourceSearchLocation`, `sourceResultCount` |

Fields are returned only when they are publicly exposed in the current search payload.

### How to scrape Immowelt property listings

1. Open Immowelt and build a German sale or rental search with the filters you need.
2. Copy the resulting URL under `https://www.immowelt.de/suche/`.
3. Add it to **Immowelt search URLs**.
4. Optionally add more URLs for other locations or property segments.
5. Set `maxItems` and optional keyword, intent, property-type, or price filters.
6. Run the Actor.
7. Open the **Results** dataset and export or integrate the records.

Start with five to ten items. Increase the limit only after confirming the supplied searches produce the expected segment.

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | required | One to ten current public Immowelt search URLs. |
| `keywords` | string array | `[]` | Keep records containing every keyword in property, location, agent, or agency text. |
| `intent` | string | `any` | Keep `buy`, `rent`, or both listing intents. |
| `propertyTypes` | string array | all | Keep selected normalized property types. |
| `minPrice` | integer | none | Minimum displayed price in euros. |
| `maxPrice` | integer | none | Maximum displayed price in euros. |
| `maxItems` | integer | `30` | Save at most 1–300 unique listings. |
| `proxyConfiguration` | object | direct | Optional Apify Proxy configuration for challenged traffic. |

Example input:

```json
{
  "startUrls": [
    {
      "url": "https://www.immowelt.de/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634"
    }
  ],
  "intent": "buy",
  "maxPrice": 500000,
  "maxItems": 10
}
```

### Output example

Each default-dataset item represents one unique property listing.

```json
{
  "listingId": "25ABC12DEF34",
  "legacyId": "12345678-abcd-4321-abcd-1234567890ab",
  "listingUrl": "https://www.immowelt.de/expose/12345678-abcd-4321-abcd-1234567890ab",
  "title": "Bright two-room apartment near the city center",
  "intent": "buy",
  "propertyType": "apartment",
  "price": 320000,
  "priceFormatted": "320.000 €",
  "pricePerSquareMeter": 5333.33,
  "currency": "EUR",
  "rooms": 2,
  "livingAreaSquareMeters": 60,
  "city": "Berlin",
  "district": "Mitte",
  "postcode": "10115",
  "imageUrls": [
    "https://mms.immowelt.de/a/b/c/d/example-image.jpg"
  ],
  "agentName": "Example Contact",
  "agencyName": "Example Property Agency",
  "advertiserType": "AGENCY",
  "agencyProfileUrl": "https://www.immowelt.de/profil/example-agency",
  "agencyPhoneNumbers": ["030 1234567"],
  "sourceSearchLocation": "Berlin",
  "sourceResultCount": 1200,
  "scrapedAt": "2025-02-01T10:00:00.000Z"
}
```

### How much does it cost to extract Immowelt property listings?

This Actor uses pay-per-event pricing:

- **Run started:** $0.005 once per run.
- **Item extracted:** a tiered property-listing price that starts at $0.00138 on the FREE tier and decreases on higher Apify tiers.

On the FREE tier, calculate the Actor charge as the $0.005 run-start event plus one $0.00138 item event for each saved listing. For example, a ten-listing run records one start event and ten item events; a 100-listing run records one start event and 100 item events. Higher Apify tiers use lower per-item prices.

Only unique records written to the dataset receive an item charge. Filtered, duplicate, empty, or failed records do not. Optional proxy transfer and platform compute are separate Apify usage costs and can vary by configuration.

### Recurring monitoring workflows

A dataset is a snapshot from one run. To monitor changes:

1. save the Actor as an Apify Task;
2. schedule it daily, weekly, or at another suitable interval;
3. keep stable source URLs and filters;
4. compare `listingId`, `price`, `status`, `createdAt`, and `updatedAt` between runs;
5. notify your team or update your warehouse through a webhook.

The Actor does not maintain cross-run history or send alerts itself. Apify schedules, webhooks, and your downstream storage provide that workflow.

### Export and integration patterns

From the dataset you can:

- download JSON, CSV, Excel, XML, or RSS;
- connect Google Sheets through an Apify integration;
- send completed-run webhooks to Make, Zapier, or your application;
- pull records into a BI tool or data warehouse;
- trigger another Actor for compliant enrichment or analysis;
- preserve repeated snapshots for inventory and price-change reporting.

Use `listingId` or `legacyId` as the primary deduplication key in downstream systems.

### Run through the Apify API with cURL

Replace `APIFY_TOKEN` with a token stored in your environment.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~immowelt-property-listings-agents-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{
      "url": "https://www.immowelt.de/suche/mieten/wohnung/berlin/berlin-10115/ad08de8634"
    }],
    "intent": "rent",
    "maxItems": 10
  }'
```

Use the returned run ID to inspect status and retrieve the default dataset.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor(
  'automation-lab/immowelt-property-listings-agents-scraper'
).call({
  startUrls: [{
    url: 'https://www.immowelt.de/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634',
  }],
  intent: 'buy',
  maxItems: 10,
});

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

Install the client with `npm install apify-client`.

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor(
    'automation-lab/immowelt-property-listings-agents-scraper'
).call(run_input={
    'startUrls': [{
        'url': 'https://www.immowelt.de/suche/kaufen/haus/berlin/berlin-10115/ad08de8634'
    }],
    'intent': 'buy',
    'maxItems': 10,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

Install the client with `pip install apify-client`.

### Use the Actor through MCP

Add the Apify MCP server to Claude Code:

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

#### Claude Desktop setup

Add this JSON to the Claude Desktop MCP configuration:

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

#### Cursor setup

Open **Cursor Settings → MCP**, add a server named `apify`, and use the same Actor-specific URL shown above.

#### VS Code setup

Open the MCP server configuration in VS Code, add an HTTP server named `apify`, and use the same Actor-specific URL shown above.

Example prompts:

- “Run the Immowelt scraper for this Berlin rental search and return five listings.”
- “Extract sale listings below €500,000 and summarize price per square meter.”
- “Collect displayed agencies from these Immowelt search URLs and group listings by agency.”

### Limits and troubleshooting

#### Current-page coverage

Each supplied search URL contributes the current server-rendered result page, normally up to 30 source cards. The Actor does not claim deep pagination. For broader coverage, create multiple narrower Immowelt searches by location, intent, price, or property type.

#### Germany-only search URLs

The supported source is `immowelt.de`. Immowelt Austria, `immowelt.at`, and unrelated domains are not accepted.

#### No detail-page enrichment

Direct expose/detail pages are not fetched. Output is limited to data displayed in Immowelt's structured search response, which already includes many property and provider fields.

#### Challenged traffic

If all supplied URLs fail with a structured-payload error, verify that the URLs still open as public searches. You can then configure an Apify Proxy, preferably with German geography. The Actor does not silently activate residential traffic.

#### Empty output

A successful run with zero rows means the search page loaded but no current card matched every optional filter. Remove or relax `keywords`, price bounds, intent, or property-type filters.

### Responsible use and legality

This Actor extracts information publicly displayed by Immowelt. You are responsible for your use of the data and for complying with applicable laws, Immowelt terms, database rights, privacy rules, and marketing regulations.

Do not use public contact metadata for spam, harassment, discrimination, or unlawful profiling. Collect only what you need, protect exported data, respect deletion requests, and apply an appropriate retention policy. Public display does not remove every legal obligation.

This documentation is not legal advice.

### Frequently asked questions

#### Does this provide an unofficial Immowelt API?

It provides structured Actor input and dataset output suitable for API automation. It is not affiliated with Immowelt and does not expose a private or official Immowelt API.

#### Can it scrape both properties for sale and rent?

Yes. Supply current sale and rental search URLs. Use `intent` to enforce the same scope across every URL.

#### Does it return agent phone numbers?

It returns phone numbers only when they are present in the public provider metadata attached to the current search result. Some listings expose no phone number or agency.

#### Can it scrape every result in a large city?

Not from one URL. The bounded route reads the current server-rendered page. Split a large market into narrower searches when you need broader inventory coverage.

#### Why did my URL fail validation?

Only HTTPS Immowelt search URLs under `/suche/` are accepted. Listing detail URLs, profile URLs, non-Immowelt domains, and other paths fail closed.

#### Why are some fields missing?

Immowelt controls which fields are displayed per listing. Private or undisclosed addresses, agents, phones, badges, websites, plot areas, and energy classes remain absent rather than being guessed.

### Related automation-lab Actors

- [Immowelt Search Results Scraper](https://apify.com/automation-lab/immowelt-search-results-scraper) — a lighter listing-card extractor when you do not need the richer structured provider output.
- [ImmoScout24 Property Listings Scraper](https://apify.com/automation-lab/immoscout24-property-scraper) — collect comparable German sale and rental inventory from another public property portal.
- [Immoweb Belgium Property Listings Scraper](https://apify.com/automation-lab/immoweb-belgium-property-listings-scraper) — export Belgian property listing records for cross-market workflows.

### Support

If a current public search stops producing records, include the Actor run URL, a sanitized input, the expected search segment, and the observed behavior in your report. Do not paste Apify tokens or other credentials.

# Actor input Schema

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

One to ten public URLs under https://www.immowelt.de/suche/. Filters encoded in each URL are preserved.

## `keywords` (type: `array`):

Case-insensitive words or phrases matched against title, description, location, agent, and agency fields on every supplied URL.

## `intent` (type: `string`):

Keep sale listings, rental listings, or both. This filter is also applied when a supplied URL has a broader scope.

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

Optional Immowelt property types to keep.

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

Exclude listings below this displayed price in euros.

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

Exclude listings above this displayed price in euros.

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

Stop after saving this many unique listings across all supplied search URLs.

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

Optional Apify Proxy settings. Direct anonymous HTTP is the default; choose a German proxy only if Immowelt challenges your traffic.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.immowelt.de/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634"
    }
  ],
  "keywords": [],
  "intent": "any",
  "maxItems": 10
}
```

# Actor output Schema

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

Unique Immowelt property listings extracted during this run.

# 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/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/immowelt-property-listings-agents-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/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634" }],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/immowelt-property-listings-agents-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/suche/kaufen/wohnung/berlin/berlin-10115/ad08de8634"
    }
  ],
  "maxItems": 10
}' |
apify call automation-lab/immowelt-property-listings-agents-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/immowelt-property-listings-agents-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/JVb6nRQDXbnJwhsVW/builds/8QXqaO8Qla61gDMzP/openapi.json
