# Wohnungsbörse Scraper — Germany Property Data & API (`sian.agency/wohnungsboerse-property-scraper`) Actor

Wohnungsbörse scraper & real estate data API for wohnungsboerse.net. Rent & sale listings in every German city: price, size, rooms, deposit, floor, address, GPS, energy, photos — clean JSON/CSV. Fast overview or full detail. No-code, no API key needed.

- **URL**: https://apify.com/sian.agency/wohnungsboerse-property-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Real estate, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 60.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 overview listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Wohnungsbörse Scraper — Germany Property Data & API 🏠

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Idealista Scraper](https://img.shields.io/badge/Store-Idealista%20Scraper-E60023)](https://apify.com/sian.agency/smart-idealista-scraper?fpr=sian) [![Immobiliare.it Scraper](https://img.shields.io/badge/Store-Immobiliare.it%20Scraper-00A599)](https://apify.com/sian.agency/immobiliare-property-scraper?fpr=sian) [![Zoopla Scraper](https://img.shields.io/badge/Store-Zoopla%20Scraper-8046F1)](https://apify.com/sian.agency/zoopla-property-scraper?fpr=sian)

#### 🎉 Every German rent & sale listing as clean JSON — price, size, rooms, deposit, energy, GPS & photos
##### For market analysts, real-estate agents, investors and proptech teams who need wohnungsboerse.net data without copy-paste

---

### 📋 Overview

**Pull live German real-estate listings from wohnungsboerse.net into a clean, structured dataset** — built for analysts, agents, investors and developers who need property data at scale, not screenshots.

**Why professionals choose this scraper:**
- ✅ **Whole-of-Germany coverage**: rent (Miete) and sale (Kauf) listings in any city — Berlin, München, Frankfurt, Hamburg, Köln and beyond
- ⚡ **Two speeds**: a fast, cheap overview scrape for sizing a market, or full detail pages when you need everything
- 🎯 **38 structured fields**: price, price per m², area, rooms, deposit, extra costs, energy class, GPS, district, photos and more
- 💰 **Pay per result**: only charged for the listings you actually get — transparent, no subscription
- 💎 **No account, no API key**: paste a city or a search URL and run
- ✨ **Bonus KPIs**: automatic price-per-m² and thumbnail-first rows, ready for analysis

---

### ✨ Features

- 🏙️ **Search by city**: give one or more German city names and a contract type
- 🔗 **Search by URL**: paste any wohnungsboerse.net search URL — every filter you set is preserved
- 🆔 **Fetch by listing**: pass specific listing URLs or IDs for targeted detail extraction
- 📋 **Overview mode**: high-volume, low-cost card harvesting from the result list
- 🔎 **Detail mode**: deposit, Nebenkosten, energy info, floor, construction year, full description and every photo
- 📐 **Computed metrics**: price-per-m² added automatically to every row
- 🌐 **Geo data**: latitude/longitude for mapping and territory analysis
- 📤 **Export anywhere**: JSON, CSV, Excel straight from the Apify dataset

---

### 🎬 Quick Start

Pick a scrape mode, give it a city (or a search URL), and run. Results land in the dataset as structured rows you can export or pipe into your stack.

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~wohnungsboerse-property-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"scrapeMode":"overview","searchMode":"byCity","cities":["Frankfurt"],"contract":"rent","maxResults":50}'
````

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose your data depth

Pick **overview** (fast card list) or **detail** (full listing pages).

#### Step 2: Tell it what to scrape

Enter one or more **cities** + a **contract** (rent/sale), or paste a **search URL**.

#### Step 3: Run and export

Start the actor and download the dataset as JSON, CSV or Excel.

**That's it! In a couple of minutes, you'll have:**

- A clean table of German property listings
- Prices, sizes, rooms, deposits, energy and GPS
- Direct links and photos for every listing

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scrapeMode | string | No | `overview` (card list) or `detail` (full pages) |
| searchMode | string | No | `byCity`, `bySearchUrl`, or `byListingUrl` |
| cities | array | No | German city names, e.g. `["Frankfurt"]` |
| contract | string | No | `rent` (Miete) or `sale` (Kauf) |
| estateType | string | No | `1` = apartment (Wohnung), `2` = house (Haus) |
| searchUrls | array | No | wohnungsboerse.net search URLs to scrape |
| listingUrls | array | No | Specific listing URLs or IDs (detail mode) |
| maxResults | integer | No | Max listings per run |
| commissionFree | boolean | No | Only commission-free listings |
| privateOnly | boolean | No | Only private sellers (no agents) |
| sort | string | No | `estates.rent_cold` (price) or `estates.size` (area) |
| direction | string | No | `ASC` or `DESC` |

**Example — by city:**

```json
{
  "scrapeMode": "overview",
  "searchMode": "byCity",
  "cities": ["Berlin", "München"],
  "contract": "rent",
  "maxResults": 100
}
```

**Example — by search URL:**

```json
{
  "scrapeMode": "detail",
  "searchMode": "bySearchUrl",
  "searchUrls": ["https://www.wohnungsboerse.net/searches/index?marketing_type=miete&estate_types[0]=1&cities[0]=Frankfurt"]
}
```

***

### 📤 Output

Results are saved to the Apify dataset with **38+ fields** including:

| Field | Type | Description |
|-------|------|-------------|
| id | string | wohnungsboerse listing id |
| url | string | Listing detail page URL |
| propertyTitle | string | Listing headline |
| contract | string | rent or sale |
| property\_type | string | Apartment / Wohnung / Haus |
| price | integer | Kaltmiete (rent) or Kaufpreis (sale), EUR |
| price\_per\_sqm\_eur | integer | Computed price per m² |
| area\_sqm | number | Living area in m² |
| rooms | number | Number of rooms |
| deposit | integer | Kaution (deposit) |
| extra\_costs | integer | Nebenkosten |
| city / district / zip | string | Location |
| latitude / longitude | number | GPS coordinates |
| energy\_class | string | Energy efficiency class |
| images | array | All photo URLs |

**Example:**

```json
{
  "id": "40066766",
  "url": "https://www.wohnungsboerse.net/immodetail/40066766",
  "propertyTitle": "Modernes Apartment nahe Campus Westend",
  "contract": "rent",
  "property_type": "Apartment",
  "price": 245,
  "currency": "EUR",
  "price_per_sqm_eur": 13,
  "area_sqm": 19,
  "rooms": 1,
  "deposit": 750,
  "city": "Frankfurt",
  "district": "Nordend-West",
  "zip": "60322",
  "latitude": 50.1321397,
  "longitude": 8.6783627,
  "construction_year": 2024,
  "is_private": true,
  "image_count": 9
}
```

***

### 💼 Use Cases & Examples

#### 1. Rental Market Analysis

**Analysts tracking rent levels and supply across German cities.**

**Input:** Several cities + `contract: rent`
**Output:** Prices, price-per-m², area and district for every listing
**Use:** Build rent indices, spot under- and over-priced submarkets.

#### 2. Real-Estate Lead Generation

**Agents sourcing private (no-agent) listings to win mandates.**

**Input:** `privateOnly: true` + target cities
**Output:** Private listings with location and contact context
**Use:** Prioritize fresh owner-listed properties.

#### 3. Investment Sourcing

**Investors screening for yield by price-per-m².**

**Input:** `contract: sale`, sort by price
**Output:** Sale listings with computed €/m² and size
**Use:** Filter to undervalued opportunities fast.

#### 4. Relocation & Tenant Search

**Teams helping employees relocate to a new German city.**

**Input:** City + room/area filters via search URL
**Output:** Matching apartments with photos and GPS
**Use:** Shortlist homes before viewings.

#### 5. Proptech Data Feeds

**Developers powering an app or model with live listing data.**

**Input:** Scheduled runs per city
**Output:** Structured JSON ready for a database or pipeline
**Use:** Keep an always-fresh German listings feed.

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/wohnungsboerse-property-scraper').call({
  scrapeMode: 'overview',
  searchMode: 'byCity',
  cities: ['Frankfurt'],
  contract: 'rent',
});

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

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/wohnungsboerse-property-scraper').call(
    run_input={'scrapeMode': 'overview', 'searchMode': 'byCity', 'cities': ['Frankfurt'], 'contract': 'rent'}
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~wohnungsboerse-property-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"scrapeMode":"overview","searchMode":"byCity","cities":["Frankfurt"],"contract":"rent"}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: Schedule or webhook
2. **HTTP Request**: Call the actor API
3. **Process**: Handle the JSON results
4. **Action**: Save to a sheet, CRM or database

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 listings** per run — full feature access, same quality
- No credit card required
- Perfect for testing and small projects

#### PAID Tier (Production Ready)

- **Unlimited** listings per run
- Faster, uninterrupted runs
- Pay-per-result: only charged for listings actually extracted

💰 **Pay-per-result pricing** — the cheap overview event drives high-volume runs; detail is priced for full-page enrichment.

🔗 [View current pricing](https://apify.com/sian.agency/wohnungsboerse-property-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: How many listings can I scrape?**
A: FREE tier: 25 per run. PAID tier: unlimited.

**Q: Can I scrape by my own filters?**
A: Yes — set filters on wohnungsboerse.net, copy the search URL, and use `bySearchUrl`.

**Q: What's the difference between overview and detail?**
A: Overview is the fast, cheap card list. Detail opens each listing for deposit, energy, GPS, description and all photos.

**Q: What output formats are available?**
A: JSON, CSV and Excel — export directly from the Apify dataset.

**Q: Do I need a wohnungsboerse.net account or API key?**
A: No. Just provide a city or a search URL.

**Q: Is this legal?**
A: We only extract publicly available listing data. See the legal section below.

***

### 🐞 Troubleshooting

**No results returned**

- Check the city spelling (German names, e.g. `München`, `Köln`)
- Confirm the `contract` matches what the city has (rent vs sale)

**Fewer results than expected on FREE tier**

- The FREE tier caps at 25 listings per run — upgrade for unlimited

**A search URL returns nothing**

- Make sure it's a wohnungsboerse.net URL and still valid on the site

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

> **Trademark notice:** "Wohnungsbörse" and wohnungsboerse.net are trademarks of their respective owner. This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by wohnungsboerse.net or ImmobilienScout24. It accesses only publicly available data.

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check the [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `scrapeMode` (type: `string`):

⚡ **Choose the depth of data per listing.**

- **overview** — fast card-level scrape from the search result list (id, title, price, rooms, area, location, thumbnail). Cheapest, highest volume.
- **detail** — opens every listing's full page for richer fields (deposit, extra costs, energy, GPS, floor, construction year, description, all photos).

💡 **TIP:** Start with overview to size a market, then switch to detail for the listings you care about.

## `searchMode` (type: `string`):

🔍 **How to tell the scraper which listings to fetch.**

- **byCity** — give one or more German city names + a contract type.
- **bySearchUrl** — paste a wohnungsboerse.net search URL (all your filters preserved).
- **byListingUrl** — give specific listing URLs or IDs (detail mode only).

## `cities` (type: `array`):

📍 **CITY SEARCH:** German city names to scrape, e.g. `Frankfurt`, `Berlin`, `München`.

💡 **TIP:** Add several cities to compare markets in one run.

Used when **Search mode = byCity**.

## `contract` (type: `string`):

🏷️ **Rent or buy.** `rent` (Miete) returns rentals; `sale` (Kauf) returns properties for sale.

Used with **byCity** search.

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

🏘️ **wohnungsboerse `estate_types` id** — leave empty for all residential types (recommended).

`1` = Wohnung (apartment). For **rent**, the scraper defaults to `1` automatically (it returns the most apartment listings). For **sale**, leave empty — id `1` returns zero sale results on this site. Used with **byCity** search.

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

🔗 **SEARCH-URL MODE:** Paste wohnungsboerse.net search URLs — every filter you set on the site (price, rooms, area, commission-free, sort) is preserved.

✅ **SUPPORTED:** the canonical `/searches/index?...` URL and the pretty `/{City}/{mieten|kaufen}/{wohnungen|haeuser}` URL.

💡 **BULK EDIT:** Click "Bulk edit" to paste one URL per line.

Used when **Search mode = bySearchUrl**.

## `listingUrls` (type: `array`):

🆔 **DETAIL-BY-URL MODE:** Specific listing detail URLs (`https://www.wohnungsboerse.net/immodetail/40066766`) or bare numeric IDs (`40066766`).

💡 **BULK EDIT:** Click "Bulk edit" to paste one per line.

Used when **Search mode = byListingUrl** (requires **Scrape mode = detail**).

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

🔢 **Maximum listings per run.**

- **FREE users:** capped at 25 listings/run.
- **PAID users:** unlimited.

The scraper stops paginating once this many listings are collected.

## `commissionFree` (type: `boolean`):

✅ Only return commission-free listings (`provisionsfrei`). Applied to **byCity** searches.

## `privateOnly` (type: `boolean`):

✅ Only return listings from private sellers, no agents (`private_offer`). Applied to **byCity** searches.

## `sort` (type: `string`):

↕️ Sort the result list. `estates.rent_cold` = price, `estates.size` = area. Leave empty for site relevance. Applied to **byCity** searches.

## `direction` (type: `string`):

↕️ Ascending or descending, paired with **Sort by**.

## Actor input object example

```json
{
  "scrapeMode": "overview",
  "searchMode": "byCity",
  "cities": [
    "Frankfurt"
  ],
  "contract": "rent",
  "searchUrls": [
    "https://www.wohnungsboerse.net/searches/index?marketing_type=miete&estate_types[0]=1&cities[0]=Frankfurt"
  ],
  "listingUrls": [
    "40066766"
  ],
  "maxResults": 100,
  "commissionFree": false,
  "privateOnly": false,
  "sort": "",
  "direction": ""
}
```

# Actor output Schema

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

Scraped property listings — price, size, rooms, location, energy, photos and more.

# 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 = {
    "cities": [
        "Frankfurt"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/wohnungsboerse-property-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 = { "cities": ["Frankfurt"] }

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/wohnungsboerse-property-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "cities": [
    "Frankfurt"
  ]
}' |
apify call sian.agency/wohnungsboerse-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=sian.agency/wohnungsboerse-property-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Wohnungsbörse Scraper — Germany Property Data & API",
        "description": "Wohnungsbörse scraper & real estate data API for wohnungsboerse.net. Rent & sale listings in every German city: price, size, rooms, deposit, floor, address, GPS, energy, photos — clean JSON/CSV. Fast overview or full detail. No-code, no API key needed.",
        "version": "1.0",
        "x-build-id": "7td3aCtUfMx3YZAjK"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/sian.agency~wohnungsboerse-property-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-sian.agency-wohnungsboerse-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/sian.agency~wohnungsboerse-property-scraper/runs": {
            "post": {
                "operationId": "runs-sync-sian.agency-wohnungsboerse-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/sian.agency~wohnungsboerse-property-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-sian.agency-wohnungsboerse-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "scrapeMode": {
                        "title": "🧭 Scrape mode",
                        "enum": [
                            "overview",
                            "detail"
                        ],
                        "type": "string",
                        "description": "⚡ **Choose the depth of data per listing.**\n\n- **overview** — fast card-level scrape from the search result list (id, title, price, rooms, area, location, thumbnail). Cheapest, highest volume.\n- **detail** — opens every listing's full page for richer fields (deposit, extra costs, energy, GPS, floor, construction year, description, all photos).\n\n💡 **TIP:** Start with overview to size a market, then switch to detail for the listings you care about.",
                        "default": "overview"
                    },
                    "searchMode": {
                        "title": "🎯 Search mode",
                        "enum": [
                            "byCity",
                            "bySearchUrl",
                            "byListingUrl"
                        ],
                        "type": "string",
                        "description": "🔍 **How to tell the scraper which listings to fetch.**\n\n- **byCity** — give one or more German city names + a contract type.\n- **bySearchUrl** — paste a wohnungsboerse.net search URL (all your filters preserved).\n- **byListingUrl** — give specific listing URLs or IDs (detail mode only).",
                        "default": "byCity"
                    },
                    "cities": {
                        "title": "📍 Cities",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "📍 **CITY SEARCH:** German city names to scrape, e.g. `Frankfurt`, `Berlin`, `München`.\n\n💡 **TIP:** Add several cities to compare markets in one run.\n\nUsed when **Search mode = byCity**.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "contract": {
                        "title": "🏷️ Contract type",
                        "enum": [
                            "rent",
                            "sale"
                        ],
                        "type": "string",
                        "description": "🏷️ **Rent or buy.** `rent` (Miete) returns rentals; `sale` (Kauf) returns properties for sale.\n\nUsed with **byCity** search.",
                        "default": "rent"
                    },
                    "estateType": {
                        "title": "🏘️ Property type id (optional)",
                        "type": "string",
                        "description": "🏘️ **wohnungsboerse `estate_types` id** — leave empty for all residential types (recommended).\n\n`1` = Wohnung (apartment). For **rent**, the scraper defaults to `1` automatically (it returns the most apartment listings). For **sale**, leave empty — id `1` returns zero sale results on this site. Used with **byCity** search."
                    },
                    "searchUrls": {
                        "title": "🔗 Search URLs",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "🔗 **SEARCH-URL MODE:** Paste wohnungsboerse.net search URLs — every filter you set on the site (price, rooms, area, commission-free, sort) is preserved.\n\n✅ **SUPPORTED:** the canonical `/searches/index?...` URL and the pretty `/{City}/{mieten|kaufen}/{wohnungen|haeuser}` URL.\n\n💡 **BULK EDIT:** Click \"Bulk edit\" to paste one URL per line.\n\nUsed when **Search mode = bySearchUrl**.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "listingUrls": {
                        "title": "🆔 Listing URLs or IDs",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "🆔 **DETAIL-BY-URL MODE:** Specific listing detail URLs (`https://www.wohnungsboerse.net/immodetail/40066766`) or bare numeric IDs (`40066766`).\n\n💡 **BULK EDIT:** Click \"Bulk edit\" to paste one per line.\n\nUsed when **Search mode = byListingUrl** (requires **Scrape mode = detail**).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "🔢 Max results",
                        "minimum": 1,
                        "type": "integer",
                        "description": "🔢 **Maximum listings per run.**\n\n- **FREE users:** capped at 25 listings/run.\n- **PAID users:** unlimited.\n\nThe scraper stops paginating once this many listings are collected.",
                        "default": 100
                    },
                    "commissionFree": {
                        "title": "✅ Commission-free only",
                        "type": "boolean",
                        "description": "✅ Only return commission-free listings (`provisionsfrei`). Applied to **byCity** searches.",
                        "default": false
                    },
                    "privateOnly": {
                        "title": "✅ Private sellers only",
                        "type": "boolean",
                        "description": "✅ Only return listings from private sellers, no agents (`private_offer`). Applied to **byCity** searches.",
                        "default": false
                    },
                    "sort": {
                        "title": "↕️ Sort by",
                        "enum": [
                            "",
                            "estates.rent_cold",
                            "estates.size"
                        ],
                        "type": "string",
                        "description": "↕️ Sort the result list. `estates.rent_cold` = price, `estates.size` = area. Leave empty for site relevance. Applied to **byCity** searches.",
                        "default": ""
                    },
                    "direction": {
                        "title": "↕️ Sort direction",
                        "enum": [
                            "",
                            "ASC",
                            "DESC"
                        ],
                        "type": "string",
                        "description": "↕️ Ascending or descending, paired with **Sort by**.",
                        "default": ""
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
