# Idealista Scraper - Spain, Portugal & Italy Real Estate (`studio-amba/idealista-scraper`) Actor

Scrape real estate listings from Idealista.com (Spain), Idealista.pt (Portugal), and Idealista.it (Italy). Get prices, addresses, property details, photos, energy certificates, and agent contacts for properties for sale or rent. No login or cookies required.

- **URL**: https://apify.com/studio-amba/idealista-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Real estate
- **Stats:** 3 total users, 1 monthly users, 90.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Scraper

Scrape real estate listings (pisos y casas) from Idealista — the dominant property portal in Spain, Portugal, and Italy with over 1.5 million active listings. No login or cookies required.

**Verified completeness, not just a promise.** On 2026-07-16 we ran this actor against Vallehermoso (Chamberí, Madrid) — a zone Idealista itself lists as "100 casas y pisos" — and it returned all 100, zero duplicates, zero missed. Every one of the 100 also came back with `advertiserType` resolved (11 private owners, 89 agencies) — that filter isn't a checkbox that silently does nothing, it's proven on a live run. We re-run this check as part of our own monitoring, so if it breaks we know before you do.

### How to scrape Idealista data

1. Go to [Idealista Scraper](https://apify.com/studio-amba/idealista-scraper) on the Apify Store.
2. Select the **country** (Spain, Portugal, or Italy).
3. Choose a **listing type** (buy or rent).
4. Enter a **location** (city, region, or neighborhood).
5. Optionally filter by property type, price range, size, bedrooms, bathrooms, or **advertiser type** (private owner vs. agency).
6. Set the maximum number of results you want.
7. Click **Start** and wait for the data to be collected.
8. Download your results as JSON, CSV, Excel, or connect via API.

### Why use this actor?

Real estate investors, analysts, relocation agencies, and proptech companies need reliable property data from Southern Europe's largest markets. This actor extracts structured listing data from Idealista including prices, addresses, property specs, photos, energy certificates, agent contacts, and whether the seller is a private owner or an agency — ready for market analysis, price comparison, portfolio monitoring, or lead generation.

Idealista is protected by DataDome and Akamai — most scrapers either get blocked outright or silently return zero-result pages that still show as "succeeded." This actor connects through a dedicated anti-bot bypass (Bright Data Scraping Browser over CDP) instead of a plain residential-proxy browser, which is why the completeness check above actually completed instead of timing out.

Idealista covers three major markets from a single portal:

- **Spain** (idealista.com) — 800K+ listings, the #1 real estate site
- **Portugal** (idealista.pt) — the leading property portal
- **Italy** (idealista.it) — major market with growing share

### Find private sellers (FSBO), not just agencies

Every listing on Idealista is tagged internally as either **particular** (a private owner selling or renting directly) or **profesional** (an agency). We resolve that tag from each listing's detail page and expose it two ways:

- As an **output field**, `advertiserType` (`"private"` or `"professional"`), on every row.
- As an **input filter**, `advertiserType`, so you can pull only private-owner listings — the ones agencies pay outreach tools like Betipo or Hostreach to hunt down manually.

In our Vallehermoso benchmark, 11 of 100 listings were private owners. That's 11 direct leads with no agency in the way — useful for agents doing *captación de particulares* (private-listing acquisition), for buyers who want to negotiate without a broker's commission on top, or for anyone building a feed of fresh FSBO ads instead of the same agency inventory every portal already carries.

*Cada anuncio de Idealista está marcado como particular o profesional. Este actor extrae ese dato y te deja filtrar solo particulares — justo el tipo de contacto que agencias y captadores buscan a mano para captación de particulares. Si lo que necesitas son testigos (comparables de la zona) o vigilar precios para no perder una alerta, esta salida de datos —dirección, precio, m², planta, certificado energético— es la base para montarlo tú mismo con Schedule + tu propio aviso.*

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `country` | String | No | `ES` (Spain, default), `PT` (Portugal), or `IT` (Italy) |
| `listingType` | String | No | `sale` (default) or `rent` |
| `searchQuery` | String | No | City, region, or neighborhood (e.g. `Madrid`, `Barcelona`, `Lisboa`, `Roma`, `Vallehermoso`) |
| `propertyType` | String | No | `flat`, `house`, `penthouse`, `studio`, `duplex`, `loft`, `country-house`, `land`, or `garage` |
| `minPrice` | Integer | No | Minimum price in EUR |
| `maxPrice` | Integer | No | Maximum price in EUR |
| `minSize` | Integer | No | Minimum constructed area in m2 |
| `maxSize` | Integer | No | Maximum constructed area in m2 |
| `bedrooms` | Integer | No | Minimum number of bedrooms |
| `bathrooms` | Integer | No | Minimum number of bathrooms |
| `advertiserType` | String | No | `private` (particulares/FSBO only), `professional` (agencies only), or leave blank for both. Resolved from each listing's detail page — see note below on how `maxResults` interacts with this filter. |
| `maxResults` | Integer | No | Maximum results to return (default: 100) |
| `proxyConfiguration` | Object | No | Kept for input-schema compatibility; transport is handled by the actor's own anti-bot bypass regardless of this setting |

**Note on `advertiserType` + `maxResults`:** `maxResults` caps how many search-result candidates get fetched and enriched *before* the filter is applied, not the final filtered count. If you set `advertiserType: "private"` with `maxResults: 20` and only 4 of those 20 candidates turn out to be private owners, you'll get 4 rows back. Raise `maxResults` if you need a guaranteed minimum of filtered results.

### Output

Each result contains:

| Field | Type | Example |
|-------|------|---------|
| `title` | String | `"Piso en calle de Alcala"` |
| `price` | Number | `385000` |
| `currency` | String | `"EUR"` |
| `pricePerM2` | Number | `4812` |
| `originalPrice` | Number | `395000` |
| `priceDropPercent` | Number | `2.5` |
| `listingType` | String | `"sale"` or `"rent"` |
| `propertyType` | String | `"flat"` |
| `address` | String | `"Calle de Alcala, Salamanca, Madrid"` |
| `city` | String | `"Madrid"` |
| `province` | String | `"Madrid"` |
| `district` | String | `"Salamanca"` |
| `postalCode` | String | `"28009"` |
| `latitude` | Number | `40.4233` |
| `longitude` | Number | `-3.6783` |
| `bedrooms` | Number | `3` |
| `bathrooms` | Number | `2` |
| `rooms` | Number | `5` |
| `surface` | Number | `80` |
| `usableSurface` | Number | `72` |
| `landSurface` | Number | `null` |
| `floor` | String | `"3"` |
| `hasLift` | Boolean | `true` |
| `isExterior` | Boolean | `true` |
| `hasAirConditioning` | Boolean | `true` |
| `hasSwimmingPool` | Boolean | `false` |
| `hasGarden` | Boolean | `false` |
| `hasTerrace` | Boolean | `true` |
| `hasParking` | Boolean | `true` |
| `parkingPrice` | Number | `25000` |
| `condition` | String | `"good"` |
| `energyCertification` | String | `"D"` |
| `description` | String | Full property description text |
| `imageUrl` | String | Primary listing photo URL |
| `imageUrls` | Array | All listing photo URLs |
| `imageCount` | Number | `24` |
| `has3DTour` | Boolean | `true` |
| `hasVideo` | Boolean | `false` |
| `agencyName` | String | `"Engel & Volkers"` (or the owner's first name for private listings) |
| `agencyPhone` | String | `"+34 91 123 4567"` |
| `agencyUrl` | String | Agency logo URL (null for private listings) |
| `advertiserType` | String | `"private"` or `"professional"` |
| `propertyCode` | String | `"12345678"` |
| `country` | String | `"ES"` |
| `url` | String | Full listing URL on Idealista |
| `scrapedAt` | String | `"2026-06-07T12:00:00.000Z"` |

### Example output

```json
{
    "title": "Piso en calle de Alcala",
    "price": 385000,
    "currency": "EUR",
    "pricePerM2": 4812,
    "originalPrice": null,
    "priceDropPercent": null,
    "listingType": "sale",
    "propertyType": "flat",
    "address": "Calle de Alcala, Salamanca, Madrid",
    "city": "Madrid",
    "province": "Madrid",
    "district": "Salamanca",
    "postalCode": "28009",
    "latitude": 40.4233,
    "longitude": -3.6783,
    "bedrooms": 3,
    "bathrooms": 2,
    "rooms": 5,
    "surface": 80,
    "usableSurface": 72,
    "landSurface": null,
    "floor": "3",
    "hasLift": true,
    "isExterior": true,
    "hasAirConditioning": true,
    "hasSwimmingPool": false,
    "hasGarden": false,
    "hasTerrace": true,
    "hasParking": true,
    "parkingPrice": 25000,
    "condition": "good",
    "energyCertification": "D",
    "description": "Luminoso piso exterior en el barrio de Salamanca...",
    "imageUrl": "https://img3.idealista.com/blur/...",
    "imageUrls": [
        "https://img3.idealista.com/blur/...",
        "https://img3.idealista.com/blur/..."
    ],
    "imageCount": 24,
    "has3DTour": true,
    "hasVideo": false,
    "agencyName": "Engel & Volkers",
    "agencyPhone": "+34 91 123 4567",
    "agencyUrl": null,
    "advertiserType": "professional",
    "propertyCode": "12345678",
    "country": "ES",
    "url": "https://www.idealista.com/inmueble/12345678/",
    "scrapedAt": "2026-06-07T12:00:00.000Z"
}
```

### Cost estimate

This actor connects through Bright Data's Scraping Browser (a managed anti-bot bypass) rather than a plain proxy, because Idealista's DataDome + Akamai stack blocks datacenter and residential proxies alike. It visits both search pages and individual detail pages for full data enrichment, including the `advertiserType` lookup. Expect a similar cost profile to other Playwright-based real estate scrapers — test with 10-20 results first to confirm the exact usage for your search before scaling up.

### Tips for best results

- **Start small** — test with 10-20 results first, then scale up.
- **Be specific with location** — use city, district, or neighborhood names as they appear on Idealista (e.g. "Madrid", "Chamberí", "Vallehermoso").
- **Filtering by `advertiserType`?** Raise `maxResults` so the pre-filter candidate pool is large enough to contain your target count — see the note under Input above.
- **Combine filters** — narrow results with price range, property type, and advertiser type together to get exactly the leads you want.

### Supported countries and cities

#### Spain (idealista.com)

Madrid, Barcelona, Valencia, Sevilla, Malaga, Bilbao, Alicante, Palma de Mallorca, Las Palmas, Zaragoza, and all provinces — down to district and neighborhood level (e.g. Chamberí, Vallehermoso).

#### Portugal (idealista.pt)

Lisboa, Porto, Faro, Braga, Coimbra, Setúbal, Funchal, and all districts.

#### Italy (idealista.it)

Roma, Milano, Napoli, Torino, Firenze, Bologna, Palermo, Genova, and all provinces.

### Limitations

- Idealista has aggressive anti-bot protection (DataDome + Akamai); this actor routes around it via a managed Scraping Browser, but individual pages can still occasionally be blocked — the actor falls back gracefully rather than crashing
- `advertiserType` requires a successful detail-page fetch to resolve; if that page is blocked, the field is `null` and the listing is excluded when the `advertiserType` filter is active (see Input notes)
- Maximum ~60 pages per search (Idealista platform limit), which is approximately 1,800 listings per search query without splitting by price band
- GPS coordinates are only available when the listing includes a map
- Data is scraped from the public website and may change without notice
- Respect the website's terms of service and use responsibly

### Use cases

- **FSBO lead generation** — filter to `advertiserType: private` for fresh owner-direct listings, the same segment tools like Betipo and Hostreach charge €20-35/month to hand-hunt.
- **Market analysis** — track asking prices, price-per-m2, and inventory across Spanish, Portuguese, and Italian cities.
- **Investment research** — compare rental yields and property values across Southern European markets.
- **Relocation intelligence** — aggregate listings by neighborhood, price, and features for expat relocation services.
- **Competitor monitoring** — track how agencies price and position their listings vs. private sellers.
- **Academic research** — study housing market trends, gentrification patterns, and price dynamics.

### Related Spanish & Italian property scrapers

We publish scrapers for every major Spanish and Italian real estate portal, so you can cross-check the same address across all of them or dedupe listings that get syndicated to multiple sites:

- [Fotocasa Scraper](https://apify.com/studio-amba/fotocasa-scraper) — Spain's #2 portal
- [Habitaclia Scraper](https://apify.com/studio-amba/habitaclia-scraper) — Catalonia-strong Spanish portal
- [Pisos.com Scraper](https://apify.com/studio-amba/pisos-com-scraper) — another major Spanish portal
- [Immobiliare.it Scraper](https://apify.com/studio-amba/immobiliare-scraper) — Italy's #1 real estate portal

### Support

Hit a bug or a missing field? Open an issue on the Actor page — we respond fast and ship fixes within 24 hours. Every published scraper in the Studio Amba catalog is monitored daily; broken runs trigger an automatic heal cycle.

# Actor input Schema

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

Target country domain.

## `listingType` (type: `string`):

Filter by buy (sale) or rent.

## `searchQuery` (type: `string`):

City, region, or neighborhood to search (e.g. 'Madrid', 'Barcelona', 'Lisboa', 'Roma'). Leave empty for the default (Madrid).

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

Filter by property type.

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

Minimum price filter in EUR.

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

Maximum price filter in EUR.

## `minSize` (type: `integer`):

Minimum constructed area in square meters.

## `maxSize` (type: `integer`):

Maximum constructed area in square meters.

## `bedrooms` (type: `integer`):

Minimum number of bedrooms.

## `bathrooms` (type: `integer`):

Minimum number of bathrooms.

## `advertiserType` (type: `string`):

Filter by who's selling: private owners (particulares/FSBO, no agency) or professional agencies (profesionales). Resolved from each listing's detail page — listings we can't confirm are excluded when this filter is active.

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

Maximum number of listings to return.

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

Proxy settings. Residential proxies recommended — Idealista has strong anti-bot protection.

## Actor input object example

```json
{
  "country": "ES",
  "listingType": "sale",
  "searchQuery": "Madrid",
  "propertyType": "",
  "advertiserType": "",
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}
```

# 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",
    "listingType": "sale",
    "searchQuery": "Madrid",
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "ES"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/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 = {
    "country": "ES",
    "listingType": "sale",
    "searchQuery": "Madrid",
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "ES",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/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 '{
  "country": "ES",
  "listingType": "sale",
  "searchQuery": "Madrid",
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}' |
apify call studio-amba/idealista-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/O0ehAgldLMeaQSV18/builds/QUrUTe5KZlmvxiIwT/openapi.json
