# Immowelt Germany Property Scraper (`automatic/immowelt-scraper`) Actor

Collect property listings from immowelt.de search results for market research and listing monitoring. Search by city or postcode, rent or buy, and apartment, house or plot; alternatively supply an Immowelt search URL.

- **URL**: https://apify.com/automatic/immowelt-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/automatic) (community)
- **Categories:** Real estate
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 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.

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 Germany Property Scraper

Collect property listings from immowelt.de search results for market research and listing monitoring. Search by city or postcode, rent or buy, and apartment, house or plot; alternatively supply an Immowelt search URL. Price, rooms and living area ranges filter the returned listings.

### Usage

```json
{
  "searchUrl": "https://www.immowelt.de/suche/mieten/wohnung/berlin/berlin-10115/ad08de8634",
  "maxResults": 20
}
```

Empty input uses Berlin apartments for rent, up to 20 listings. Search URLs override location, transaction and property type; numeric ranges apply locally. Filters apply to the first 30 results of each search and cannot promise 20 matches. Location names are resolved through Immowelt redirects; for a specific locality prefer an exact search URL. Results vary with current availability.

### Output

Each row includes `listingId`, `url`, `title`, `transactionType`, `propertyType`, `price`, `currency`, `priceOnRequest`, `coldRent`, `warmRent`, `purchasePrice`, `rooms`, `livingArea`, `plotArea`, `floor`, `yearBuilt`, `energyClass`, `city`, `district`, `postcode`, `availableFrom`, `agencyName`, `images`, `postedAt` and `updatedAt`.

Amounts are EUR; `price` is the main displayed amount. Cold rent, warm rent and purchase price are kept separate when labelled by the source. Listings the source marks as price on request keep `price` and `currency` null with `priceOnRequest` true. Areas are square metres. Floor and availability retain the German source text. Dates are source creation/update timestamps and may differ from the first public posting date. Missing values are null; images is an array, empty if none are shown. Company names are limited to agency titles with an explicit corporate legal form (for example GmbH, AG or KG) to avoid exporting personal agent names. Sole traders, partnerships that trade under the owners' personal names and other unverified agency names remain null. Contact names, telephone numbers, emails and raw provider objects are excluded.

This version reads search data only. There is no `includeDetails` input and no request to expose pages. Detail-only information such as year built will often be null. Suggestions and broadened search results are excluded; only the search's main classified IDs are processed.

### Coverage and limits

Each search returns at most its first 30 listings. Deeper paging is not supported yet: listing detail pages and deeper result pages are not fetched. Use `searchUrls` (a list of SEO URLs), or `locations` (a list of cities or postcodes), to cover several searches. `searchUrls` overrides `searchUrl` and locations. Set `fanOutMax` to the number of searches to run (1 by default, at most 50). No automatic district expansion is performed: the saved search state contains room-count links, not a district or postcode list. For example, use two district SEO URLs and `fanOutMax: 2` for wider coverage. URLs must start with `https://www.immowelt.de/suche/` and have no query parameters.

Listings are deduplicated by source ID across all searches. `maxResults` caps delivery; the available first pages, filters, charge limit and deadline may stop earlier. The source client declares a 10,000-result navigation cap, but this actor only reads the first 30 per search and cannot exhaust that inventory. An empty page is requested a second time before confirming no results. A shared deadline reserves 20 seconds for finishing and bounds every request and retry delay. `Retry-After` is honoured in full; the actor finishes if it cannot fit. Delivered rows remain available when a later search is blocked or the deadline expires. An empty blocked or genuinely empty search fails with a readable status; deadline and charge-limit stops succeed even with zero rows. The status and summary identify incomplete searches. Fan-out stops on the first unavailable search.

Direct HTTP is attempted first. Optional `proxyConfiguration` enables standard Apify proxy after a block; residential fallback is disabled. It does not solve challenges. Default runs use 512 MB. Under a per-event plan the platform counts one start event at this memory size and the SDK counts one dataset-item event per unique emitted listing. Blocked, rejected, filtered and duplicate rows produce no dataset-item charges. The SDK charge limit is checked before further requests and delivery. Consult the current Store pricing.

Download the dataset in JSON, CSV or Excel. The `OUTPUT` key-value record reports delivery count, stop reason and network usage.

# Actor input Schema

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

German city name or five-digit postcode. Ignored when searchUrl is supplied. Location names are resolved through Immowelt redirects; for a specific locality prefer an exact search URL.

## `transactionType` (type: `string`):

Rent or buy. Ignored when searchUrl is supplied.

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

Property type. Ignored when searchUrl is supplied.

## `priceFrom` (type: `number`):

Inclusive price bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `priceTo` (type: `number`):

Inclusive price bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `roomsFrom` (type: `number`):

Inclusive rooms bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `roomsTo` (type: `number`):

Inclusive rooms bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `areaFrom` (type: `number`):

Inclusive area bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `areaTo` (type: `number`):

Inclusive area bound, applied to returned rows. Price is EUR; area is living area in square metres. Missing values do not match a bound.

## `searchUrl` (type: `string`):

Immowelt HTTPS SEO search URL under /suche/, without query parameters. Overrides location, transaction and property type; numeric filters remain active.

## `maxResults` (type: `integer`):

Maximum unique matching listings across all searches. Each search contributes at most its first 30; deeper paging is not supported.

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

Optional standard Apify proxy fallback after a direct block. Residential groups and custom proxy URLs are not enabled.

## `searchUrls` (type: `array`):

SEO search URLs, up to 50; overrides searchUrl and locations. Only fanOutMax searches run.

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

City names or postcodes, up to 50; used only without search URLs. Only fanOutMax searches run.

## `fanOutMax` (type: `integer`):

Maximum first-page searches to run. Default one search. Deduplicates listings across searches.

## Actor input object example

```json
{
  "location": "Berlin",
  "transactionType": "rent",
  "propertyType": "apartment",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "fanOutMax": 1
}
```

# Actor output Schema

## `dataset` (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 = {
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatic/immowelt-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 = { "maxResults": 20 }

# Run the Actor and wait for it to finish
run = client.actor("automatic/immowelt-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 '{
  "maxResults": 20
}' |
apify call automatic/immowelt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automatic/immowelt-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/zc69sHAFca3L4T2FZ/builds/wppHRYThGJox8yYGh/openapi.json
