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

Scrape real estate listings from Idealista.com. Extract property prices, locations, features, photos, and agent contacts for Spain, Italy, and Portugal.

- **URL**: https://apify.com/crawlerbros/idealista-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Stats:** 111 total users, 5 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 1.00 out of 5 stars

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

Extract real estate listing data from Idealista.com across Spain, Italy, and Portugal. Get property prices, sizes, locations, features, photos, and agent contacts for homes, offices, garages, new developments, and more.

### What It Does

- Scrape property listings for **sale or rent** across all property types
- Support for **Spain** (idealista.com), **Italy** (idealista.it), and **Portugal** (idealista.pt)
- **30+ data fields** per listing including price, size, location, features, and agency info
- All property types: homes, offices, premises, garages, lands, storage rooms, buildings, bedrooms
- Automatic **pagination** — collects all available pages up to your configured maximum
- Mirror-first cloud fetching that avoids slow browser sessions for normal runs
- Export to **JSON, CSV, Excel, or XML**

### Input

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `location` | string | Yes\* | madrid-madrid | City or area slug from Idealista URLs (e.g., `madrid-madrid`, `barcelona-barcelona`, `lisboa`, `roma-roma`) |
| `operation` | string | No | sale | Listing type: `sale` or `rent` |
| `propertyType` | string | No | homes | Property type (see list below) |
| `country` | string | No | es | Target country: `es` (Spain), `pt` (Portugal), `it` (Italy) |
| `maxItems` | integer | No | 100 | Maximum listings to scrape (max 1,800 per search) |
| `startUrls` | array | Yes\* | — | Direct Idealista search URLs — overrides location/operation/propertyType |
| `proxyConfiguration` | object | No | Apify Proxy | Keep the default proxy settings for best cloud reliability |

\* At least one of `location` or `startUrls` is required.

#### Property Types

| Value | Description |
|-------|-------------|
| `homes` | Apartments, houses, villas |
| `newDevelopments` | Off-plan and new-build developments |
| `offices` | Office spaces |
| `premises` | Commercial premises / retail units |
| `garages` | Garages and parking spaces |
| `lands` | Plots and land |
| `storageRooms` | Storage rooms (trasteros) |
| `buildings` | Entire buildings |
| `bedrooms` | Rooms for rent |

#### Example Input

```json
{
    "location": "madrid-madrid",
    "operation": "sale",
    "propertyType": "homes",
    "country": "es",
    "maxItems": 50
}
```

#### Location Slug Reference

Find your slug by searching on Idealista and copying the location segment from the URL:

| Country | Location | Slug |
|---------|----------|------|
| Spain | Madrid | `madrid-madrid` |
| Spain | Barcelona | `barcelona-barcelona` |
| Spain | Seville | `sevilla-sevilla` |
| Spain | Valencia | `valencia-valencia` |
| Spain | Marbella | `marbella-malaga` |
| Spain | Málaga | `malaga-malaga` |
| Portugal | Lisbon | `lisboa` |
| Portugal | Porto | `porto` |
| Portugal | Faro | `faro` |
| Italy | Rome | `roma-roma` |
| Italy | Milan | `milano-milano` |
| Italy | Florence | `firenze-firenze` |

You can also paste a full Idealista URL directly into the `location` field, or use `startUrls` to scrape multiple search pages at once.

### Output

Each property listing produces one dataset record. This version scrapes search-result cards (not individual property detail pages), so fields are split below into what the search page reliably exposes vs. what would need a detail-page visit (see [Limitations](#limitations)).

#### Core Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `propertyCode` | string | Idealista property ID |
| `url` | string | Full URL to the property listing page |
| `sourceUrl` | string | Same canonical property URL, included for standard dataset consumers |
| `recordType` | string | `listing` for property listing records |
| `price` | integer | Listing price in EUR |
| `priceByArea` | integer | Price per square meter in EUR |
| `currency` | string | Currency code (EUR) |
| `size` | integer | Property size in m² |
| `rooms` | integer | Number of bedrooms |
| `bathrooms` | integer | Number of bathrooms (from the card, or parsed from the description text) |
| `floor` | string | Floor level (e.g., `4ª planta exterior con ascensor`) |
| `exterior` | boolean | Exterior-facing property |
| `description` | string | Listing description text as shown on the search card |

#### Location Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `address` | string | Street address or location label as shown on the card |
| `municipality` | string | City or municipality, parsed from the address |
| `district` | string | District or neighbourhood, parsed from the address |
| `country` | string | Country code: `es`, `pt`, or `it` |

#### Media Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `thumbnail` | string | Primary listing photo URL |
| `numPhotos` | integer | Total number of photos in the card's gallery |

#### Feature Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `hasLift` | boolean | Building has an elevator |
| `hasSwimmingPool` | boolean | Property has a pool |
| `hasTerrace` | boolean | Property has a terrace |
| `hasAirConditioning` | boolean | Property has air conditioning |
| `hasBoxRoom` | boolean | Includes a storage room (trastero) |
| `hasGarden` | boolean | Property has a garden |
| `hasParkingSpace` | object | `{ hasParkingSpace, isParkingSpaceIncludedInPrice }` — detected from card text |

#### Contact Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `contactInfo` | object | Agency details: `{ commercialName, agencyLogo }` |

#### Status & Classification Fields (reliably populated)

| Field | Type | Description |
|-------|------|-------------|
| `propertyType` | string | Property type (homes, offices, etc.) — from your search input |
| `operation` | string | `sale` or `rent` — from your search input |
| `newDevelopment` | boolean | New construction development, detected from card text |
| `topPlus` | boolean | Top Plus premium placement, detected from card styling |
| `scrapedAt` | string | ISO 8601 UTC timestamp of scrape |

#### Fields not available from search cards

Idealista's search-result cards don't expose these — they require visiting each property's individual detail page, which this version doesn't do yet (see [Limitations](#limitations)):

`province`, `latitude`, `longitude`, `showAddress`, `locationId`, `multimedia`, `hasVideo`, `has3DTour`, `has360`, `hasStaging`, `hasPlan`, `status`, `newProperty`, `externalReference`, `detailedType`, `topNewDevelopment`, `visualHighlight`, `urgentVisualHighlight`, `preferenceHighlight`, `topHighlight`.

#### Sample Output

```json
{
    "propertyCode": "107795847",
    "url": "https://www.idealista.com/inmueble/107795847/",
    "sourceUrl": "https://www.idealista.com/inmueble/107795847/",
    "recordType": "listing",
    "price": 1160000,
    "priceByArea": 5321,
    "currency": "EUR",
    "size": 218,
    "rooms": 3,
    "bathrooms": 2,
    "floor": "4ª planta exterior con ascensor",
    "exterior": true,
    "description": "Espectacular piso en venta en el barrio de Salamanca...",
    "address": "Piso en Calle de Jorge Juan, Recoletos, Madrid",
    "municipality": "Madrid",
    "district": "Recoletos",
    "country": "es",
    "thumbnail": "https://img3.idealista.com/blur/WEB_LISTING/0/id.pro.es.image.master/...",
    "numPhotos": 24,
    "hasLift": true,
    "hasTerrace": true,
    "hasAirConditioning": true,
    "hasParkingSpace": {
        "hasParkingSpace": true,
        "isParkingSpaceIncludedInPrice": false
    },
    "contactInfo": {
        "commercialName": "Engel & Völkers Madrid",
        "agencyLogo": "https://img3.idealista.com/..."
    },
    "propertyType": "homes",
    "operation": "sale",
    "newDevelopment": false,
    "topPlus": false,
    "scrapedAt": "2026-06-23T10:00:00+00:00"
}
```

### When the run finds nothing

If a run ends with 0 listings, the run's status message explains why:

- **All attempts blocked** — Idealista or the mirror blocked every fetch attempt. This is usually temporary; keep the default proxy settings and try again.
- **No listings extracted** — the page had no results, most often because the location slug is wrong. Check the [Location Slug Reference](#location-slug-reference) table above — Italy requires Italian names (`roma-roma`, not `rome`), and Portugal uses Portuguese names (`lisboa`, not `lisbon`).
- **No URLs to process** — `startUrls` only contained individual property detail pages, which this actor doesn't scrape yet (search result pages only).

Check the run's Status Message in the Apify Console for the specific reason.

### Use Cases

- **Market analysis**: Track property prices and trends across Spanish, Italian, and Portuguese cities
- **Investment research**: Compare prices per square meter across neighbourhoods and districts
- **Competitive monitoring**: Track competitor agency listings and pricing strategies
- **Lead generation**: Collect agency contact details for real estate businesses
- **Portfolio management**: Monitor listings in specific areas for property management firms
- **Price alerts**: Run on a schedule to detect new listings or price changes

### Limitations

- **Search pages only**: The stable cloud path scrapes search-result cards. Individual property detail pages are not supported yet.
- **Search result cap**: Idealista caps search results at ~1,800 listings (60 pages) per query. Split large cities into districts for broader coverage.
- **Rate limits**: The scraper uses polite delays between pages. Small runs usually finish in under a minute.
- **No individual property pages**: This version scrapes search result cards. Full detail pages (phone numbers, more photos) require navigating to each property URL individually.

### FAQ

**Do I need a login or cookies?**
No. Idealista listings are publicly accessible — no account required.

**Why does the input include proxy settings?**
Cloud traffic can be blocked by Idealista or by the mirror. The actor keeps Apify Proxy enabled by default and uses it only when needed for reliable public-page access.

**Which countries are supported?**
Spain (`idealista.com`), Portugal (`idealista.pt`), and Italy (`idealista.it`).

**What property types can I scrape?**
Homes, new developments, offices, commercial premises, garages, plots/land, storage rooms, entire buildings, and rooms for rent.

**How do I find the location slug?**
Search on Idealista and look at the URL. For `idealista.com/venta-viviendas/madrid-madrid/`, the slug is `madrid-madrid`. For Portugal: `idealista.pt/comprar-casas/lisboa/` → `lisboa`. For Italy: `idealista.it/vendita-case/roma-roma/` → `roma-roma`.

**Why are some fields missing from the output?**
Fields are omitted when they have no value. For example, coordinates appear only when Idealista exposes them, and features like pool or terrace are only included when they are mentioned in the listing card.

**How many listings can I scrape?**
Up to 1,800 per search query (Idealista's hard cap). For large cities, split the search by district or neighbourhood to get broader coverage.

**How fast is the scraper?**
Small runs usually finish in under a minute. Larger runs depend on pagination depth and mirror response time.

**Can I scrape multiple cities in one run?**
Yes — use `startUrls` to provide multiple search page URLs (one per city or district). The actor scrapes them in sequence up to `maxItems` total.

**What if the run finishes with 0 listings?**
Check the run's Status Message — it explains whether Idealista blocked every attempt (temporary; try again) or the location slug returned no results.

# Actor input Schema

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

City or area to search. Use the location slug from Idealista URLs. Spain: 'madrid-madrid', 'barcelona-barcelona', 'marbella-malaga'. Italy: 'roma-roma', 'milano-milano'. Portugal: 'lisboa', 'porto'. You can also paste a full Idealista search URL.

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

Type of listing: properties for sale or for rent.

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

Type of property to search for.

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

Idealista country: Spain, Portugal, or Italy.

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

Maximum number of property listings to scrape. Leave empty for all available results (up to 1,800 per search).

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

Direct Idealista search result page URLs (e.g. https://www.idealista.com/venta-viviendas/madrid-madrid/). When provided, these override the location/operation/propertyType fields. Individual property/listing detail page URLs are not supported yet and will be skipped.

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

Apify Proxy is recommended. The actor uses a mirror-first fetch path and falls back to proxied requests when the mirror blocks direct cloud traffic.

## Actor input object example

```json
{
  "location": "madrid-madrid",
  "operation": "sale",
  "propertyType": "homes",
  "country": "es",
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset containing all scraped Idealista property listings.

# 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 = {
    "location": "madrid-madrid",
    "operation": "sale",
    "propertyType": "homes",
    "country": "es",
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/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 = {
    "location": "madrid-madrid",
    "operation": "sale",
    "propertyType": "homes",
    "country": "es",
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/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 '{
  "location": "madrid-madrid",
  "operation": "sale",
  "propertyType": "homes",
  "country": "es",
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call crawlerbros/idealista-scraper --silent --output-dataset

```

## MCP server setup

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