# Idealista Scraper - Spain, Italy & Portugal Real Estate Data (`ahmed_jasarevic/idealista-property-scraper`) Actor

Scrape property listings from Idealista (idealista.com, .it, .pt): price, price/m², size, rooms, bathrooms, floor, GPS coordinates, energy rating, description, photos and agency contacts.

- **URL**: https://apify.com/ahmed\_jasarevic/idealista-property-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.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.

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 Property Scraper — Spain, Italy & Portugal Real Estate Listings

Scrape **Idealista** property listings from **idealista.com** (Spain), **idealista.it** (Italy) and **idealista.pt** (Portugal) in one run. Extract the full listing record: **title, price, price per m², size, rooms, bathrooms, floor, location, neighborhood, district, city, GPS coordinates, energy rating, year built, price history, description, photos, and agency contact details** (name, phone, website, address).

Built on the Apify platform — get results as a clean JSON/CSV/Excel dataset via API, schedule recurring runs, and integrate with any workflow.

### Why use this actor?

- **One actor, three markets** — Spain, Italy and Portugal share the same Idealista layout; this actor handles all three with a single input.
- **Investor-grade data** — price history, price per m², community fees, property tax and energy rating are exactly what market analysts and investors need.
- **Agency lead generation** — every record includes the listing agency's name, phone, website and address, perfect for real estate agencies, relocation services and proptech startups.
- **Hybrid browser + HTTP engine** — a stealthy **Camoufox** browser (anti-detect Firefox) solves Idealista's **DataDome** challenge once per sticky residential IP. The harvested `datadome` cookie, exact User-Agent and Accept-Language are then replayed by **Impit** clients (real Firefox TLS/HTTP2 fingerprints) over plain HTTP — roughly **20x faster** than browser-per-page scraping at a fraction of the compute cost.
- **Self-healing sessions** — if DataDome blocks or rate-limits a session, it is retired automatically, a fresh proxy session is warmed in the browser, and the affected requests are retried — no manual intervention.
- **Safe by default** — hard caps on pages, items and browser launches; free users get a 10-listing preview.

### How to use

1. Open the actor on Apify and click **Start**.
2. Pick the **country** (Spain / Italy / Portugal), **operation** (sale / rent) and **property type**.
3. Optionally enter a **location slug** (e.g. `madrid`, `barcelona`, `milano`, `roma`, `lisboa`, `porto`) or paste **custom start URLs**.
4. Set **max listings** and **max search pages**, then run.
5. Download the dataset as JSON, HTML, CSV or Excel, or pull it via the Apify API.

### Input

| Field            | Type   | Description                                                                                        |
| ---------------- | ------ | -------------------------------------------------------------------------------------------------- |
| `country`        | select | `spain` (idealista.com), `italy` (idealista.it) or `portugal` (idealista.pt)                       |
| `operation`      | select | `sale` or `rent`                                                                                   |
| `propertyType`   | select | homes, apartments, houses/villas, offices, shops/premises, garages, land                           |
| `location`       | string | City/district SEO slug, e.g. `madrid`, `milano`, `lisboa` (empty = whole country)                  |
| `maxItems`       | number | Max listings to scrape (default 50)                                                                |
| `maxPages`       | number | Max search result pages to crawl (default 5, ~30 listings/page)                                    |
| `sessions`       | number | Browser-warmed proxy sessions (default 2, max 8)                                                   |
| `maxConcurrency` | number | Parallel HTTP requests across sessions (default 8, max 16)                                         |
| `requestDelayMs` | number | Min delay between requests on the same session (default 900 ms)                                    |
| `fetchDetails`   | bool   | Visit each listing's detail page for the full record (default ON; OFF = much faster, fewer fields) |
| `startUrls`      | array  | Custom Idealista search or listing URLs (overrides the fields above)                               |
| `debugSaveHtml`  | bool   | Save raw HTML of key pages to the key-value store for debugging                                    |
| `proxy`          | proxy  | Apify proxy config; **Residential** group recommended                                              |

Example input:

```json
{
    "country": "spain",
    "operation": "sale",
    "propertyType": "apartments",
    "location": "madrid",
    "maxItems": 100,
    "maxPages": 5,
    "sessions": 3,
    "maxConcurrency": 8,
    "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Output

Each dataset item is one listing. Example:

```json
{
    "id": "123456789",
    "url": "https://www.idealista.com/inmueble/123456789/",
    "title": "Piso en calle Gran Vía, Madrid Capital",
    "price": 350000,
    "pricePerSqm": 2917,
    "currency": "EUR",
    "size": 120,
    "rooms": 3,
    "bathrooms": 2,
    "floor": "2ª planta",
    "location": "Calle Gran Vía, Madrid Capital",
    "neighborhood": "Gran Vía",
    "district": "Centro",
    "city": "Madrid Capital",
    "province": "Madrid",
    "country": "Spain",
    "latitude": 40.4203,
    "longitude": -3.7058,
    "energyRating": "E",
    "yearBuilt": 1960,
    "priceHistory": [{ "date": "2025-06-01", "price": 365000 }],
    "description": "Piso luminoso en pleno centro...",
    "photos": ["https://img3.idealista.com/foto/123456789.jpg"],
    "agency": {
        "name": "Inmobiliaria Ejemplo",
        "phone": "910000000",
        "website": "https://www.inmobiliaria-ejemplo.com",
        "address": "Calle Mayor 1, Madrid"
    },
    "features": { "rooms": "3", "bathrooms": "2", "size": "120 m²", "condition": "Buen estado" }
}
```

You can download the dataset in various formats such as **JSON, HTML, CSV, or Excel**.

### Data table

| Field                                                                      | Description                                                              |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `id` / `url`                                                               | Listing ID and canonical URL                                             |
| `title`                                                                    | Listing headline                                                         |
| `price` / `pricePerSqm` / `currency`                                       | Price, price per m², currency                                            |
| `size` / `rooms` / `bathrooms` / `floor`                                   | Property dimensions                                                      |
| `location` / `neighborhood` / `district` / `city` / `province` / `country` | Full location hierarchy                                                  |
| `latitude` / `longitude`                                                   | GPS coordinates                                                          |
| `energyRating` / `yearBuilt`                                               | Energy certificate and construction year                                 |
| `priceHistory`                                                             | Array of `{ date, price }` entries                                       |
| `description`                                                              | Full listing description                                                 |
| `photos`                                                                   | Full-resolution photo URLs                                               |
| `agency`                                                                   | `{ name, phone, website, address }`                                      |
| `features`                                                                 | All feature-item key/value pairs (condition, orientation, heating, etc.) |
| `reference` / `communityFees` / `propertyTax`                              | Advert reference and recurring costs                                     |

### How much does it cost to scrape Idealista?

- **Free tier**: every run scrapes up to **10 listings** at no charge.
- **Paid runs**: billed by Apify compute units. The browser is only used for the short DataDome-solving step per session; everything else is fast HTTP, so a run of ~100 listings typically costs a few hundredths of a dollar in compute. Residential proxy traffic is billed per GB by Apify — keep `maxItems`/`maxPages` modest to control cost.
- Runs are bounded: `maxItems`, `maxPages`, a hard cap on browser launches, and per-session request pacing mean a run can never spin out of control.

### Tips

- **Use Residential proxy** — Idealista's DataDome protection blocks datacenter IPs. The actor defaults to the `RESIDENTIAL` Apify proxy group. Each new IP gets its DataDome challenge solved once in the Camoufox browser; when a cookie expires or a block is detected, that session is retired and a fresh one is warmed automatically.
- **Empty location = whole country** — with no `location`, Idealista serves a landing page without a listing grid; the actor automatically discovers and crawls the zone search pages linked from it. For targeted runs, set a city/province slug (e.g. `madrid`) for maximum speed.
- **Tune speed vs. stealth** — more `sessions` and higher `maxConcurrency` finish faster but spread more load; if you see frequent "Session blocked" warnings, increase `requestDelayMs` or lower `maxConcurrency`.
- **Tune speed vs. richness** — with `fetchDetails: false` the actor extracts ~30 listings per search-page request straight from the result cards (title, price, size, rooms, floor, description snippet, agency, photos): 50 listings in a couple of requests instead of 50+. Turn it on (default) for the full record including GPS coordinates, energy rating and complete descriptions.
- **Start small** — test with `maxItems: 10` on one city before scaling to a full country crawl.
- **Custom URLs** — you can paste any Idealista search URL (e.g. a filtered search with price/rooms constraints) into `startUrls` and the actor will follow it and its pagination.
- **Debugging** — enable `debugSaveHtml` to store the raw HTML of the first search page in the run's key-value store.
- **Schedule it** — use Apify's scheduler to track price changes over time; combine with the `priceHistory` field for market analysis.

### FAQ, disclaimers and support

- **Is scraping Idealista legal?** Scraping publicly available data may be subject to the website's Terms of Service and local law. You are responsible for how you use the data. This actor respects `robots.txt` and rate limits.
- **Why do some fields come back empty?** Idealista hides some data (e.g. phone numbers behind a click, price history only on some listings). The actor extracts everything that is publicly visible on the page.
- **Idealista blocks my run** — make sure Residential proxy is enabled; if you still see blocks, the site may have tightened protection — open an issue and we'll update the actor.
- **How does the DataDome bypass work?** Idealista server-renders every page, so all data (including JSON-LD) is in the raw HTML. DataDome serves a JS challenge to first-time visitors, which a pure HTTP client cannot execute — so the actor runs one Camoufox (anti-detect Firefox) visit per sticky residential IP to solve it, then harvests the `datadome` cookie together with the browser's exact User-Agent and Accept-Language. All subsequent requests on that IP go over plain HTTP through Impit, which reproduces Firefox's TLS and HTTP/2 fingerprints, so the traffic stays consistent with the browser that earned the cookie. Expired cookies and blocks are detected and re-solved automatically.
- **Need a custom version?** Contact us for tailored extraction, additional markets, or integration with your pipeline.

# Actor input Schema

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

Which Idealista site to scrape.

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

Sale or rent listings.

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

Category of property to scrape.

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

City, district or zone slug, e.g. 'madrid', 'barcelona', 'milano', 'roma', 'lisboa', 'porto'. Leave empty for the whole country.

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

Maximum number of listings to scrape.

## `maxPages` (type: `integer`):

Maximum number of search result pages to crawl (30 listings per page).

## `sessions` (type: `integer`):

Number of independent browser-warmed proxy sessions. Each session solves the DataDome challenge once and then serves fast HTTP requests from the same IP. 2 is a good balance; use 1 for cheapest runs.

## `maxConcurrency` (type: `integer`):

Upper bound on parallel HTTP requests across all sessions. Note: each session still sends one request at a time (human-like); this caps the total.

## `requestDelayMs` (type: `integer`):

Minimum delay between two requests on the same session. Keep >= 800 to avoid DataDome blocks; increase if sessions get blocked often.

## `reuseSessions` (type: `boolean`):

When ON (default), sessions solved by a previous run are saved and revalidated on startup - skipping the slow browser DataDome solve entirely when the sticky proxy IP is still alive. Turn OFF to always solve fresh.

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

Optional custom Idealista search or listing URLs. Overrides country/operation/propertyType/location.

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

When ON (default), visits every listing's detail page for the full record (GPS, energy rating, full description, all photos) - about 1 extra request per listing. When OFF, extracts listings directly from search pages (~30 per request): much faster, fewer fields.

## `proxy` (type: `object`):

Apify Proxy with Residential IPs is recommended to avoid blocking (Idealista uses DataDome anti-bot).

## Actor input object example

```json
{
  "country": "spain",
  "operation": "sale",
  "propertyType": "homes",
  "location": "madrid",
  "maxItems": 50,
  "maxPages": 5,
  "sessions": 2,
  "maxConcurrency": 8,
  "requestDelayMs": 900,
  "reuseSessions": true,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "sessions": 2,
    "maxConcurrency": 8,
    "requestDelayMs": 900,
    "reuseSessions": true,
    "fetchDetails": false,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/idealista-property-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 = {
    "sessions": 2,
    "maxConcurrency": 8,
    "requestDelayMs": 900,
    "reuseSessions": True,
    "fetchDetails": False,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/idealista-property-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 '{
  "sessions": 2,
  "maxConcurrency": 8,
  "requestDelayMs": 900,
  "reuseSessions": true,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ahmed_jasarevic/idealista-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/idealista-property-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/350Iw38ZM0QaaJxe6/builds/Zg7QAKHl0XytXdYfk/openapi.json
