# Idealista Real Estate Scraper (Spain Property Listings) (`scrapers_lat/idealista-scraper`) Actor

Scrape Idealista property listings by search URL, location or listing URL. Get price, price per m2, rooms, size, floor, features, geo, energy rating, owner-direct vs agency and agency name. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/scrapers\_lat/idealista-scraper.md
- **Developed by:** [Scrapers Lat](https://apify.com/scrapers_lat) (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 $18.91 / 1,000 listing 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?

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 Real Estate Scraper (Spain Property Listings)](https://scrapers.lat/banners/idealista-scraper.png)](https://console.apify.com/actors/21RdkDgRNJG8herPH/input)

## Idealista Real Estate Scraper (Spain Property Listings)

Here is one real result, with the fields the actor returns when the detail add-on is on:

```json
{
  "listingId": "112153132",
  "title": "Piso en Calle de las Infantas, Chueca-Justicia, Madrid",
  "listingUrl": "https://www.idealista.com/inmueble/112153132/",
  "operation": "venta",
  "propertyType": "piso",
  "priceAmount": 1000000,
  "priceCurrency": "EUR",
  "pricePerM2": 7407,
  "rooms": 2,
  "bathrooms": 2,
  "sizeM2": 135,
  "floor": "4ª planta exterior con ascensor",
  "latitude": 40.4199231,
  "longitude": -3.6994614,
  "locationText": "Chueca-Justicia, Madrid",
  "ownerDirect": false,
  "isProfessional": true,
  "agencyName": "Gilmar Centro",
  "agencySlug": "gilmar-centro",
  "energyCertificate": "C",
  "features": ["135 m² construidos", "2 habitaciones", "2 baños", "Terraza", "Armarios empotrados", "Aire acondicionado"],
  "featureCount": 13,
  "description": "Atractivo ático dúplex de 135 m² construidos, situado en una cuarta planta exterior con ascensor, en pleno barrio de Justicia...",
  "imageCount": 40,
  "publishedDate": "17 de agosto",
  "aiHighlights": ["Ático dúplex con terraza privada", "Ubicación en el corazón de Justicia"],
  "aiCondition": "good",
  "aiTargetBuyer": "young professionals or couples",
  "aiPricePerM2Assessment": "in line with prime central Madrid",
  "source": "idealista.com",
  "observedAt": "2026-08-20T03:03:45.019Z"
}
```

The most complete Idealista scraper available. It returns every listing field on the search results (price, price per m2, rooms, size, floor, property type, the owner-direct vs agency signal, agency name and image), plus an optional detail pass that adds geo coordinates, the full feature list, energy certificate, bathrooms, all images, the full description and the agency profile, plus an optional AI summary, and gives you filters to target exactly the properties you want.

**📥 [Input](https://apify.com/scrapers_lat/idealista-scraper/input-schema) · 📤 [Output](https://apify.com/scrapers_lat/idealista-scraper/output-schema) · 💰 [Pricing](https://apify.com/scrapers_lat/idealista-scraper/pricing) · ▶️ [Examples](https://apify.com/scrapers_lat/idealista-scraper/examples)**

![Apify](https://img.shields.io/badge/Platform-Apify-1CE1CE?logo=apify\&logoColor=white)
![Coverage](https://img.shields.io/badge/Coverage-Idealista%20Spain-green)
![Output](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-orange)
![Billing](https://img.shields.io/badge/Billing-Pay%20per%20result-brightgreen)

### Table of contents

- [What it does](#what-it-does)
- [Quickstart](#quickstart)
- [Input reference](#input-reference)
- [Output reference](#output-reference)
- [Run via API and CLI](#run-via-api-and-cli)
- [Fetch results](#fetch-results)
- [Billing and limits](#billing-and-limits)
- [FAQ and troubleshooting](#faq-and-troubleshooting)

### What it does

Point the actor at an Idealista search results URL (the most precise option: apply any filters you like on the site, then copy the URL), or give it a location slug and an operation, or a list of individual listing URLs. It paginates the search, collects every property, and writes one normalized record per listing to the run dataset. Each listing comes back with its price, price per m2, rooms, size in m2, floor, detected property type, the private-owner vs agency signal, the agency name and the main image.

Two optional add-ons enrich each listing further:

- **Contact and full detail enrichment** opens each listing page and adds geo coordinates, the complete feature list, energy certificate, bathroom count, every image, the full description, the ad update date, the agency profile and a phone when the page shows one. This is the data most buyers and analysts want. It is off by default and charged only when real detail is returned.
- **AI listing summary** produces buyer-facing highlights, a condition assessment, the ideal target buyer and a price-per-m2 value assessment. Off by default, charged only when a usable summary is returned.

A standout field is `ownerDirect`: it flags listings posted by a private owner (particular) rather than an agency, so you can target owner-direct deals that competitors do not surface. Missing values are returned as `null`, never invented. Anti-bot handling is fully internal, so you do not configure proxies or supply any login.

### Quickstart

Open the actor, paste this into the input, and press Run. It returns 10 properties for sale in Madrid.

```json
{
  "startUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
  "maxResults": 10
}
```

To get geo, full features, energy rating and an AI summary, add the two add-ons (a paid Apify plan is required for add-ons):

```json
{
  "startUrl": "https://www.idealista.com/alquiler-viviendas/barcelona-barcelona/",
  "maxResults": 50,
  "minPrice": 900,
  "maxPrice": 2000,
  "minRooms": 2,
  "contactDetails": true,
  "aiListingSummary": true
}
```

### Input reference

| Field | Type | Required | Example | Description |
|---|---|---|---|---|
| `startUrl` | string | one of these | `https://www.idealista.com/venta-viviendas/madrid-madrid/` | An Idealista search results URL. The most precise way to target listings; pagination is followed automatically. |
| `location` | string | one of these | `barcelona-barcelona` | Convenience alternative to `startUrl`: an Idealista location slug, combined with `operation` to build the search. Ignored when `startUrl` is set. |
| `operation` | enum | no | `venta` | `venta` (buy) or `alquiler` (rent). Used with `location`. |
| `propertyType` | enum | no | `piso` | Keep only this type: `piso`, `casa`, `chalet`, `atico`, `duplex`, `estudio`, `apartamento`, `loft`. Empty for all. |
| `minPrice` | integer | no | `900` | Keep only listings priced at or above this amount in euros. |
| `maxPrice` | integer | no | `2000` | Keep only listings priced at or below this amount in euros. |
| `minRooms` | integer | no | `2` | Keep only listings with at least this many rooms. |
| `listingUrls` | array of strings | one of these | `["https://www.idealista.com/inmueble/112153132/"]` | Individual listing URLs to scrape directly with full detail. |
| `maxResults` | integer | no | `10` | Maximum listings to collect across the whole run. Free plans are capped at 10. |
| `contactDetails` | boolean | no | `false` | Paid add-on, off by default. Fetch each listing page for geo, full features, energy rating, bathrooms, all images, full description, agency profile and phone. Charged only when real detail is returned. |
| `aiListingSummary` | boolean | no | `false` | Paid add-on, off by default. AI highlights, condition, target buyer and price-per-m2 assessment. Charged only when a usable summary is returned. |

Provide at least a `startUrl`, a `location`, or one or more `listingUrls`. The add-ons are disabled on free Apify plans.

### Output reference

One dataset item per listing. Types: `string`, `number`, `integer`, `boolean`, `string[]`, or `null` when a value is absent.

| Field | Type | Description |
|---|---|---|
| `listingId` | string | Idealista listing id. |
| `title` | string | Listing title. |
| `listingUrl` | string | Full listing page URL. |
| `operation` | string | `venta` (sale) or `alquiler` (rent). |
| `propertyType` | string | Detected property type (`piso`, `casa`, `chalet`, `atico`, and so on). |
| `priceAmount` | integer | Price in euros. |
| `priceCurrency` | string | Always `EUR`. |
| `pricePerM2` | integer | Price per square metre in euros, when shown. |
| `rooms` | integer | Number of rooms (habitaciones). |
| `bathrooms` | integer | Number of bathrooms (detail add-on). |
| `sizeM2` | integer | Built size in square metres. |
| `floor` | string | Floor or storey text, for example `4ª planta exterior con ascensor`. |
| `latitude` | number | Latitude (detail add-on). |
| `longitude` | number | Longitude (detail add-on). |
| `locationText` | string | Neighborhood and city text (detail add-on). |
| `ownerDirect` | boolean | `true` when listed by a private owner, not an agency. |
| `isProfessional` | boolean | `true` when listed by a professional agency. |
| `agencyName` | string | Agency or advertiser name. |
| `agencySlug` | string | Agency profile slug (detail add-on). |
| `phone` | string | Contact phone when the page shows one (detail add-on). |
| `energyCertificate` | string | Energy certificate rating A to G (detail add-on). |
| `features` | string\[] | Full feature list such as terraza, ascensor, aire acondicionado (detail add-on). |
| `featureCount` | integer | Number of features captured (detail add-on). |
| `descriptionSnippet` | string | Short description from the search card. |
| `description` | string | Full description (detail add-on). |
| `image` | string | First listing image URL. |
| `images` | string\[] | All listing image URLs (detail add-on). |
| `imageCount` | integer | Number of images captured (detail add-on). |
| `publishedDate` | string | Ad updated date (detail add-on). |
| `aiHighlights` | string\[] | AI buyer-facing highlights (AI add-on). |
| `aiCondition` | string | AI condition assessment (AI add-on). |
| `aiTargetBuyer` | string | AI ideal target buyer (AI add-on). |
| `aiPricePerM2Assessment` | string | AI price-per-m2 value assessment (AI add-on). |
| `searchUrl` | string | Search URL that produced this listing. |
| `source` | string | Always `idealista.com`. |
| `observedAt` | string | ISO 8601 timestamp when the record was collected. |
| `error` | string | `null` on success. On a failed run a single item with a populated `error` field is written instead. |

### Run via API and CLI

Start a run and read the dataset. Replace `<TOKEN>` with your Apify API token.

Run synchronously and get dataset items in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~idealista-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"startUrl":"https://www.idealista.com/venta-viviendas/madrid-madrid/","maxResults":25}'
```

Start a run asynchronously with the paid add-ons:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~idealista-scraper/runs?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"startUrl":"https://www.idealista.com/alquiler-viviendas/valencia-valencia/","maxResults":100,"contactDetails":true,"aiListingSummary":true}'
```

Apify CLI:

```bash
apify call scrapers_lat/idealista-scraper \
  --input '{"location":"sevilla-sevilla","operation":"venta","maxResults":50,"minRooms":3}'
```

### Fetch results

Every run writes to a dataset. Fetch items as JSON, CSV, or Excel by changing `format`:

```bash
## JSON
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=json"

## CSV
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"

## Paginate large datasets
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&offset=1000&limit=1000"
```

`<DATASET_ID>` is returned as `defaultDatasetId` in the run object. Use `offset` and `limit` to page through large result sets.

### Billing and limits

- **Pay per result.** You are charged one `result` event per listing returned. A one-time `actor-start` event is charged when a run begins.
- **Add-ons are opt-in.** Contact and full detail enrichment (`contact_details`) and the AI summary (`ai_listing_summary`) are off by default. Each is charged only when it produces data: `contact_details` when real detail is returned, `ai_listing_summary` when the AI returns a usable summary. Both are disabled on free Apify plans.
- **No charge on failure.** If a run errors or matches nothing, the actor writes a single item with a populated `error` field and does not charge `result` or any add-on. Empty runs cost nothing.
- **Spend cap respected.** Set `maxTotalChargeUsd` on the run; once reached, the actor stops emitting and charging further billable results.
- **Free Apify plans** are capped at 10 listings per run and cannot use the paid add-ons. Upgrade for higher `maxResults`.
- **Tiered pricing.** Per-event prices step down across Apify plan tiers. See the [pricing tab](https://apify.com/scrapers_lat/idealista-scraper/pricing) for the current rates.

### FAQ and troubleshooting

**A run returned 0 listings. Why?**
The search URL or location matched nothing, or the location slug was not recognized. Copy a working search URL from your browser, or use the `provincia-municipio` slug format such as `madrid-madrid`. Zero-result runs are not charged.

**How do I filter exactly like on the site?**
Apply your filters on idealista.com, then paste the resulting URL into `startUrl`. The actor also applies `minPrice`, `maxPrice`, `minRooms` and `propertyType` on top, so you can combine a broad URL with precise limits.

**How do I find owner-direct (particular) listings?**
Every record includes `ownerDirect`. Filter the output for `ownerDirect: true` to get listings posted by private owners rather than agencies.

**Why are geo, features and energy rating empty on some records?**
Those fields come from the detail page and are only filled when `contactDetails` is enabled. Without the add-on you still get price, price per m2, rooms, size, floor, type, the owner-direct signal and the agency name from the search results.

**Why is `phone` empty?**
Idealista often hides the contact phone behind a click, so it is not always present in the page. When it is shown, the detail add-on captures it. Otherwise the agency name and profile let you reach the advertiser.

**Do I need a proxy or an Idealista login?**
No. Anti-bot handling is fully internal. You never configure a proxy or supply any cookies or credentials.

**Is this an official Idealista tool?**
No. This actor is independent and not affiliated with Idealista. It reads only data that is publicly visible on Idealista search and listing pages.

### Related scrapers

- [Adondevivir Scraper](https://apify.com/scrapers_lat/adondevivir-scraper): real estate listings for Latin America.
- [Real estate and lead scrapers at scrapers.lat](https://scrapers.lat): property and business data across platforms.

### More scrapers at scrapers.lat

Built and maintained by [scrapers.lat](https://scrapers.lat), where we publish scrapers for US, European and Latin American public platforms: company registries, government data, finance, real estate, e-commerce and more. Browse the catalog or request a custom scraper at [scrapers.lat](https://scrapers.lat).

***

> Independent tool, not affiliated with Idealista. Accesses only publicly available Idealista data. Use in accordance with Idealista's terms of service.

# Actor input Schema

## `startUrl` (type: `string`):

An Idealista search results URL to scrape (copy it from your browser after applying filters on idealista.com), for example https://www.idealista.com/venta-viviendas/madrid-madrid/. All matching listings are collected, following pagination. This is the most precise way to target results.

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

Optional convenience alternative to Search URL: an Idealista location slug such as madrid-madrid, barcelona-barcelona or valencia-valencia. Combined with Operation to build the search. Ignored when Search URL is set.

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

Buy (venta) or rent (alquiler). Used with Location to build the search URL.

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

Only keep listings of this property type. Leave empty for all types.

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

Only keep listings priced at or above this amount in euros. Leave empty for no minimum.

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

Only keep listings priced at or below this amount in euros. Leave empty for no maximum.

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

Only keep listings with at least this many rooms (habitaciones). Leave empty for no minimum.

## `listingUrls` (type: `array`):

Optional list of individual Idealista listing URLs (https://www.idealista.com/inmueble/<id>/) to scrape directly with full detail (features, geo, agency, full description).

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

Maximum number of listings to collect across the whole run. Free Apify plans are capped at 10 per run.

## `contactDetails` (type: `boolean`):

Fetch each listing detail page to add the full feature list, geo coordinates, energy certificate, agency name, owner-direct signal, full description and phone when shown. Charged only when real detail is returned. Disabled on free plans.

## `aiListingSummary` (type: `boolean`):

Use AI to produce buyer-facing highlights, a condition assessment, the ideal target buyer and a price-per-m2 value assessment for each listing. Charged only when a usable summary is returned. Disabled on free plans.

## Actor input object example

```json
{
  "startUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
  "operation": "venta",
  "propertyType": "",
  "listingUrls": [],
  "maxResults": 10,
  "contactDetails": false,
  "aiListingSummary": false
}
```

# Actor output Schema

## `results` (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 = {
    "startUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers_lat/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 = {
    "startUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapers_lat/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 '{
  "startUrl": "https://www.idealista.com/venta-viviendas/madrid-madrid/",
  "maxResults": 10
}' |
apify call scrapers_lat/idealista-scraper --silent --output-dataset

```

## MCP server setup

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