# idealista Listing Lookup — Spain Real Estate API (`accountable_eel/idealista-listing-lookup`) Actor

Look up any idealista.com property listing: price, price per m², size, rooms, floor, sale/rent, property type, and neighbourhood. Uses a real browser session through an unblocking proxy to reliably get past bot protection. Pay only for listings that resolve.

- **URL**: https://apify.com/accountable\_eel/idealista-listing-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** Real estate, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $9.75 / 1,000 successful lookups

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/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 Listing Lookup — Price, Size & Features API

Paste a list of [idealista](https://www.idealista.com) property listing URLs and get structured
data back for each one — price, price per m², size, rooms, floor, neighbourhood, city, property
type, sale-or-rent, and the listing's feature tags. idealista is protected by DataDome, so this
actor routes each lookup through a real browser session on Apify's UNBLOCKER proxy group to get
past the challenge that blocks plain HTTP requests. Covers idealista's Spanish, Portuguese and
Italian sites.

### Who it's for

The accountable\_eel catalogue also covers single-listing lookups on marketplaces that don't
publish an open API. Each actor takes a list of listing URLs and returns one flat,
stably-named row per input — price, size, condition, location, seller signal — read from the
listing page itself rather than from CSS selectors that move with every redesign. Pricing is
pay-per-event and per-listing: you pay for a listing that actually resolved, and nothing for a
removed listing, a 404, or a page with no property data. No seat licence, no monthly minimum,
no credit system to decode. This one covers idealista, the dominant property portal in Spain,
Portugal and Italy — where the hard part isn't the parsing, it's getting past DataDome at all.

### Why this one

- **It actually gets past DataDome.** A plain residential proxy with browser-like headers gets
  a block page. This routes through Apify's UNBLOCKER proxy group, which defeats the challenge.
- **You don't pay to find out "gone."** A removed listing, an invalid URL or a page without
  property data comes back `found: false` and is never billed.
- **Price per m² comes computed.** `pricePerSqm` is parsed from the listing rather than left
  for you to derive from `price` and `sizeSqm`, which are also both returned.
- **Three markets, one actor.** Spanish, Portuguese and Italian idealista listings all resolve
  through the same lookup.
- **Bare IDs or full URLs.** Pass a full listing URL or just the numeric listing id.

### What you get

One row per input listing. Every field below is stably named and won't be renamed between runs.

| Field | Type / format | Description |
|---|---|---|
| `query` | text | The listing URL or id exactly as submitted. |
| `found` | boolean | Whether the page returned usable property data. Gates billing — `false` rows are never charged. |
| `scrapedAt` | date (ISO 8601) | When the listing was read. |
| `data.title` | text | Listing headline as shown on idealista. |
| `data.listingId` | text | idealista's numeric listing id. |
| `data.propertyType` | text | Property type as idealista classifies it — flat, house, and so on. |
| `data.operation` | text | Whether the listing is a sale or a rental. |
| `data.price` | number | Asking price or monthly rent, as a number. |
| `data.currency` | text | Always `EUR` across all three markets. |
| `data.pricePerSqm` | number | Price per square metre, as published on the listing. |
| `data.sizeSqm` | number | Floor area in square metres. |
| `data.rooms` | number | Room count as idealista reports it. |
| `data.floorInfo` | text | Floor and lift information, as free text. |
| `data.neighbourhood` | text | Neighbourhood or district. |
| `data.city` | text | City the listing sits in. |
| `data.features` | array | Feature tags from the listing — terrace, parking, air conditioning, and similar. |
| `data.url` | link | The resolved listing URL. |

`floorInfo` and `features` are free-text as idealista publishes them, and they're published in
the listing's own language — Spanish, Portuguese or Italian depending on the site. Normalize
downstream if you're mixing markets in one table.

### Price

$9.75 per 1,000 resolved listings, plus a $0.0507 start fee per run. A removed listing, an
invalid URL, or a page without property data is never charged.

This is materially more expensive per row than the bulk idealista scrapers on the Store, and
the reason is architectural: every lookup here is a full headless browser session through
UNBLOCKER, billed by compute time, because that's what clears DataDome on a single listing
page. If you need thousands of listings from search results, a crawler that amortizes one
session across many listings will be cheaper. If you have specific listing URLs and need them
resolved reliably, this is built for that. The start fee is per run, not per listing, so batch
your lookups rather than running them one at a time.

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `listingUrls` field
   is pre-filled with a working example.
2. **Via the API.** Call it with a POST request once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~idealista-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"listingUrls":["https://www.idealista.com/inmueble/12345678/"]}'
   ```
3. **On a schedule.** Save the actor as an Apify **Task**, then add a **Schedule** so it runs on
   its own.

**Common ways teams use this:**

- **Track asking prices** across a watchlist of listings by re-running on a schedule and
  diffing `price`.
- **Benchmark price per m²** across neighbourhoods using `pricePerSqm`, `city` and
  `neighbourhood` together.
- **Verify a listing is still live** before sending it to a client or publishing it.
- **Enrich a property shortlist** with size, rooms and feature tags from a list of URLs you
  already have.
- **Compare sale versus rental yields** in an area by running both and grouping on `operation`.

### Input

```json
{
  "listingUrls": [
    "https://www.idealista.com/inmueble/110910838/",
    "https://www.idealista.com/inmueble/106303416/",
    "https://www.idealista.com/inmueble/111323975/",
    "https://www.idealista.com/inmueble/108919870/",
    "https://www.idealista.com/inmueble/109266379/",
    "https://www.idealista.com/inmueble/110784153/",
    "https://www.idealista.com/inmueble/110697237/",
    "https://www.idealista.com/inmueble/111298148/"
  ]
}
```

One idealista.com property listing URL or bare numeric listing ID per line. Accepted formats: https://www.idealista.com/inmueble/112153132/, 112153132.

```json
{
  "listingUrls": [
    "https://www.idealista.com/inmueble/12345678/",
    "https://www.idealista.pt/imovel/23456789/"
  ],
  "maxConcurrency": 2
}
```

`listingUrls` is your list of idealista property listing URLs, or bare numeric listing ids.
Spanish (`idealista.com`), Portuguese (`idealista.pt`) and Italian (`idealista.it`) listings all
work and can be mixed in one run. `maxConcurrency` controls parallel browser sessions and
defaults to 2 — keep it low, since each session is a full headless browser through UNBLOCKER
and higher concurrency multiplies compute cost quickly rather than saving money.

### Sample output

| query | found | status | scrapedAt |
| --- | --- | --- | --- |
| https://www.idealista.com/inmueble/106303416/ | false | OK | 2026-08-20T13:24:17.235Z |

A single row reads like this:

```json
{
  "query": "https://www.idealista.com/inmueble/12345678/",
  "found": true,
  "data": {
    "title": "Piso en venta en Malasaña",
    "listingId": "12345678",
    "propertyType": "Piso",
    "operation": "venta",
    "price": 485000,
    "currency": "EUR",
    "pricePerSqm": 6928,
    "sizeSqm": 70,
    "rooms": 2,
    "floorInfo": "Planta 3ª exterior con ascensor",
    "neighbourhood": "Universidad",
    "city": "Madrid",
    "features": ["Terraza", "Aire acondicionado"],
    "url": "https://www.idealista.com/inmueble/12345678/"
  },
  "scrapedAt": "2026-08-20T12:00:00.000Z"
}
```

A listing that no longer resolves comes back with no `data`, and is never charged:

```json
{
  "query": "https://www.idealista.com/inmueble/00000000/",
  "found": false,
  "scrapedAt": "2026-08-20T12:00:04.000Z"
}
```

Miss rows are written so you can see exactly which URLs failed rather than diffing your input
list against the output.

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it from a script, a workflow tool, or an AI
agent, with no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~idealista-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"listingUrls":["https://www.idealista.com/inmueble/12345678/"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL
`https://api.apify.com/v2/acts/accountable_eel~idealista-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`,
Body Content Type `JSON`, JSON Body `{"listingUrls":["<listing URL>"]}`.

**Clay.** Add an "HTTP API" column: Method `POST`, same URL, Body
`{"listingUrls":["{{value}}"]}`, mapping the row's listing URL into the array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "idealista
Listing Lookup | Apify" — the agent will find and run this actor.

### Tips

- **Batch your listings into one run.** The start fee is charged per run, not per listing, so
  one run of 200 listings costs one start fee and 200 runs of one listing cost 200.
- **Keep `maxConcurrency` at 2–3.** Each session is a full browser through UNBLOCKER, billed by
  compute time. Raising it makes a batch finish sooner, not cost less.
- **Normalize `features` before comparing across markets.** The tags come back in the listing's
  own language, so a Spanish "Terraza" and an Italian "Terrazzo" won't group on their own.
- **Use `pricePerSqm` rather than deriving it.** It's taken from the listing, so it matches what
  a buyer sees even where rounding differs from `price ÷ sizeSqm`.
- **Re-run on a schedule and diff `price`** to catch reductions across a watchlist.

### vs. alternatives

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** (`idealista-listing-lookup`) | $9.75 per 1,000 resolved listings, $0.0507 actor start, nothing for a removed or invalid listing | Structured price, price per m², size, rooms, location and feature tags for listing URLs you already have, across ES/PT/IT | The most expensive per row of the four, because every lookup is a real browser session through UNBLOCKER. It also won't search or crawl — you supply the URLs. |
| **igolaizola/idealista-scraper** (2,041 users) | $0.0009 per result, $0.0009 per detail fetch, $0.005 start | The category leader: searches by location, filters, and crawls listings in bulk across Spain, Italy and Portugal | Roughly a tenth of the price per row and it discovers listings rather than requiring URLs. If you want volume from search results, use this. |
| **dz\_omar/idealista-scraper-api** (1,221 users) | $0.003 per property, $0.0045 per detailed property, $0.01 start | Bulk property extraction with a detailed tier | Around a third of the price per row, also crawler-shaped rather than lookup-shaped. |
| **Doing it yourself** | Your time + a headless browser fleet, plus solving DataDome, its retries and its transient failures | The same data | This actor absorbs the UNBLOCKER routing, the retry logic and the parsing. DataDome is the whole difficulty; everything after it is straightforward. |

Competitor prices are their published FREE-tier list prices as of August 2026 and are not
tracked here — check the actor's own page before relying on the comparison.

### FAQ

**What counts as "found"?**
The listing page must load past DataDome and contain usable property data. Removed listings,
404s and pages without that data return `found: false` and are never charged.

**Why does this need a real browser instead of a plain HTTP request?**
idealista is protected by DataDome. A plain residential proxy with browser-like headers gets the
same block page as a bare request — this routes through Apify's UNBLOCKER proxy group
specifically because it clears that challenge.

**Why is it more expensive than the other idealista actors?**
Because it's a different shape. Bulk crawlers amortize one browser session across many listings
found in search results. This resolves specific listing URLs one at a time, and each needs its
own UNBLOCKER session. For volume from search, a crawler is cheaper; for reliable resolution of
URLs you already hold, this is what it costs.

**Can I use search-result or map pages instead of listing URLs?**
No. This actor takes individual property listing pages. If you need to discover listings from a
search, a crawler-shaped actor is the right tool.

**Does it work on idealista.pt and idealista.it?**
Yes. All three sites resolve through the same lookup, and you can mix them in one run.
`currency` is `EUR` throughout.

**Why are `features` and `floorInfo` not in English?**
They're free text exactly as idealista publishes them, in the listing's own language.
Translating them would mean guessing, so they're passed through unchanged.

**Is the price live or cached?**
Live. Every row is a fresh page load at run time — nothing is stored between runs.

### Related actors

- [Allegro Listing Lookup](https://apify.com/accountable_eel/allegro-listing-lookup) — the same
  listing-lookup shape for Allegro.pl marketplace listings.
- [Shopify Store Lookup](https://apify.com/accountable_eel/shopify-store-lookup) — live product
  catalogues for merchants running their own storefront.
- [Open Food Facts Product Lookup](https://apify.com/accountable_eel/openfoodfacts-product-lookup) —
  product data by barcode.

### En español · Em português · In italiano

**ES —** Extrae datos estructurados de cualquier anuncio de idealista a partir de su URL:
precio, precio por m², superficie, habitaciones, planta, barrio, ciudad y características. Solo
pagas por los anuncios que se resuelven; los anuncios retirados son gratuitos.
*Palabras clave: API idealista, scraper idealista, precio por metro cuadrado, datos
inmobiliarios, seguimiento de precios de vivienda.*

**PT —** Extrai dados estruturados de qualquer anúncio do idealista a partir do URL: preço,
preço por m², área, quartos, andar, bairro, cidade e características. Paga apenas pelos
anúncios encontrados.
*Palavras-chave: API idealista, scraper idealista, preço por metro quadrado, dados imobiliários.*

**IT —** Estrae dati strutturati da qualsiasi annuncio idealista partendo dall'URL: prezzo,
prezzo al m², superficie, locali, piano, quartiere, città e caratteristiche. Paghi solo per gli
annunci effettivamente trovati.
*Parole chiave: API idealista, scraper idealista, prezzo al metro quadro, dati immobiliari.*

# Actor input Schema

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

One idealista.com property listing URL or bare numeric listing ID per line. Accepted formats: https://www.idealista.com/inmueble/112153132/, 112153132. You're only charged for the ones we actually find — a miss costs nothing.

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

Parallel browser sessions. Keep low — each session is a full headless browser through UNBLOCKER, more sessions at once multiplies compute cost fast.

## Actor input object example

```json
{
  "listingUrls": [
    "https://www.idealista.com/inmueble/110697237/",
    "https://www.idealista.com/inmueble/110784153/"
  ],
  "maxConcurrency": 2
}
```

# 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 = {
    "listingUrls": [
        "https://www.idealista.com/inmueble/110697237/",
        "https://www.idealista.com/inmueble/110784153/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/idealista-listing-lookup").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 = { "listingUrls": [
        "https://www.idealista.com/inmueble/110697237/",
        "https://www.idealista.com/inmueble/110784153/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/idealista-listing-lookup").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 '{
  "listingUrls": [
    "https://www.idealista.com/inmueble/110697237/",
    "https://www.idealista.com/inmueble/110784153/"
  ]
}' |
apify call accountable_eel/idealista-listing-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/idealista-listing-lookup"
        }
    }
}

```

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/1ZI8NszTaCdsSLRD7/builds/buRmz7TKYrYhFV6Fr/openapi.json
