# Idealista Scraper | Price Drops & EUR/m2 Deal Signals (`webdata_labs/idealista-price-drop-scraper`) Actor

\[💵 $0.90 / 1K - no start fee] Idealista listings for Spain, Italy and Portugal with the price cut as a real field: previous price, amount reduced and drop percent, read straight off the search page. Plus EUR/m2 per listing and how each compares with the median of your search.

- **URL**: https://apify.com/webdata\_labs/idealista-price-drop-scraper.md
- **Developed by:** [WebData Labs](https://apify.com/webdata_labs) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 listing returneds

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

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

## What's an Apify Actor?

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

## How to integrate an Actor?

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

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

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

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

# README

## Idealista Scraper - Price Drops & €/m² Deal Signals

**Every Idealista listing for Spain, Italy and Portugal, with the price cut and the €/m² gap to the local market as real columns you can sort on.**

Idealista already knows which sellers have blinked. It prints the old price and the reduction badge right on the search card, and it has a whole sort order for it. Almost every export of that data throws the signal away and hands you a flat list of asking prices, so the only way to find a motivated seller is to scrape the same city twice a week apart and diff the two files yourself. This Actor keeps the field. One run, and you know which properties were reduced, by how much, and whether the new price is actually cheap for that street or just cheaper than it used to be.

### ✅ What you get / ❌ what this isn't

| ✅ What you get | ❌ What this isn't |
|---|---|
| **Previous price, amount cut and drop percent** on every reduced listing, from a single run | Not a "run it twice and diff it yourself" export that needs two runs and a spreadsheet to find a cut |
| **€/m² per listing plus the median of your whole search**, and a `% vs median` gap | Not a raw price column that leaves you to work out whether 420,000 € is good for that district |
| **Idealista's own "biggest reductions" ordering**, so a small run is nearly all reduced stock | Not a relevance-sorted crawl of a whole city hoping a discount turns up |
| **Spain, Italy and Portugal**, each with its own verified URL, sort and pagination grammar | Not a Spanish scraper with the other two domains bolted on and quietly capped at page one |
| **Agency name and the private-owner flag** on every row | Not an anonymous listing dump you have to re-scrape to find out who to call |
| **No proxy or anti-bot setup** - the residential exit and browser are chosen for you | Not a scraper that hands you a proxy field and blames your proxies when it returns nothing |

### 🔎 Why use this Actor

- **The price cut is a field, not a diff.** Idealista renders the previous price and reduction badge server-side on reduced cards, so `previousPrice`, `priceDropAmount` and `priceDropPercent` come out of one run. The percentage is recomputed from the two prices rather than copied from Idealista's badge, which rounds to a whole number.
- **Sorted by reduction, not by relevance.** `sortBy: priceDrop` uses Idealista's own "biggest reductions" order, so the first pages are almost entirely reduced stock. A 100-row run on Madrid comes back with 100 reduced listings rather than the ~11% you get from an unsorted crawl.
- **€/m² is scored, not just printed.** Every row carries `pricePerSqm`, the `medianPricePerSqm` of everything the run collected, and `pctVsMedianPricePerSqm`, so "reduced" and "actually cheap" stay separate questions. `isBelowMarket` is the one-column answer.
- **Three countries, three grammars.** Pagination alone differs on every site: `/pagina-2.htm` in Spain, `/lista-2.htm` in Italy, `/pagina-2` in Portugal. Each country's sort parameter, filter segments and pagination were read off the live sites, so an Italian run paginates past page one instead of stopping at 30 rows.
- **Private owners are separable.** `isProfessionalAd` and `onlyPrivateOwners` split agency stock from owners selling directly.
- **You pay per listing, with no start fee.** Most Idealista Actors add a per-run charge on top of the per-result price; this one does not, so short and scheduled runs stay cheap.

### 👥 Who it's for

Buyer's agents, property investors, relocation consultants and portal/PropTech teams who need to know which asking prices are moving before the listing is gone.

- Build a weekly call list of every reduced listing in your patch, with the seller's agency attached.
- Find properties that are both reduced **and** below the local €/m² median, which is where a negotiation actually starts.
- Track how deep the discounts run in a district over time by scheduling the same search.
- Feed asking prices and €/m² into a valuation model or CMA without hand-collecting comparables.
- Pull an agency's reduced stock to see who is under pressure to close.

### Example tasks

Ready-made searches you can open, copy the input from, and adapt. Each one is a saved
configuration of this Actor, so the fastest way to start is usually to take the closest task
and change the location.

- [Find Idealista price drops in Madrid](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-price-drops-madrid) - reduced listings across the whole city, deepest cuts first.
- [Find Idealista price drops in Barcelona](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-price-drops-barcelona) - the same search on the second Spanish market.
- [Track Idealista price drops on the Costa del Sol](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-price-drops-costa-del-sol) - Malaga province, cuts of 5% or more, for second-home and expat buyers.
- [Bajadas de precio en idealista: pisos rebajados en Valencia](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-bajadas-de-precio-espana) - only listings cut by 10% or more.
- [Case con ribassi di prezzo su idealista a Milano](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-ribassi-di-prezzo-milano) - the Italian site, using its own reduction ordering.
- [Scrape Idealista apartments for rent in Lisbon](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-lisbon-apartments-for-rent) - Portuguese rentals up to 2,500 EUR a month.
- [Find Idealista properties priced below the local market](https://apify.com/webdata_labs/idealista-price-drop-scraper/examples/idealista-undervalued-properties-below-market) - sorted by EUR/m2, then scored against the median of the results.

### ⚙️ How to find reduced listings

1. Pick the **Country** (Spain, Italy or Portugal) and whether you want **sale** or **rent**.
2. Set the **Location** to the slug Idealista uses in its own URL, for example `madrid-madrid`, `barcelona-barcelona` or `milano-milano`. Open the search on Idealista and copy the part after the operation.
3. Leave **Sort results by** on **Biggest price drops** so reduced listings come first.
4. Optionally set **Only listings whose price was cut** and a **Minimum price drop (%)** to keep only the deep cuts.
5. Set **Maximum listings** (100 by default, 0 for no limit) and click **Start**.
6. Open the **Price drops** view on the run's Output tab, or export to CSV, Excel, JSON via the Export button.

#### Track a district over time

Save the run as a Task and schedule it weekly. Because the reduction is read from the listing itself rather than reconstructed from history, each run is independently complete - you do not need the previous run's file for the current run to tell you what was cut.

### 📥 Input

```json
{
  "country": "es",
  "operation": "sale",
  "location": "madrid-madrid",
  "sortBy": "priceDrop",
  "onlyPriceDrops": true,
  "minPriceDropPercent": 10,
  "maxItems": 200
}
```

- `country` - `es`, `it` or `pt`. Picks the Idealista site and its URL grammar. Default `es`.
- `operation` - `sale` or `rent`. Default `sale`.
- `location` - the location slug from an Idealista URL, e.g. `madrid-madrid`. Required unless you use `startUrls`.
- `sortBy` - `priceDrop` (default), `newest`, `cheapest`, `cheapestPerSqm`, `largest` or `relevance`. Spain and Italy only; see the caveats for Portugal.
- `onlyPriceDrops` - keep only reduced listings. Off by default so a plain run returns the whole search.
- `minPriceDropPercent` - keep only listings cut by at least this much. Optional.
- `maxItems` - stop after this many matching listings. Default 100, `0` means no limit.
- `maxPrice`, `minArea`, `maxArea` - applied by Idealista as real search filters, so they narrow the crawl rather than the export. Optional.
- `minRooms` - applied to the scraped rows. Optional.
- `onlyPrivateOwners` - drop everything marketed by an agency. Optional.
- `includeDescription` - include each card's description text. On by default.
- `startUrls` *(advanced)* - full Idealista search URLs, including any filters you set on the site. Replaces the country/location/filter fields when given.

### 📤 Output

| title | price | previousPrice | priceDropPercent | pricePerSqm | pctVsMedianPricePerSqm | url |
|---|---|---|---|---|---|---|
| Piso en Calle de la Duquesa de Parcent, Lucero, Madrid | 269100 | 518650 | 48.12 | 3636.49 | -30.26 | https://www.idealista.com/inmueble/111416830/ |
| Piso en Calle de Vallehermoso, Arapiles, Madrid | 1150000 | 1190000 | 3.36 | 7666.67 | -20.31 | https://www.idealista.com/inmueble/111395207/ |
| Bilocale in Via Francesco Predabissi, NoLo - Brianza | 249000 | 448800 | 44.54 | 4698.11 | 22.22 | https://www.idealista.it/immobile/28110693/ |

Each row also carries `id`, `currency`, `hasPriceDrop` and `priceDropAmount`; the property itself as `propertyType`, `rooms`, `areaSqm`, `floor`, `isExterior`, `hasLift` and `hasGarage`; location as `street`, `district`, `city` and the raw `locationText` from the listing title; the seller as `agencyName`, `agencyUrl` and `isProfessionalAd`; `medianPricePerSqm` and `isBelowMarket` for the market comparison; and `description`, `thumbnailUrl`, `photoCount`, `searchUrl`, `country`, `operation` and `scrapedAt` for context and provenance.

### 💵 How much does it cost?

You pay **$0.90 per 1,000 listings** on the free tier, falling to $0.60 per 1,000 on the Business plan, and there is **no actor-start fee** - you are charged for rows, not for pressing Start. You are billed for the listings that come out, so filtering to `onlyPriceDrops` does not charge you for the listings that were scanned and rejected. A typical city search returns 30 listings per page; the default 100-listing run costs about $0.09 and finishes in well under a minute.

### 🔁 Run it on the Apify platform

Schedule the Actor to run daily or weekly, call it from the Apify API or any of the official clients, and export results as CSV, Excel, JSON or XML. Webhooks fire when a run finishes, so you can push new price drops straight into a CRM, a Google Sheet, Make, Zapier or your own service without polling.

### ⚠️ Limits and caveats

- **Portugal has no sort order.** The Portuguese site ignores every ordering parameter and returns the same page regardless, which we verified by comparing results rather than trusting status codes. Price drops are still detected on every Portuguese listing, but they are not front-loaded, so a Portuguese price-drop run has to scan more pages for the same number of hits. The Actor logs a warning instead of pretending the sort applied.
- **There is no minimum-price filter.** Neither the Spanish nor the Italian site has a working minimum-price URL segment - Spain's apparent one returns the unfiltered page. Rather than ship a filter that silently does nothing, the input has none. Use `startUrls` with a search you built on the site if you need a lower bound.
- **The reduction is relative to Idealista's own last price, not the property's history.** If a seller relisted the property at a new price, the badge resets, so a genuinely reduced home can show as not reduced.
- **Geography comes from the listing title, and its granularity differs by country.** Spanish titles usually end in the city; Portuguese and Italian ones often end in a district instead. `locationText` carries the raw string so you can re-split it your way.
- **The median is the median of your run, not of the market.** `pctVsMedianPricePerSqm` compares a listing with everything else the run collected, so a narrow or heavily filtered search gives a narrow benchmark. Widen the search if you want the comparison to mean more.
- **This reads search results, not detail pages.** Fields only shown on the property page - full photo sets, energy certificates, exact coordinates, the seller's phone - are not collected.
- **Rentals are priced per month**, so `pricePerSqm` on a rental search is monthly rent per m², not a purchase price.
- **Listings without a stated area** get no `pricePerSqm` and are left out of the median.

### 🧩 Related Actors

- **Spain BOE Subastas API** - Spanish public auction listings, for stock that never reaches the portal at all.
- **Portugal e-Leiloes Auctions API** and **Italy PVP Auctions API** - the same auction angle in the other two countries this Actor covers.
- **France Notaires Property API** - notarial sale data for the neighbouring market.
- **Website Contact Extractor** - turn the `agencyUrl` on each row into emails and phone numbers for outreach.
- **Lead List Deduplicator** - merge several weekly runs into one clean list without repeat rows.

### ❓ FAQ

**Am I charged for listings that get filtered out?**
No. Charging is per row written to the dataset, so listings rejected by `onlyPriceDrops`, `minPriceDropPercent`, `minRooms` or `onlyPrivateOwners` cost you nothing.

**Do I need my own proxies or an anti-bot service?**
No. Idealista refuses datacenter IPs and most browser fingerprints, so the Actor picks its own residential exit and browser. There is no proxy input to configure and nothing to buy separately.

**Which countries are covered?**
Spain (idealista.com), Italy (idealista.it) and Portugal (idealista.pt), for both sale and rent.

**Why did my Portuguese price-drop run return fewer drops than a Spanish one?**
Because Portugal offers no reduction sort, so the run scans listings in Idealista's default order and finds cuts at whatever rate the market has them. Raise `maxItems` or drop `minPriceDropPercent` for a Portuguese search.

**How do I find the right location slug?**
Run the search you want on Idealista and copy the segment after the operation from the address bar - `idealista.com/venta-viviendas/**madrid-madrid**/`. Or skip it and paste the whole URL into `startUrls`.

**How many listings can one run return?**
Set `maxItems` to `0` for no limit. Idealista itself stops paginating a search after roughly 60 pages, so a single very broad search tops out around 1,800 listings; split a big area into districts to go deeper.

**Can I get the seller's phone number?**
No. Phone numbers sit behind a click on the detail page and are not collected. `agencyName` and `agencyUrl` are provided so you can look the agency up.

### 🛠️ Support

Something wrong? Open an issue on the Actor's Issues tab with the run URL, the input you used and what you expected instead - that is enough to reproduce almost anything.

### ⭐ Rate this Actor

If this saved you a diffing script, please leave a review on the Reviews tab. Reviews are the main trust signal other buyers have, and they decide what gets built and improved next. If something is broken, please open an issue first - most problems are fixed within a day, and that is faster than a low rating gets them fixed.

# Actor input Schema

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

Which Idealista site to search: Spain (idealista.com), Italy (idealista.it) or Portugal (idealista.pt).

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

Whether to search properties for sale or for rent.

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

The location slug exactly as it appears in an Idealista URL, for example 'madrid-madrid', 'barcelona-barcelona' or 'valencia/valencia'. Open the search you want on Idealista and copy the part after the operation, e.g. idealista.com/venta-viviendas/**madrid-madrid**/.

## `sortBy` (type: `string`):

'Biggest price drops' uses Idealista's own reduction ordering, which front-loads reduced listings and is the cheapest way to harvest them. Spain and Italy only - the Portuguese site exposes no sorting, so PT runs come back in Idealista's own order with price drops still detected on every listing.

## `onlyPriceDrops` (type: `boolean`):

Drop every listing that has not been reduced. Off by default so a run returns the full search; turn it on when you only want reduced stock.

## `minPriceDropPercent` (type: `integer`):

Keep only listings reduced by at least this percentage. Leave empty for any reduction.

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

Stop after this many matching listings. Set 0 for no limit. The default keeps a first run small and cheap.

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

Highest asking price to include, applied by Idealista itself as a search filter. There is no matching minimum-price filter on the Spanish or Italian sites, so use Start URLs if you need a lower bound.

## `minArea` (type: `integer`):

Smallest floor area to include, applied by Idealista itself as a search filter.

## `maxArea` (type: `integer`):

Largest floor area to include, applied by Idealista itself as a search filter.

## `minRooms` (type: `integer`):

Keep only listings with at least this many bedrooms. Applied to the scraped rows, not to the Idealista search.

## `onlyPrivateOwners` (type: `boolean`):

Keep only listings posted by private owners, dropping everything marketed by an agency.

## `includeDescription` (type: `boolean`):

Include the description text from each card. Turn off for a narrower export.

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

Full Idealista search URLs to scrape, including any filters you set on the site. When given, these replace the country, location and filter fields above.

## Actor input object example

```json
{
  "country": "es",
  "operation": "sale",
  "location": "madrid-madrid",
  "sortBy": "priceDrop",
  "onlyPriceDrops": false,
  "maxItems": 100,
  "onlyPrivateOwners": false,
  "includeDescription": true
}
```

# Actor output Schema

## `priceDrops` (type: `string`):

No description

## `listings` (type: `string`):

No description

## `marketValue` (type: `string`):

No description

## `sellers` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "country": "es",
    "operation": "sale",
    "location": "madrid-madrid",
    "sortBy": "priceDrop",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdata_labs/idealista-price-drop-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 = {
    "country": "es",
    "operation": "sale",
    "location": "madrid-madrid",
    "sortBy": "priceDrop",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("webdata_labs/idealista-price-drop-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "country": "es",
  "operation": "sale",
  "location": "madrid-madrid",
  "sortBy": "priceDrop",
  "maxItems": 100
}' |
apify call webdata_labs/idealista-price-drop-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,webdata_labs/idealista-price-drop-scraper"
        }
    }
}

```

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/2f9eShWV3grCcMiFE/builds/nQ66O37zSWegwxWk1/openapi.json
