# Idealista Spain Listings Monitor (`automation-lab/idealista-listings-monitor`) Actor

Extract Idealista Spain sale and rental listings with stable IDs, prices, property attributes, agency identity, and optional price and availability monitoring.

- **URL**: https://apify.com/automation-lab/idealista-listings-monitor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 77.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## How to integrate an Actor?

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

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

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

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

# README

## Idealista Spain Listings Monitor

Extract public Idealista Spain sale and rental listings into structured data, or run the same saved search repeatedly to identify new, repriced, unchanged, and removed properties.

The Actor accepts real Idealista search-result URLs, preserves the filters in each URL, follows pagination, and returns stable listing IDs, canonical URLs, prices, property attributes, agency identity, and observation timestamps. It is designed for repeatable property inventory and price-change workflows rather than contact enrichment.

### What does Idealista Spain Listings Monitor do?

Use this Actor to:

- snapshot homes for sale or rent from a filtered Idealista Spain search;
- collect stable listing IDs and canonical listing URLs;
- export prices, price per square metre, rooms, area, floor details, and descriptions;
- retain publicly displayed agency names and profile URLs;
- schedule a saved search and produce a compact change feed;
- label observations as `NEW`, `PRICE_CHANGED`, `UNCHANGED`, or `REMOVED`;
- send the resulting dataset to spreadsheets, databases, dashboards, or automations.

The Actor reads public search-result cards. It does not log in, contact advertisers, reveal phone numbers, or enrich personal contact data.

### Who is it for?

#### Property analysts

Create timestamped inventories for comparable-property research and local market analysis.

#### Real estate agencies

Watch filtered sale or rental searches for new supply, asking-price changes, and removed inventory.

#### Investors and buyer agents

Track a shortlist area or price band without manually revisiting the same Idealista search every day.

#### Data and automation teams

Feed normalized property observations into a warehouse, spreadsheet, webhook workflow, or business-intelligence dashboard.

#### Researchers

Build reproducible public listing snapshots while retaining each observation's source URL and timestamp.

### Why use this Actor?

- **Search filters stay under your control.** Build a search on Idealista and pass its URL directly.
- **Stable source identity.** Each result contains Idealista's listing ID and canonical URL.
- **Monitoring is built in.** A namespaced state key keeps independent saved searches separate.
- **Compact change feeds.** Suppress unchanged records when only changes matter.
- **Bounded execution.** `maxItems` and `maxPages` provide explicit safety limits.
- **Typed output.** Dataset fields are ready for JSON, CSV, Excel, API, and database integrations.
- **Source-specific access.** Requests use Spain-targeted residential routing and browser-like TLS without downloading a full browser page stack.

### What Idealista data can I extract?

| Field | Meaning |
|---|---|
| `listingId` | Stable Idealista listing identifier |
| `url` | Canonical public property URL |
| `title` | Search-result headline |
| `price` | Current asking sale price or monthly rent |
| `currency` | `EUR` |
| `pricePerSquareMeter` | Displayed euros per square metre, when available |
| `rooms` | Displayed room/bedroom count |
| `areaSquareMeters` | Advertised floor area |
| `floor` | Floor, orientation, lift, or related summary |
| `description` | Public search-result description excerpt |
| `agencyName` | Publicly displayed agency name, when available |
| `agencyUrl` | Public Idealista agency profile URL, when available |
| `imageUrl` | Primary image URL shown in the result card |
| `isProfessional` | Whether Idealista marks the advertiser as professional |
| `sourceSearchUrl` | Original filtered search that produced the record |
| `page` | Search-result page number |
| `availability` | `ACTIVE` or `REMOVED` |
| `changeType` | `NEW`, `PRICE_CHANGED`, `UNCHANGED`, or `REMOVED` |
| `previousPrice` | Price from the prior snapshot, when available |
| `observedAt` | ISO timestamp of the observation |

Some fields are nullable because Idealista does not display every attribute on every card. A removed record preserves identity and prior price but cannot recover fields no longer present on the current page.

### How to scrape Idealista Spain listings

1. Open Idealista Spain and create a sale or rental search.
2. Apply the location, property type, price, room, and other filters you need.
3. Copy the resulting `https://www.idealista.com/...` search URL.
4. Open this Actor's **Input** tab.
5. Add the URL under **Idealista Spain search URLs**.
6. Choose conservative `maxItems` and `maxPages` limits.
7. Run the Actor.
8. Open the default dataset to preview or export the records.

Example one-time snapshot:

```json
{
  "startUrls": [
    { "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/" }
  ],
  "maxItems": 20,
  "maxPages": 1
}
```

### How to monitor Idealista prices and availability

Monitoring compares each run with the previous complete snapshot stored under your `stateKey`.

1. Set `monitoring` to `true`.
2. Choose a stable, descriptive `stateKey`.
3. Keep the same search scope for future runs using that key.
4. Schedule the Actor from Apify Console.
5. Leave `emitUnchanged` off for a compact change-only dataset.
6. Leave `emitRemoved` on if complete snapshots should detect disappearance.

```json
{
  "startUrls": [
    { "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/" }
  ],
  "maxItems": 200,
  "maxPages": 10,
  "monitoring": true,
  "stateKey": "madrid-sale-monitor",
  "emitUnchanged": false,
  "emitRemoved": true
}
```

The first run labels current listings as `NEW`. Later runs emit new and price-changed listings, plus removed records when the snapshot is complete. Enable `emitUnchanged` when you need a full observation table on every run.

Use a different `stateKey` for every distinct search. Reusing one key for unrelated locations or filters would compare different inventories.

### Input parameters

| Parameter | Type | Default | Description |
|---|---:|---:|---|
| `startUrls` | array | required | Public Idealista Spain sale or rental search-result URLs |
| `maxItems` | integer | `100` | Maximum unique output records across all supplied searches |
| `maxPages` | integer | `10` | Maximum sequential pages per search |
| `monitoring` | boolean | `false` | Save state and compare with the preceding snapshot |
| `stateKey` | string | — | Required stable namespace when monitoring is enabled |
| `emitUnchanged` | boolean | `false` | Include records whose price has not changed |
| `emitRemoved` | boolean | `true` | Emit prior listings absent from a complete current snapshot |

Supported URLs must use HTTPS on `idealista.com` or `www.idealista.com` and point to a Spain search-result route. Individual listing-detail URLs and non-Idealista hosts fail validation rather than silently changing scope.

### Output example

A dataset item has this shape:

```json
{
  "listingId": "106979106",
  "url": "https://www.idealista.com/inmueble/106979106/",
  "title": "Piso en venta en Madrid",
  "price": 425000,
  "currency": "EUR",
  "pricePerSquareMeter": 5312,
  "rooms": 3,
  "areaSquareMeters": 80,
  "floor": "2ª planta exterior con ascensor",
  "description": "Vivienda luminosa cerca del transporte público.",
  "agencyName": "Agencia inmobiliaria",
  "agencyUrl": null,
  "imageUrl": "https://img4.idealista.com/blur/WEB_LISTING/0/id.pro.es.image.master/example.jpg",
  "isProfessional": true,
  "sourceSearchUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
  "page": 1,
  "availability": "ACTIVE",
  "changeType": "PRICE_CHANGED",
  "previousPrice": 435000,
  "observedAt": "2026-01-15T12:00:00.000Z"
}
```

The example illustrates the contract; values vary with live public search results. Use `listingId` as the primary source key and `observedAt` as the snapshot timestamp.

### How much does it cost to monitor Idealista listings?

The Actor uses pay-per-event pricing:

- a one-time **Start** event for each run;
- an **Item processed** event for each record written to the dataset.

The Start event is **$0.001 per run**. Item prices decrease by Apify subscription tier: FREE $0.0004784, BRONZE $0.000416, SILVER $0.00032448, GOLD $0.0002496, PLATINUM $0.0001664, and DIAMOND $0.00011648 per output record. Active prices are also shown in Apify Console before every run. Proxy and compute consumption are covered by event pricing; you do not configure a separate proxy input.

For planning, total event cost is:

```text
run cost = $0.001 + (dataset records × applicable item price)
```

At the BRONZE tier, 1 record costs about **$0.001416**, 10 records cost about **$0.00516**, and 100 records cost about **$0.04260**. A change-only monitoring run can cost less than a full snapshot because unchanged listings are not written or billed as dataset items. The live Console pricing panel remains authoritative.

### Pagination, limits, and removed listings

The Actor follows Idealista's own next-page link sequentially and deduplicates by `listingId`.

`maxItems` limits output records across all searches. `maxPages` limits each supplied search independently.

Removed-listing detection is intentionally conservative. If `maxItems` or `maxPages` truncates a snapshot while more search results remain, the Actor skips removals and logs a warning. This avoids incorrectly labeling unvisited properties as removed.

For reliable availability monitoring:

- use limits large enough to cover the complete saved search;
- avoid changing a search's filters while keeping the same state key;
- inspect truncation warnings;
- schedule at a cadence appropriate for your analysis.

### Schedule and integrate recurring monitoring

In Apify Console, create a task from your tested input and attach a schedule. Common patterns include:

- daily city inventory snapshots;
- hourly monitoring for narrow high-priority searches;
- weekly asking-price trend exports;
- change-only webhook notifications;
- dataset-to-Google-Sheets or dataset-to-database pipelines.

For downstream comparisons, upsert by `listingId` and retain `observedAt`, `price`, `availability`, and `changeType` as historical facts.

### Export Idealista data

The default Apify dataset supports:

- JSON;
- CSV;
- Excel;
- XML;
- RSS;
- API access.

Use the `overview` dataset view for the core price and monitoring columns. Use the full dataset when your integration needs all fields.

### Run through the Apify API with cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~idealista-listings-monitor/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url":"https://www.idealista.com/venta-viviendas/madrid-madrid/"}],
    "maxItems": 20,
    "maxPages": 1
  }'
```

To wait for completion and receive dataset items directly, use the synchronous dataset-items endpoint supported by the Apify API.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/idealista-listings-monitor').call({
  startUrls: [{ url: 'https://www.idealista.com/venta-viviendas/madrid-madrid/' }],
  maxItems: 20,
  maxPages: 1,
});

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

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/idealista-listings-monitor').call(run_input={
    'startUrls': [{'url': 'https://www.idealista.com/alquiler-viviendas/barcelona-barcelona/'}],
    'maxItems': 20,
    'maxPages': 1,
})

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

### Use Idealista data through MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/idealista-listings-monitor"
```

Equivalent desktop or editor configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/idealista-listings-monitor"
    }
  }
}
```

Example prompts:

- “Run my Madrid Idealista sale search for one page and summarize asking prices.”
- “Snapshot this Barcelona rental search and return listing IDs, rents, areas, and agencies.”
- “Run the saved Idealista monitor and show only new, repriced, or removed listings.”

#### Claude Desktop

Add the JSON configuration above to Claude Desktop's MCP configuration, then restart Claude Desktop.

#### Cursor

Open Cursor MCP settings, add the same HTTP server URL, and enable the `apify` server.

#### VS Code

Add the same server URL to your VS Code MCP configuration and start the server from the MCP panel.

### Tips for reliable results

- Test a new search with one page before increasing limits.
- Keep saved-search filters encoded in the supplied Idealista URL.
- Use a unique monitoring key for every inventory.
- Keep concurrency conservative; the Actor already uses bounded sequential requests.
- Do not treat a short or naturally empty filtered search as a platform failure.
- Review logs when Idealista changes its page structure or serves a challenge.
- Avoid scheduling many identical searches more frequently than your business need.

### Limitations

- Spain search-result URLs are supported; Idealista Italy and Portugal are outside this Actor's scope.
- Individual listing-detail URLs are not accepted.
- Output is limited to fields publicly present in result cards.
- Contact details, inquiry actions, login-only data, and private API access are excluded.
- Idealista can change markup or anti-bot controls without notice.
- A listing missing from a truncated snapshot is not classified as removed.
- Search results, rankings, and availability are source observations, not guaranteed ground truth.
- Historical data begins when you first enable monitoring; the Actor cannot reconstruct old snapshots.

### Troubleshooting

#### Why did my URL fail validation?

Confirm that it starts with `https://www.idealista.com/` and is a Spain sale or rental search-results URL. Property-detail pages and other domains are rejected.

#### Why were no removed records emitted?

Check the log for a truncation warning. Increase `maxItems` or `maxPages` until the entire saved search is visited, and keep the same search filters and `stateKey` between runs.

#### Why are unchanged listings missing?

`emitUnchanged` defaults to false during monitoring. Enable it when you need a complete dataset on every run.

#### Why did the run report a block?

Idealista may reject all bounded residential sessions temporarily. Retry later rather than launching many concurrent runs. Persistent failures can indicate a source-side anti-bot change.

#### Why is an attribute null?

Idealista does not show every property or agency field on every search card. Nullable output preserves honest source coverage instead of inventing values.

### Responsible and legal use

This Actor processes publicly visible listing metadata. You are responsible for ensuring that your use complies with Idealista's terms, applicable laws, database rights, privacy rules, and your contractual obligations.

Use reasonable schedules and limits. Do not use the Actor to contact, profile, harass, or discriminate against individuals. Do not republish copyrighted descriptions or images without a lawful basis. When personal data appears incidentally, apply data-minimization and retention controls appropriate to your jurisdiction.

### Related Automation Lab actors

- [Fotocasa Property Listings Scraper](https://apify.com/automation-lab/fotocasa-property-listings-scraper) — source-specific Spanish property coverage for Fotocasa.

Combining separate source-specific Actors can broaden market analysis while preserving each marketplace's stable identifiers and source URLs.

### FAQ

#### Does this Actor use the official Idealista API?

No. The official API requires private credentials. This Actor reads public Spain search-result pages through a bounded residential route.

#### Can I scrape multiple searches in one run?

Yes. Add multiple URLs to `startUrls`. The Actor deduplicates listing IDs across the run and applies the overall `maxItems` limit.

#### Can I monitor prices over time?

Yes. Enable monitoring, choose a stable state key, and schedule repeated runs. The output classifies price changes relative to the previous saved snapshot.

#### Can it detect deleted or unavailable listings?

It can emit `REMOVED` when a listing was present in the prior complete snapshot but absent from the current complete snapshot. It does not claim why the listing disappeared.

#### Does it scrape Idealista Barcelona?

Yes, for Spain search URLs such as Barcelona sale and rental searches. “Idealista Italia” and Idealista Portugal searches are not supported.

#### Are records charged if they are unchanged?

Only records written to the dataset receive an item event. In the default change-only mode, unchanged listings are observed for state comparison but are neither output nor billed as dataset items.

#### Can I use the output in Google Sheets?

Yes. Export CSV or Excel, or connect the default dataset to an Apify integration or automation workflow.

#### Is the result a live availability guarantee?

No. It is a timestamped observation of the public search results reached during that run. Retain `observedAt` and the source URL with your analysis.

# Actor input Schema

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

One or more public idealista.com Spain sale or rental result URLs. Filters already present in each URL are preserved.

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

Stop after this many unique listing or removal records across all searches.

## `maxPages` (type: `integer`):

Safety limit for sequential pagination of each supplied search URL.

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

Persist a snapshot under stateKey and label records as NEW, PRICE\_CHANGED, UNCHANGED, or REMOVED on later runs.

## `stateKey` (type: `string`):

Stable name that isolates this saved search snapshot, for example madrid-sale-under-500k. Required when monitoring is enabled.

## `emitUnchanged` (type: `boolean`):

When monitoring, also output listings whose observed price did not change. Disabled by default to produce a compact change feed.

## `emitRemoved` (type: `boolean`):

When monitoring, output listings present in the previous complete snapshot but absent now as REMOVED.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/"
    }
  ],
  "maxItems": 20,
  "maxPages": 2,
  "monitoring": false,
  "emitUnchanged": false,
  "emitRemoved": true
}
```

# Actor output Schema

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

Default dataset containing normalized Idealista listing observations.

## `state` (type: `string`):

Key-value store containing namespaced monitoring snapshots when enabled.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/"
        }
    ],
    "maxItems": 20,
    "maxPages": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/idealista-listings-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/" }],
    "maxItems": 20,
    "maxPages": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/idealista-listings-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/"
    }
  ],
  "maxItems": 20,
  "maxPages": 2
}' |
apify call automation-lab/idealista-listings-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/idealista-listings-monitor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CPXElRIBdrhAhADJr/builds/zuS9Ny4fVAQiP1cLd/openapi.json
