# Idealista Scraper (`trakk/idealista-scraper`) Actor

Scrape Idealista search results and listing detail pages from Spain, Italy, and Portugal using request-only HTTP with browser TLS impersonation. Supports pagination, optional detail enrichment, price-range splitting, search monitoring, and coverage reports.

- **URL**: https://apify.com/trakk/idealista-scraper.md
- **Developed by:** [Blynx](https://apify.com/trakk) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 results

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

## Idealista Scraper

Scrape property listings from Idealista in Spain, Italy, and Portugal. This Actor works with Idealista search URLs and individual listing URLs, extracts clean real estate data, and stores the results in an Apify dataset ready for JSON, CSV, Excel, API, or MCP workflows.

The scraper is request-only: it does not use Playwright, Puppeteer, Selenium, or a headless browser. It fetches Idealista HTML with browser TLS impersonation and parses the public page payloads directly.

### What You Can Scrape

- Search results from `idealista.com`, `idealista.it`, and `idealista.pt`
- Individual property detail pages
- Sale and rental listings
- URLs with Idealista filters already applied
- Generated search URLs from country, operation, and location slug
- Optional detail enrichment for every search result

### Key Features

- Spain, Italy, and Portugal in one Actor
- Request-only scraping with browser TLS impersonation
- Search pagination with configurable page limits
- Optional price-range splitting for broad searches
- Coverage reports showing total results, pages fetched, pushed rows, and truncation
- Optional monitoring mode for new, unchanged, price-changed, and removed listings
- Search result fields: price, size, bedrooms, advertiser, photos, multimedia flags, floor, lift, tags, and listing URL
- Detail page fields: description, address, city, province, coordinates, advertiser, features, energy information, gallery photos, and normalized amenity flags
- Residential proxy support through Apify Proxy

### Quick Start

Paste one or more Idealista search URLs:

```json
{
  "mode": "SEARCH",
  "searchUrls": [
    { "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/con-precio-hasta_400000,precio-desde_200000/" },
    { "url": "https://www.idealista.it/en/vendita-case/milano-milano/con-prezzo_400000,prezzo-min_200000/" },
    { "url": "https://www.idealista.pt/en/comprar-casas/lisboa/com-preco-max_400000,preco-min_200000/" }
  ],
  "maxPagesPerSearch": 1,
  "includeDetails": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
````

Or scrape one property detail page:

```json
{
  "mode": "DETAIL",
  "detailUrls": [
    { "url": "https://www.idealista.com/en/inmueble/108563656/" }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Input Modes

#### SEARCH

Use `SEARCH` mode when you want listings from a search or filtered results page.

```json
{
  "mode": "SEARCH",
  "searchUrls": [
    { "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/" }
  ],
  "maxPagesPerSearch": 3,
  "maxItems": 100,
  "includeDetails": false
}
```

SEARCH mode emits property rows plus one `_recordType=coverageReport` row per search URL. The coverage report helps you see whether the search was truncated by your page limit.

#### DETAIL

Use `DETAIL` mode when you already have listing URLs or listing IDs.

```json
{
  "mode": "DETAIL",
  "detailUrls": [
    { "url": "https://www.idealista.com/en/inmueble/108563656/" }
  ],
  "rawOutput": false
}
```

DETAIL mode extracts the richer data available on the property page, including description, location, gallery photos, energy fields, and normalized facts such as bathrooms, terrace, balcony, wardrobes, air conditioning, heating, garden, swimming pool, storage room, and accessibility.

### Generated URLs

You can also build search URLs from input fields instead of pasting full URLs.

```json
{
  "mode": "SEARCH",
  "country": "ES",
  "operation": "SALE",
  "locationSlug": "madrid-madrid",
  "minPrice": 200000,
  "maxPrice": 400000,
  "maxPagesPerSearch": 1
}
```

Supported countries:

- `ES` for `idealista.com`
- `IT` for `idealista.it`
- `PT` for `idealista.pt`

Supported operations:

- `SALE`
- `RENT`
- `NEW_DEVELOPMENT`

### Price-Range Splitting

For broad searches, enable `enablePriceSplitting` to split the search into price ranges and reduce truncation.

```json
{
  "mode": "SEARCH",
  "searchUrls": [
    { "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/" }
  ],
  "enablePriceSplitting": true,
  "maxPagesPerSearch": 20,
  "maxSplitDepth": 2,
  "maxItems": 0
}
```

The Actor records a coverage report for every search URL. The report includes:

- reported total results
- reported pages
- pages fetched
- rows pushed
- duplicate skips
- range count
- truncation status

If a range is still too large, the `truncated` field tells you that the current input limits did not cover the full result set.

### Monitoring Mode

Set `monitoring=true` to compare a search with previous runs stored in a named key-value store.

```json
{
  "mode": "SEARCH",
  "searchUrls": [
    { "url": "https://www.idealista.com/en/alquiler-viviendas/barcelona-barcelona/" }
  ],
  "monitoring": true,
  "monitoringStoreName": "idealista-monitoring"
}
```

Property rows can be marked as:

- `new`
- `unchanged`
- `price_changed`

When a run is not truncated, removed listings can be emitted as `_recordType=change` rows.

### Output

Each dataset item has `_recordType` so you can distinguish property rows, coverage reports, change rows, and error rows.

#### Search Result Example

```json
{
  "_recordType": "property",
  "source": "idealista",
  "propertyId": "108563656",
  "url": "https://www.idealista.com/en/inmueble/108563656/",
  "title": "Flat / apartment in Calle Simpatia, 11, El Canaveral, Madrid",
  "price": "327,000 EUR",
  "priceValue": 327000,
  "currency": "EUR",
  "sizeM2": 64,
  "bedrooms": 1,
  "advertiserName": "Soldit Homes",
  "photoCount": 13,
  "hasVideo": false,
  "has3DTour": false,
  "hasFloorPlan": true,
  "country": "ES"
}
```

#### Detail Result Example

```json
{
  "_recordType": "property",
  "source": "idealista",
  "propertyId": "108563656",
  "title": "Flat / apartment for sale in Calle Simpatia, 11",
  "price": "327,000 EUR",
  "priceValue": 327000,
  "sizeM2": 64,
  "bedrooms": 1,
  "bathrooms": 1,
  "address": "Calle Simpatia, 11",
  "city": "Madrid",
  "province": "Madrid city, Madrid",
  "advertiserName": "Soldit Homes",
  "photoCount": 13,
  "url": "https://www.idealista.com/en/inmueble/108563656/"
}
```

Fields vary by listing and by country. Idealista sometimes hides exact addresses, coordinates, or advertiser details, so those fields can be null.

### Important Fields

Common property fields include:

- `propertyId`
- `url`
- `title`
- `price`
- `priceValue`
- `currency`
- `priceByArea`
- `sizeM2`
- `bedrooms`
- `bathrooms`
- `floorText`
- `floorNumber`
- `hasLift`
- `exterior`
- `description`
- `address`
- `neighborhood`
- `district`
- `city`
- `province`
- `latitude`
- `longitude`
- `advertiserName`
- `advertiserUrl`
- `photos`
- `photoCount`
- `hasVideo`
- `has3DTour`
- `hasFloorPlan`
- `energyConsumption`
- `energyEmissions`
- `hasTerrace`
- `hasBalcony`
- `hasAirConditioning`
- `hasHeating`
- `hasGarden`
- `hasSwimmingPool`
- `hasStorageRoom`

### Pricing Notes

This Actor uses pay-per-event pricing with the dataset item as the primary event. In SEARCH mode, the Actor writes property rows and coverage report rows to the default dataset. In DETAIL mode, it writes one dataset row per processed detail URL, either a property row or an error row if the URL could not be fetched.

### Proxy and Blocking Notes

Idealista uses anti-bot protection, and cloud datacenter IPs can be challenged. Residential proxies are recommended on Apify:

```json
{
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

The Actor retries proxy errors and DataDome challenge pages. If one search URL fails and `failOnSearchError=false`, the run continues and writes an `_recordType=error` item for that URL.

### Contact Phones

`includeContactPhones` is available as an experimental option. Idealista's contact-phone AJAX endpoint is stricter than the public HTML pages and can return DataDome challenges even when listing pages load correctly. For stable production runs, keep `includeContactPhones=false`.

### Limits and Recommendations

- Start with `maxPagesPerSearch=1` for tests.
- Use `maxItems` to cap large runs.
- Use residential proxies for production runs.
- Enable `enablePriceSplitting` for very broad searches.
- Use `includeDetails=true` only when you need detail-page fields for every search result, because it adds one extra request per listing.
- Keep `failOnSearchError=false` for large batches so one blocked URL does not stop the whole run.

### FAQ

#### Does this Actor use a browser?

No. It is request-only and uses browser TLS impersonation via HTTP requests.

#### Can it scrape Spain, Italy, and Portugal?

Yes. It supports Idealista's `.com`, `.it`, and `.pt` domains.

#### Can I paste filtered Idealista URLs?

Yes. The Actor respects existing Idealista URL filters such as price ranges, sale/rent paths, and location slugs.

#### Does it always return phone numbers or emails?

No. Emails are not exposed on normal listing pages, and phone endpoints are protected more strictly. The Actor focuses on stable listing, advertiser, location, feature, and photo data.

#### Why do I see `truncated=true` in coverage reports?

It means the reported number of pages is higher than your `maxPagesPerSearch` setting. Increase the page limit or enable price splitting if you need broader coverage.

#### Why are there coverage report rows in my dataset?

Coverage reports make search runs auditable. They tell you how many results Idealista reported, how many pages were fetched, and whether the run was truncated.

# Actor input Schema

## `mode` (type: `string`):

SEARCH paginates Idealista search URLs. DETAIL scrapes individual listing pages.

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

Idealista search/listing URLs from idealista.com, idealista.it, or idealista.pt.

## `detailUrls` (type: `array`):

Individual property URLs. Used in DETAIL mode.

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

Mixed Idealista URLs. Search URLs are used in SEARCH mode; detail URLs are used in DETAIL mode.

## `listingIds` (type: `array`):

Raw Idealista listing IDs for DETAIL mode.

## `datasetId` (type: `string`):

Optional dataset with propertyId/adId/url/detailUrl fields. Used in DETAIL mode.

## `country` (type: `string`):

Used only when building search/detail URLs from locationSlug or listingIds.

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

Used only with locationSlug/locationSlugs.

## `locationSlug` (type: `string`):

Optional Idealista location slug, e.g. madrid-madrid, milano-milano, lisboa. Prefer searchUrls for exact filters.

## `locationSlugs` (type: `array`):

Optional list of location slugs for generated search URLs.

## `language` (type: `string`):

Language path used for generated URLs. Use en for English output where Idealista supports it.

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

Optional price filter. Replaces existing price filters on search URLs.

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

Optional price filter. Replaces existing price filters on search URLs.

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

Global cap on pushed property rows. Set 0 for no cap.

## `maxPagesPerSearch` (type: `integer`):

Pagination cap for each search URL or price range.

## `enablePriceSplitting` (type: `boolean`):

Split broad searches into Idealista price ranges to reduce truncation and produce a coverage report.

## `maxSplitDepth` (type: `integer`):

Recursive split depth when a price range still has more pages than maxPagesPerSearch.

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

If enabled, each search result is enriched with its detail page fields and photos.

## `includeContactPhones` (type: `boolean`):

Try Idealista's contact-phone AJAX endpoint from detail pages. This endpoint is stricter and may return a DataDome challenge.

## `rawOutput` (type: `boolean`):

Include parsed raw JS config fields in detail output.

## `monitoring` (type: `boolean`):

Compare current search results with a named key-value store and mark new/unchanged/price\_changed/removed listings.

## `monitoringStoreName` (type: `string`):

Named key-value store used for monitoring snapshots.

## `maxDetailUrls` (type: `integer`):

Optional cap for DETAIL mode URLs collected from inputs/datasets. Set 0 for no cap.

## `maxConcurrency` (type: `integer`):

Parallel detail requests.

## `maxRetries` (type: `integer`):

General retry budget per request.

## `maxProxyRetries` (type: `integer`):

Dedicated retry budget for proxy/transport failures.

## `maxBlockRetries` (type: `integer`):

Dedicated retry budget for DataDome challenge pages.

## `failOnSearchError` (type: `boolean`):

Fail the whole run when one search URL fails. Disabled by default so large URL batches can continue and store per-URL error rows.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each HTTP request.

## `impersonateProfile` (type: `string`):

curl\_cffi browser impersonation profile. Safari currently works best for Idealista HTML pages.

## `acceptLanguage` (type: `string`):

HTTP Accept-Language header.

## `proxy` (type: `object`):

Proxy configuration. Residential proxies are recommended on Apify if datacenter IPs are challenged.

## Actor input object example

```json
{
  "mode": "SEARCH",
  "searchUrls": [
    {
      "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/"
    }
  ],
  "detailUrls": [
    {
      "url": "https://www.idealista.com/en/inmueble/106387165/"
    }
  ],
  "startUrls": [],
  "listingIds": [],
  "country": "ES",
  "operation": "SALE",
  "locationSlugs": [],
  "language": "en",
  "maxItems": 100,
  "maxPagesPerSearch": 3,
  "enablePriceSplitting": false,
  "maxSplitDepth": 1,
  "includeDetails": false,
  "includeContactPhones": false,
  "rawOutput": false,
  "monitoring": false,
  "monitoringStoreName": "idealista-monitoring",
  "maxDetailUrls": 0,
  "maxConcurrency": 5,
  "maxRetries": 4,
  "maxProxyRetries": 4,
  "maxBlockRetries": 4,
  "failOnSearchError": false,
  "requestTimeoutSecs": 30,
  "impersonateProfile": "safari",
  "acceptLanguage": "en-US,en;q=0.9",
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "searchUrls": [
        {
            "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/"
        }
    ],
    "detailUrls": [
        {
            "url": "https://www.idealista.com/en/inmueble/106387165/"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("trakk/idealista-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 = {
    "searchUrls": [{ "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/" }],
    "detailUrls": [{ "url": "https://www.idealista.com/en/inmueble/106387165/" }],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("trakk/idealista-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 '{
  "searchUrls": [
    {
      "url": "https://www.idealista.com/en/venta-viviendas/madrid-madrid/"
    }
  ],
  "detailUrls": [
    {
      "url": "https://www.idealista.com/en/inmueble/106387165/"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call trakk/idealista-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Idealista Scraper",
        "description": "Scrape Idealista search results and listing detail pages from Spain, Italy, and Portugal using request-only HTTP with browser TLS impersonation. Supports pagination, optional detail enrichment, price-range splitting, search monitoring, and coverage reports.",
        "version": "0.1",
        "x-build-id": "HedGlE4VFWIYcfcRF"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/trakk~idealista-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-trakk-idealista-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/trakk~idealista-scraper/runs": {
            "post": {
                "operationId": "runs-sync-trakk-idealista-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/trakk~idealista-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-trakk-idealista-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": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "SEARCH",
                            "DETAIL"
                        ],
                        "type": "string",
                        "description": "SEARCH paginates Idealista search URLs. DETAIL scrapes individual listing pages.",
                        "default": "SEARCH"
                    },
                    "searchUrls": {
                        "title": "Search URLs",
                        "type": "array",
                        "description": "Idealista search/listing URLs from idealista.com, idealista.it, or idealista.pt.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "detailUrls": {
                        "title": "Detail URLs",
                        "type": "array",
                        "description": "Individual property URLs. Used in DETAIL mode.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Mixed Idealista URLs. Search URLs are used in SEARCH mode; detail URLs are used in DETAIL mode.",
                        "default": [],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "listingIds": {
                        "title": "Listing IDs",
                        "type": "array",
                        "description": "Raw Idealista listing IDs for DETAIL mode.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "datasetId": {
                        "title": "Input Dataset",
                        "type": "string",
                        "description": "Optional dataset with propertyId/adId/url/detailUrl fields. Used in DETAIL mode."
                    },
                    "country": {
                        "title": "Country for built URLs",
                        "enum": [
                            "ES",
                            "IT",
                            "PT"
                        ],
                        "type": "string",
                        "description": "Used only when building search/detail URLs from locationSlug or listingIds.",
                        "default": "ES"
                    },
                    "operation": {
                        "title": "Operation for built search URLs",
                        "enum": [
                            "SALE",
                            "RENT",
                            "NEW_DEVELOPMENT"
                        ],
                        "type": "string",
                        "description": "Used only with locationSlug/locationSlugs.",
                        "default": "SALE"
                    },
                    "locationSlug": {
                        "title": "Location slug",
                        "type": "string",
                        "description": "Optional Idealista location slug, e.g. madrid-madrid, milano-milano, lisboa. Prefer searchUrls for exact filters."
                    },
                    "locationSlugs": {
                        "title": "Location slugs",
                        "type": "array",
                        "description": "Optional list of location slugs for generated search URLs.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "language": {
                        "title": "Language path",
                        "type": "string",
                        "description": "Language path used for generated URLs. Use en for English output where Idealista supports it.",
                        "default": "en"
                    },
                    "minPrice": {
                        "title": "Minimum price",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Optional price filter. Replaces existing price filters on search URLs."
                    },
                    "maxPrice": {
                        "title": "Maximum price",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Optional price filter. Replaces existing price filters on search URLs."
                    },
                    "maxItems": {
                        "title": "Max items",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Global cap on pushed property rows. Set 0 for no cap.",
                        "default": 100
                    },
                    "maxPagesPerSearch": {
                        "title": "Max pages per search/range",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Pagination cap for each search URL or price range.",
                        "default": 3
                    },
                    "enablePriceSplitting": {
                        "title": "Enable price splitting",
                        "type": "boolean",
                        "description": "Split broad searches into Idealista price ranges to reduce truncation and produce a coverage report.",
                        "default": false
                    },
                    "maxSplitDepth": {
                        "title": "Max split depth",
                        "minimum": 0,
                        "maximum": 4,
                        "type": "integer",
                        "description": "Recursive split depth when a price range still has more pages than maxPagesPerSearch.",
                        "default": 1
                    },
                    "includeDetails": {
                        "title": "Fetch detail pages in SEARCH mode",
                        "type": "boolean",
                        "description": "If enabled, each search result is enriched with its detail page fields and photos.",
                        "default": false
                    },
                    "includeContactPhones": {
                        "title": "Try contact phones",
                        "type": "boolean",
                        "description": "Try Idealista's contact-phone AJAX endpoint from detail pages. This endpoint is stricter and may return a DataDome challenge.",
                        "default": false
                    },
                    "rawOutput": {
                        "title": "Include raw config snippets",
                        "type": "boolean",
                        "description": "Include parsed raw JS config fields in detail output.",
                        "default": false
                    },
                    "monitoring": {
                        "title": "Enable monitoring",
                        "type": "boolean",
                        "description": "Compare current search results with a named key-value store and mark new/unchanged/price_changed/removed listings.",
                        "default": false
                    },
                    "monitoringStoreName": {
                        "title": "Monitoring store name",
                        "type": "string",
                        "description": "Named key-value store used for monitoring snapshots.",
                        "default": "idealista-monitoring"
                    },
                    "maxDetailUrls": {
                        "title": "Max detail URLs",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Optional cap for DETAIL mode URLs collected from inputs/datasets. Set 0 for no cap.",
                        "default": 0
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Parallel detail requests.",
                        "default": 5
                    },
                    "maxRetries": {
                        "title": "Max retries",
                        "minimum": 0,
                        "maximum": 15,
                        "type": "integer",
                        "description": "General retry budget per request.",
                        "default": 4
                    },
                    "maxProxyRetries": {
                        "title": "Max proxy retries",
                        "minimum": 1,
                        "maximum": 15,
                        "type": "integer",
                        "description": "Dedicated retry budget for proxy/transport failures.",
                        "default": 4
                    },
                    "maxBlockRetries": {
                        "title": "Max DataDome retries",
                        "minimum": 1,
                        "maximum": 15,
                        "type": "integer",
                        "description": "Dedicated retry budget for DataDome challenge pages.",
                        "default": 4
                    },
                    "failOnSearchError": {
                        "title": "Fail on search error",
                        "type": "boolean",
                        "description": "Fail the whole run when one search URL fails. Disabled by default so large URL batches can continue and store per-URL error rows.",
                        "default": false
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout seconds",
                        "minimum": 5,
                        "maximum": 120,
                        "type": "integer",
                        "description": "Timeout for each HTTP request.",
                        "default": 30
                    },
                    "impersonateProfile": {
                        "title": "TLS impersonation profile",
                        "type": "string",
                        "description": "curl_cffi browser impersonation profile. Safari currently works best for Idealista HTML pages.",
                        "default": "safari"
                    },
                    "acceptLanguage": {
                        "title": "Accept-Language header",
                        "type": "string",
                        "description": "HTTP Accept-Language header.",
                        "default": "en-US,en;q=0.9"
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy configuration. Residential proxies are recommended on Apify if datacenter IPs are challenged.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
