# Idealista Scraper — Spain, Italy & Portugal Properties (`logiover/idealista-scraper`) Actor

Scrape idealista.com, .it and .pt listings — homes, rentals, offices, land. Price, price drops, €/m², rooms, floor, lift, agency, photos and optional full details. Splits big searches past the 1,800 cap. No login.

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

## Pricing

from $2.50 / 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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Idealista Scraper — Spain, Italy & Portugal Properties

> **Independent tool.** This Actor is not affiliated with, endorsed by, or sponsored by idealista. "idealista" is a trademark of its owner and is used here only to describe the website this tool reads.

Scrape property listings from **idealista.com (Spain), idealista.it (Italy) and idealista.pt (Portugal)** — homes for sale and rent, offices, shops, garages, land, rooms and new developments. Paste any idealista search URL with your own filters, or just type a city, and get a clean spreadsheet of listings: **price, price drops, €/m², size, rooms, floor, lift, garage, agency, photos, tags** and, if you want them, the **full description, bathrooms, year built, condition and energy certificate** of every listing.

Pisos en venta y alquiler, viviendas, locales y garajes en España · case e immobili in vendita e in affitto in Italia · casas, apartamentos e imóveis para comprar ou arrendar em Portugal — one Actor, one schema, three countries.

**No login, no API key, no browser extension.** Large searches are split automatically, so you are not stuck at idealista's 1,800-listing limit per search.

***

### ✨ Why this idealista scraper

- **Gets past the 1,800 cap.** idealista shows at most 60 pages × 30 listings per search. This Actor reads idealista's own district/neighbourhood breadcrumb (whose counts add up exactly to the search total) and walks every sub-area — measured: **2,454 of 2,454** listings from a single "Barrio de Salamanca" search.
- **Price-drop data built in.** Every listing with a reduction comes with `previousPrice` and `priceDropPercent` — ready for price-drop alerts and negotiation targets.
- **Three countries, one schema.** Spanish, Italian and Portuguese pages are normalised into the same columns (`rooms`, `sizeM2`, `floorNumber`, `hasLift`, `garage`…), with the raw text kept alongside.
- **Every property type.** Homes, rentals, offices, commercial premises, garages, land, storage rooms, whole buildings, rooms to rent and new-build developments.
- **Optional deep mode.** Turn on *Fetch full listing details* for the full text, every feature bullet, bathrooms, built/usable area, year built, condition, heating, orientation, energy rating, amenities (pool, terrace, A/C…), ad reference, last-update date and all full-size photos.
- **Honest runs.** If idealista refuses access, the run **fails with the reason** instead of "succeeding" with an empty dataset. A `SUMMARY` record in the key-value store tells you what happened.

### 🎯 Use cases

- **Price monitoring** — schedule a daily run over your target areas and track every listing's price by `propertyCode`.
- **Price-drop alerts** — filter `priceDropPercent > 5` to find motivated sellers before anyone else.
- **Investment analysis** — compare €/m² across districts and neighbourhoods; spot under-priced flats.
- **Rental yield** — run the same area for sale and for rent and compute gross yield per neighbourhood.
- **Agency lead generation** — export which agencies list what, where, and how much (agency name, profile URL, logo, listing count per area).
- **Market research & reporting** — stock, asking prices, size and typology mix for any city in Spain, Italy or Portugal.
- **PropTech & data products** — feed valuation models, dashboards and CRMs with structured, de-duplicated listings.

### 🚀 Quick start

1. Open idealista in your browser, search for what you want (city, sale or rent, filters such as price, bedrooms, size, lift…) and copy the address bar.
2. Paste it into **Start URLs** — or skip that and type location slugs (e.g. `madrid-madrid`, `milano-milano`, `lisboa`) in **Locations**.
3. Set **Max listings** and press **Start**. Export as Excel, CSV, JSON or use the API.

### 📥 Input examples

**1. Any search URL, with your own filters (Spain, flats under €300,000):**

```json
{
  "startUrls": [
    { "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/con-precio-hasta_300000/" }
  ],
  "maxItems": 2000
}
```

**2. Several cities at once with the built-in search builder (Italy, rentals):**

```json
{
  "country": "it",
  "operation": "rent",
  "propertyType": "homes",
  "locations": ["milano-milano", "roma-roma", "torino-torino", "bologna-bologna"],
  "maxItems": 5000
}
```

**3. Full details for price-drop tracking, plus single listings you already follow (Portugal + Spain):**

```json
{
  "startUrls": [
    { "url": "https://www.idealista.pt/comprar-casas/lisboa/?ordem=atualizado-desc" },
    { "url": "https://www.idealista.com/inmueble/112272495/" }
  ],
  "fetchDetails": true,
  "maxItems": 500
}
```

| Input | What it does |
|---|---|
| **Start URLs** | Any idealista search results page (any filters, any sort order) or single listing URL, from .com, .it or .pt. Translated pages (`/en/…`) are accepted too. |
| **Country / Operation / Property type / Locations** | A shortcut that builds the search URL for you from a location slug. |
| **Max listings** | Stop after this many unique listings. `0` = no limit. |
| **Max pages per search** | Up to 60 (idealista's own maximum). Lower it to sample many searches. |
| **Go past the 1,800-listing cap** | Split large searches into districts/neighbourhoods automatically (on by default). |
| **Fetch full listing details** | Open each listing page for the full data set (slower — one extra request per listing). |
| **Parallel requests** | 1–50, default 50. Includes hedged duplicates of slow pages. |

### 📤 Output example

A real row from a test run (Madrid, Barrio de Salamanca → Goya neighbourhood):

```json
{
  "propertyCode": "111435766",
  "url": "https://www.idealista.com/inmueble/111435766/",
  "title": "Piso en Calle de la Fuente del Berro, Goya, Madrid",
  "propertyType": "Piso",
  "operation": "sale",
  "propertyCategory": "homes",
  "country": "ES",
  "price": 1460000,
  "priceFrom": false,
  "currency": "EUR",
  "pricePeriod": null,
  "priceText": "1.460.000€",
  "previousPrice": 1495000,
  "priceDropPercent": 2,
  "pricePerM2": 9799,
  "sizeM2": 149,
  "rooms": 3,
  "floor": "2ª planta",
  "floorNumber": 2,
  "isExterior": true,
  "hasLift": true,
  "garage": null,
  "landClassification": null,
  "publishedText": null,
  "features": [
    "3 hab.",
    "149 m²",
    "2ª planta exterior con ascensor"
  ],
  "description": "The Avenue Select Real Estate presenta esta sofisticada propiedad completamente reformada y lista para estrenar, situada en una segunda planta exterior de una elegante finca moderna de 1954, perfectam…",
  "tags": [],
  "ribbon": null,
  "isNewDevelopment": false,
  "developmentName": null,
  "photoCount": 44,
  "mainImageUrl": "https://img4.idealista.com/blur/591_420_mq/0/id.pro.es.image.master/c6/48/1e/1444805773.jpg",
  "images": [
    "https://img4.idealista.com/blur/591_420_mq/0/id.pro.es.image.master/c6/48/1e/1444805773.jpg",
    "https://img4.idealista.com/blur/189_120_mq/0/id.pro.es.image.master/87/1e/90/1444805771.jpg",
    "https://img4.idealista.com/blur/189_120_mq/0/id.pro.es.image.master/a5/e2/4c/1444805774.jpg"
  ],
  "hasFloorPlan": true,
  "hasVideo": true,
  "hasVirtualTour": true,
  "hasHomeStaging": false,
  "isHighlighted": false,
  "isProfessional": true,
  "advertiserType": "professional",
  "agencyName": "THE AVENUE Select Real Estate",
  "agencyUrl": "https://www.idealista.com/pro/the-avenue-select-real-estate/",
  "agencyLogoUrl": "https://st3.idealista.com/4c/35/50/the-avenue-select-real-estate.gif",
  "onlineBooking": false,
  "address": "Calle de la Fuente del Berro, Goya, Madrid",
  "area": "Goya",
  "locality": "Madrid",
  "searchLocation": "Goya",
  "locationId": "0-EU-ES-28-07-001-079-04-002",
  "searchUrl": "https://www.idealista.com/venta-viviendas/madrid/barrio-de-salamanca/goya/",
  "page": 1,
  "position": 27,
  "scrapedAt": "2026-10-10T18:17:16.711Z"
}
```

With **Fetch full listing details** on, each row also carries (real example, Barcelona):

```json
{
  "propertyCode": "112021636",
  "url": "https://www.idealista.com/inmueble/112021636/",
  "title": "Piso en Calle de Roger de Llúria, 120, La Dreta de l'Eixample, Barcelona",
  "price": 1295000,
  "pricePerM2": 8576,
  "sizeM2": 151,
  "rooms": 3,
  "floor": "2ª planta",
  "hasLift": true,
  "agencyName": "Bcn Advisors",
  "detailFetched": true,
  "bathrooms": 2,
  "builtAreaM2": 151,
  "usableAreaM2": 151,
  "condition": "Segunda mano/buen estado",
  "yearBuilt": 1926,
  "orientation": null,
  "heating": "Calefacción individual: Bomba de frío/calor",
  "energyRating": "E",
  "energyConsumption": "200 kWh/m² año",
  "energyEmissions": "100 kg CO2/m² año",
  "adReference": "BCN078830010",
  "lastUpdatedText": "Anuncio actualizado el 9 de octubre",
  "fullDescription": "Hay viviendas que simplemente se visitan y otras que se sienten desde el primer instante. Esta excepcional propiedad reformada a estrenar, situada en una elegante finca regia, pertenece a ese reducido grupo de viviendas …",
  "detailFeatures": [
    "Características básicas: 151 m² construidos, 125 m² útiles",
    "Características básicas: 3 habitaciones",
    "Características básicas: 2 baños",
    "Características básicas: Terraza y balcón",
    "Características básicas: Segunda mano/buen estado",
    "Características básicas: Armarios empotrados",
    "…"
  ],
  "photoUrls": [
    "https://img4.idealista.com/blur/WEB_DETAIL/0/id.pro.es.image.master/1f/7b/e7/1478850244.jpg",
    "https://img4.idealista.com/blur/WEB_DETAIL/0/id.pro.es.image.master/0f/43/3e/1478850375.jpg",
    "… (68 in total)"
  ]
}
```

### 📋 Data fields

| Field | Type | Description |
|---|---|---|
| `propertyCode` | text | idealista's own ID for the listing (stable across runs — use it to track price changes). |
| `url` | text | Public listing page. |
| `title` | text | Listing headline as shown in results, e.g. "Piso en Calle de López de Hoyos, Castellana, Madrid". |
| `propertyType` | text | Type as idealista names it: Piso, Ático, Dúplex, Casa o chalet independiente, Estudio, Bilocale, Trilocale, Apartamento, Moradia, Oficina, Local, Nave, Garaje, Terreno… |
| `operation` | text | sale or rent. |
| `propertyCategory` | text | homes, offices, premises, garages, land, storage, buildings, rooms or newDevelopments (from the search). |
| `country` | text | ES, IT or PT. |
| `price` | number | Asking price in euros (monthly rent for rentals). |
| `priceFrom` | true/false | True for new-development cards that show a starting price ("Desde"). |
| `currency` | text | Always EUR. |
| `pricePeriod` | text | month for rentals; empty for sales. |
| `priceText` | text | Price exactly as displayed, e.g. "2.595.000€" or "1.400€/mes". |
| `previousPrice` | number | Price before the latest reduction. Only set when idealista shows a price drop. |
| `priceDropPercent` | number | Size of the latest reduction in percent. Only set when there is a drop. |
| `pricePerM2` | number | €/m² as shown by idealista, otherwise price ÷ size (monthly €/m² for rentals). |
| `sizeM2` | number | Built area in square metres from the listing card. |
| `rooms` | number | Spain: bedrooms (hab.); Italy: rooms incl. living room (locali); Portugal: T-number bedrooms (T2 = 2). |
| `floor` | text | Floor as written, e.g. "2ª planta", "Bajo", "1º piano", "Rés do chão". |
| `floorNumber` | number | Numeric floor: 0 for ground floor, -1 for basement. |
| `isExterior` | true/false | Spain only: true for exterior-facing, false for interior. |
| `hasLift` | true/false | Building has a lift (con/sin ascensor, con/senza ascensore, com/sem elevador). |
| `garage` | text | included or optional when the card mentions parking. |
| `landClassification` | text | For land: Urbano (solar), Urbanizable, No urbanizable… |
| `publishedText` | text | Freshness label idealista shows on new listings, e.g. "39 minutos", "Publicado ayer", "06 oct". |
| `features` | list | Every feature chip on the card, verbatim. |
| `description` | text | Start of the advertiser's description as shown in results. Use Fetch full listing details for the full text. |
| `tags` | list | Labels such as Lujo, Villa, Apartamento, Alquiler de temporada, In esclusiva, Luminoso. |
| `ribbon` | text | Ribbon on the photo, e.g. Reserva Online, Obra nueva, Nova construção. |
| `isNewDevelopment` | true/false | Listing belongs to a new-build promotion. |
| `developmentName` | text | Name of the new-build promotion, when shown. |
| `photoCount` | number | Number of photos in the listing gallery. |
| `mainImageUrl` | text | URL of the first photo. |
| `images` | list | Photo URLs shown on the card (up to 3). Use Fetch full listing details for all photos. |
| `hasFloorPlan` | true/false | Listing has a floor plan. |
| `hasVideo` | true/false | Listing has a video. |
| `hasVirtualTour` | true/false | Listing has a 3D or 360° virtual tour. |
| `hasHomeStaging` | true/false | Listing has virtual home staging. |
| `isHighlighted` | true/false | Paid "top" placement in the results. |
| `isProfessional` | true/false | true for agencies/developers, false for private owners. |
| `advertiserType` | text | professional or private. |
| `agencyName` | text | Agency or developer name (empty for private owners). |
| `agencyUrl` | text | Agency profile page on idealista. |
| `agencyLogoUrl` | text | Agency logo image URL. |
| `onlineBooking` | true/false | Rental can be reserved online. |
| `address` | text | Street, neighbourhood and town as written on the card. |
| `area` | text | Neighbourhood/zone part of the address. |
| `locality` | text | Last part of the address: town in Spain and Italy, parish (freguesia) in Portugal. |
| `searchLocation` | text | Area of the search page the listing came from (a district or neighbourhood when the search was split). |
| `locationId` | text | idealista location ID of that area, e.g. 0-EU-ES-28-07-001-079-04. |
| `searchUrl` | text | Search page the listing was found on. |
| `page` | number | Results page number. |
| `position` | number | Position on that page (1–30). |
| `scrapedAt` | text | When this row was collected (ISO 8601). |
| `detailFetched` | true/false | Only with Fetch full listing details: whether the listing page was read. |

**Extra fields with *Fetch full listing details*:**

| Field | Type | Description |
|---|---|---|
| `fullDescription` | text | the advertiser's full text |
| `detailFeatures` | list | every feature bullet, prefixed with its section (Basic features, Building, Equipment, Energy certificate) |
| `bathrooms` | number | Bathrooms |
| `builtAreaM2` | number | Built area m² |
| `usableAreaM2` | number | , when the advertiser gives it |
| `condition` | text | , e.g. Segunda mano/buen estado, Buono stato, A reformar |
| `yearBuilt` | number | , when given |
| `orientation` | text | , when given |
| `heating` | text | , when given |
| `energyRating` | text | letter A–G when published (Spain/Portugal) |
| `energyConsumption` | text | , e.g. 1 kWh/m² año |
| `energyEmissions` | text | , e.g. 1 kg CO2/m² año |
| `adReference` | text | the advertiser's own reference code |
| `lastUpdatedText` | text | , e.g. "Anuncio actualizado el 9 de octubre" |
| `contactName` | text | name on the contact form |
| `photoUrls` | list | every gallery photo in full size |
| `hasAirConditioning` | true/false | air conditioning is listed among the features |
| `hasTerrace` | true/false | a terrace is listed |
| `hasBalcony` | true/false | a balcony is listed |
| `hasPool` | true/false | a swimming pool is listed |
| `hasGarden` | true/false | a garden is listed |
| `hasStorageRoom` | true/false | a storage room (trastero / cantina / arrecadação) is listed |
| `hasBuiltInWardrobes` | true/false | built-in wardrobes are listed |
| `isAccessible` | true/false | adapted access for people with reduced mobility is listed |

An empty value always means idealista did not publish that information for that listing (for example, Italian listings do not publish an energy letter and many sellers do not state the year built) — it is never a silent zero.

### 📊 How many results can I get?

idealista itself never shows more than **60 pages × 30 = 1,800 listings per search**: page 61 repeats page 60 and page 100 returns "not found". Searches in big cities report far more — measured on 10 October 2026: Madrid 19,087 homes for sale, Milano 15,650, Barcelona 13,180, Lisboa 10,590.

This Actor gets past the cap without guessing:

1. Every results page carries idealista's location breadcrumb with each child area's listing count. We verified that the children add up **exactly** to the parent (Madrid 19,089 = sum of its 21 districts; Barrio de Salamanca 2,454 = sum of its 6 neighbourhoods; the same holds for Milano, Lisboa and Barcelona rentals, and your filters are kept).
2. When a search is bigger than 1,800, it is replaced by its districts, and a district bigger than 1,800 by its neighbourhoods — recursively.
3. If a smallest area is still above the cap, it is read again under other sort orders (price ascending/descending, newest, size) and merged by `propertyCode`.

Measured on the platform: one search URL for *Barrio de Salamanca (Madrid)* → **2,454 unique listings, 0 duplicates**, 86 page requests (6.5 minutes on the first release, which read 10 pages at a time; the current engine reads up to 50 at once). A whole city like Madrid (≈19,000 homes for sale) is the same process on a larger scale: ≈650 page requests.

### ⚡ Speed and cost

idealista sits behind DataDome bot protection, so every page is fetched through Apify's **UNBLOCKER** proxy. idealista's own servers answer in about half a second; the unblocking in front of them takes **3–60 seconds per page** (median ≈ 27 s, measured). The Actor is built around that fixed cost:

- **Everything at once.** It requests every page it needs in parallel (up to 50 in flight) and builds page URLs itself instead of waiting for page 1; split areas queue all their pages straight from the counts in idealista's breadcrumb.
- **Hedged requests.** A page that is slow to answer gets a duplicate request on a fresh unblocker session; the first good answer wins and the others are cancelled. Cancelled duplicates are not billed by the unblocker.
- **Streaming.** Rows are saved the moment each page is parsed, and the run stops the instant it has the number of listings you asked for.

Measured on the Apify platform with default settings (10 October 2026):

| Run | Before (v1.0.4) | Now |
|---|---|---|
| Example input (60 listings, Madrid) | 77–79 s | 7–37 s, first rows after 4–35 s |
| 1,000 listings (Valencia, sale) | 172.6 s | 36–46 s, first rows after 3–4 s |

- The ranges come from separate platform runs. The unblocker's latency swings with its load and moves together for all requests: in one example run every page answered within 4 s, in another no copy of either page came back before 33 s. Hedging removes single slow pages; it cannot shorten a slow period of the unblocker itself.
- Platform cost (compute + unblocker) is about **$0.06 per 1,000 listings**, on top of the per-result price (it was $0.07 before the speed update).
- **Fetch full listing details** adds one page per listing; detail pages are fetched with the same parallel, hedged engine.
- Memory: the default 1 GB is plenty (peak measured 81 MB with 50 requests in flight).

### 💡 Tips

- **Filters live in the URL.** Price ranges, bedrooms, size, "with lift", "exterior", "new build", publication date — set them on idealista, copy the URL, and the Actor keeps them (also when it splits by district).
- **Newest first:** add `?ordenado-por=fecha-publicacion-desc` (Spain), `?ordine=pubblicazione-desc` (Italy) or `?ordem=atualizado-desc` (Portugal) to your URL and schedule a short daily run to catch new listings.
- **Price tracking:** keep `propertyCode` as your key; join each day's export with the previous one to see changes, or simply filter on `priceDropPercent`.
- **Location slugs** are the part of an idealista URL after the operation: `madrid-madrid` (city), `madrid-provincia` (province), `madrid/barrio-de-salamanca` (district), `milano-milano`, `lisboa`, `porto`.
- **Agencies without branding:** about 30% of professional listings show no agency name on the results card (the agency does not pay for branding). Turn on *Fetch full listing details* to get the advertiser name for all of them.

### ❓ FAQ

**Do I need an idealista account, login or API key?**
No. The Actor reads public search and listing pages, the same ones you see in a browser without logging in.

**Does it work for Italy and Portugal, not only Spain?**
Yes — idealista.it and idealista.pt use the same page structure; Italian and Portuguese vocabulary (locali, piano, ascensore, T2, andar, elevador…) is normalised into the same fields.

**Can I scrape more than 1,800 listings from one search?**
Yes. Leave *Go past the 1,800-listing cap* on and the Actor splits the search into districts and neighbourhoods using idealista's own counts. We measured 2,454/2,454 listings from one search.

**What about rentals, rooms and holiday lets?**
Rental searches (alquiler / affitto / arrendar) are supported; `price` is the monthly rent and `pricePeriod` is `month`. Room rentals (alquiler-habitacion, affitto-stanze, arrendar-quarto) work too.

**How do I get price drops?**
Every listing with a reduction has `previousPrice` and `priceDropPercent` on the results page — no extra cost. The *Prices & drops* view in the dataset shows them side by side.

**Can I get the phone number?**
idealista hides phone numbers behind a click that requires an interaction with their contact service, so phone numbers are not collected. You get the agency name, profile page and the contact name from the listing (with details on).

**What if idealista blocks the run?**
Each blocked or failed request is retried through a fresh unblocker session. If nothing gets through, the run fails with a clear message (outcome `BLOCKED`) instead of returning an empty "successful" dataset. A non-idealista URL or a misspelled location fails immediately with `INVALID_START_URL`.

**How fresh is the data?**
Every run reads idealista live. Each row has `scrapedAt`; with details on, `lastUpdatedText` shows when the advertiser last updated the listing.

**How do I schedule daily runs?**
Use the **Schedules** tab in Apify Console (e.g. every morning) and connect the output to Google Sheets, Slack, a webhook or your database through Apify integrations.

**Can I export to Excel or Google Sheets?**
Yes — every dataset can be downloaded as Excel, CSV, JSON, XML or HTML, or pushed to Google Sheets, Airtable, Make, Zapier or n8n.

**Why are some fields empty?**
Because idealista did not show them for that listing: a garage only appears if the advertiser mentions one, land has no rooms, Italian listings carry no energy letter. Columns are never filled with guesses.

**Is it legal to scrape idealista?**
The Actor collects only publicly available listing information and does not log in or bypass access controls for private content. You are responsible for how you use the data: respect idealista's terms, copyright in photos and descriptions, and data-protection law (GDPR) — avoid processing personal data of private sellers beyond what your legitimate purpose requires.

### 🔌 Use it via API

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/logiover~idealista-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.idealista.com/alquiler-viviendas/barcelona-barcelona/"}],"maxItems":300}'
```

**JavaScript (apify-client)**

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('logiover/idealista-scraper').call({
    locations: ['valencia-valencia', 'malaga-malaga'],
    operation: 'sale',
    maxItems: 3000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((x) => x.priceDropPercent >= 5));
```

**Python (apify-client)**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("logiover/idealista-scraper").call(run_input={
    "startUrls": [{"url": "https://www.idealista.it/vendita-case/milano-milano/"}],
    "maxItems": 2000,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["propertyCode"], item["price"], item["pricePerM2"], item["area"])
```

### 🔗 Related real-estate scrapers

- [Pisos.com Property Scraper](https://apify.com/logiover/pisos-com-property-scraper) — Spain
- [Habitaclia Scraper](https://apify.com/logiover/habitaclia-com-spain-scraper) — Catalonia
- [Milanuncios Scraper](https://apify.com/logiover/milanuncios-spain-classifieds-scraper) — Spanish classifieds
- [Imovirtual Scraper](https://apify.com/logiover/imovirtual-pt-scraper-portugal-real-estate) — Portugal
- [Casa.it Scraper](https://apify.com/logiover/casa-it-scraper-italy-real-estate) — Italy
- [Subito.it Property Scraper](https://apify.com/logiover/subito-it-property-scraper) — Italy
- [Rightmove Scraper](https://apify.com/logiover/rightmove-scraper) — United Kingdom

### ⚖️ Legal and trademark

This Actor is an independent tool. It is not affiliated with, endorsed by, sponsored by or connected to idealista or any of its subsidiaries. "idealista" and related names and logos are trademarks of their respective owners and are used here only to identify the website the tool works with. The Actor reads publicly accessible pages only; users are responsible for complying with the website's terms of use and with applicable laws, including the EU General Data Protection Regulation.

### 📝 Changelog

#### 2026-10-10 — speed update

- **Faster:** a 1,000-listing run went from 172.6 s to 36–46 s and the example input from 77 s to 7–37 s (first rows typically after 3–4 s). Every needed page is requested at once, slow pages get a hedged duplicate on a fresh session (first answer wins, the rest are cancelled), rows are saved as each page is parsed, and the run stops the instant the requested number of listings is reached. Default parallel requests raised from 8 to 50.

#### 2026-10-10

- First release: idealista.com, idealista.it and idealista.pt; all property types; sale and rent.
- Automatic district/neighbourhood splitting past the 1,800-listing cap, with sort-order fallback.
- Price-drop fields, €/m², normalised rooms/floor/lift/garage across three languages.
- Optional full listing details: description, all features, bathrooms, areas, year built, condition, heating, orientation, energy certificate, amenities, ad reference, photos.
- Clear failure outcomes (`BLOCKED`, `INVALID_START_URL`) and a `SUMMARY` record on every run.

# Changelog

This Actor's version history is a separate document: https://apify.com/logiover/idealista-scraper/changelog.md

# Actor input Schema

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

idealista search result pages from idealista.com (Spain), idealista.it (Italy) or idealista.pt (Portugal) — open your search in a browser, apply any filters you like (price, rooms, size, lift…) and paste the address. Single listing URLs (/inmueble/…, /immobile/…, /imovel/…) also work and are returned with full details.

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

Used only with Locations below.

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

Used only with Locations.

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

Used only with Locations. Not every type exists in every country; unsupported combinations are skipped with a warning.

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

Location slugs exactly as they appear in idealista URLs, e.g. madrid-madrid, barcelona-barcelona, valencia-valencia, malaga-malaga, madrid-provincia (Spain); milano-milano, roma-roma (Italy); lisboa, porto (Portugal). Districts work too: madrid/barrio-de-salamanca.

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

Stop after this many unique listings across all searches. 0 = no limit.

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

idealista shows at most 60 pages × 30 listings per search. Lower this to sample the first pages of many searches.

## `splitLargeSearches` (type: `boolean`):

When a search reports more listings than 60 pages can show, replace it with its districts/neighbourhoods (idealista's own breadcrumb — their counts add up exactly to the total), recursively. Leaf areas still over the cap are walked again under other sort orders. Filters and sort order in your URL are kept.

## `fetchDetails` (type: `boolean`):

Open every listing page for the full description, all feature bullets (bathrooms, built/usable area, condition, year built, heating, orientation), energy certificate, ad reference, last-updated date and every photo URL. One extra request per listing — slower and pricier on proxy, so leave off for large exports.

## `concurrency` (type: `integer`):

Maximum requests in flight at once, including duplicate (hedged) requests. idealista pages take 3–60 s each through the unblocker, so the Actor asks for every page it needs at the same time and re-asks slow ones on a fresh session (cancelled duplicates are not billed by the unblocker). 50 lets a 1,000-listing run fire all of its pages at once.

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

idealista is protected by DataDome and refuses ordinary datacenter and residential proxies (measured HTTP 403). The Actor uses Apify's UNBLOCKER group; keep it unless you have your own unblocking proxy.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/"
    }
  ],
  "country": "es",
  "operation": "sale",
  "propertyType": "homes",
  "locations": [],
  "maxItems": 60,
  "maxPagesPerSearch": 60,
  "splitLargeSearches": true,
  "fetchDetails": false,
  "concurrency": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}
```

# Actor output Schema

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

All listings collected in this run.

# 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": 60,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "UNBLOCKER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/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 = {
    "startUrls": [{ "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/" }],
    "maxItems": 60,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/idealista-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 '{
  "startUrls": [
    {
      "url": "https://www.idealista.com/venta-viviendas/madrid-madrid/"
    }
  ],
  "maxItems": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}' |
apify call logiover/idealista-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,logiover/idealista-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/82gWdsdotP8gqI8Wr/builds/m5z0Kz3Su197MhF9h/openapi.json
