Idealista Scraper - Property Listings, Prices & Contacts avatar

Idealista Scraper - Property Listings, Prices & Contacts

Pricing

from $1.00 / 1,000 results

Go to Apify Store
Idealista Scraper - Property Listings, Prices & Contacts

Idealista Scraper - Property Listings, Prices & Contacts

From $1/1K. Scrape Idealista properties across Spain, Italy, and Portugal. Extract 35+ fields including prices, sizes, rooms, coordinates, advertiser contacts, phone numbers, descriptions, and photos. Supports properties for sale, rent, and rooms.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

7

Total users

0

Monthly active users

2 days ago

Last modified

Share

Idealista Scraper: Spain, Italy and Portugal Property Listings

Idealista Scraper turns idealista into a clean property data feed across its three markets: idealista.com (Spain), idealista.it (Italy) and idealista.pt (Portugal). Search by location or paste any idealista search link, get price, size, rooms, energy rating, GPS coordinates, advertiser name and phone, full descriptions and deduplicated photo galleries, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Three markets, one actor. Spain, Italy and Portugal, selected per run in Search mode; URL mode detects the market automatically from each pasted link.
  • 50+ fields on full detail. Price per m2, energy rating, GPS coordinates, advertiser name, phone when the listing page shows it, construction year, the complete description and up to 40 deduplicated photos.
  • Two ways to search. Build a search from a location, operation and filters, or paste any idealista search URL directly. Multiple URLs and forward pagination are supported.
  • Buy, rent or room listings in every market, with idealista's own search filters in Search mode (price, size, bedrooms, bathrooms, property type, features, condition, freshness and sort order), built into the search itself so they work the same way across Spain, Italy and Portugal.
  • Detail enrichment on demand. Turn it off for a fast run with search-result fields only, or on for the full record, one extra page fetch per listing.
  • Built for schedules. Incremental mode returns only new, updated and reappeared listings on recurring runs, and a run that cannot reach the site fails loudly instead of returning an empty dataset.
  • Automatic connection retry. If a connection is refused, the actor retries with a different one before giving up, so a single flaky attempt doesn't end the run.

Use Cases

  • Real estate investors and flippers: track price drops and new listings across three markets to spot deals early.
  • Market researchers and analysts: build historical price-per-m2 and rent datasets by neighborhood and city.
  • Relocation and property agencies: aggregate cross-market listings into one feed for clients comparing Spain, Italy and Portugal.
  • Lead generation teams: capture advertiser names and phone numbers from professional listings for outreach.
  • Journalists and academics: monitor housing supply, price trends and listing turnover over time.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
id"00000001"
url"https://www.idealista.com/inmueble/00000001/"
market"ES" (also "IT", "PT")
operation"sale" (also "rent", "room")
title"Sample Flat in Example Street"
propertyType"flat" (inferred from the first word of the title, e.g. "Piso...")
price450000
priceText"450.000 EUR"
pricePerM24736 (when detail pages are fetched)
previousPrice / priceDropped480000 / true
size95.0
rooms3
bathrooms2 (when detail pages are fetched)
floor"3rd floor with lift"
hasLifttrue
condition"Second hand, good condition" (when detail pages are fetched)
constructionYear1985 (when detail pages are fetched)
energyConsumptionRating / energyEmissionsRating"D" / "D" (when detail pages are fetched)
neighborhood / city / province"Example District" / "Example City" / "Example Province" (when detail pages are fetched; province is omitted when the page shows none)
latitude / longitude40.0000 / -3.0000 (when detail pages are fetched)
advertiserName / phone"Sample Agency" / "+34 000 000 000" (when detail pages are fetched)
images / imageCount / imageTagslist of up to 40 photo URLs / 24 / [{"url": "...", "tag": "Cocina"}] (imageCount is the site's full total, images is capped at 40; imageTags is the room label idealista gives each photo that has one, in the site's own language (Spanish on .com, Italian on .it, Portuguese on .pt), so filter on Cocina, not Kitchen; all when detail pages are fetched)
tags["price drop"]
scrapedAt"2026-01-01T00:00:00.000000+00:00"
changeType"NEW" (Incremental mode only; also "UPDATED", "UNCHANGED", "REAPPEARED", "EXPIRED")

Feature flags such as hasTerrace, hasGarage, hasStorage, hasGarden, hasPool and hasAC appear only when idealista's own feature list confirms them (always true); their absence means the feature wasn't listed, not that it was confirmed absent. hasVideo, has3DTour, hasFloorPlan and hasHomeStaging, by contrast, are always present as true or false. isProfessionalAd is true for an agency or professional advertiser and false for a private owner; it comes from the result card, so it is present even when Fetch Detail Pages is off. In Incremental mode, records also carry changedFields (the list of fields that changed), firstSeenAt and lastSeenAt.

How to Use

  1. Pick a mode: Search by Location builds URLs for you, Direct URLs scrapes the idealista search links you paste.
  2. For Search mode, choose a market, an operation (buy, rent or room), one or more location slugs, and any filters (price, size, bedrooms, bathrooms, property types, must-have features, condition, freshness, sort order). For URL mode, paste one or more idealista search URLs.
  3. Set Max Listings and Max Pages Per Search to control run size and cost, and turn Fetch Detail Pages on or off depending on whether you need the full record.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search Spain (Madrid), buy, lean run:

{
"mode": "search",
"market": "es",
"operation": "sale",
"locations": ["madrid-madrid"],
"maxListings": 50,
"fetchDetails": false
}

Search with price and bedroom filters, full detail:

{
"mode": "search",
"market": "es",
"operation": "sale",
"locations": ["barcelona-barcelona"],
"minPrice": 200000,
"maxPrice": 500000,
"minBedrooms": 3,
"fetchDetails": true
}

Search Italy (rent in Rome):

{
"mode": "search",
"market": "it",
"operation": "rent",
"locations": ["roma-roma"],
"maxListings": 100
}

URL mode (paste idealista search links, multiple supported):

{
"mode": "url",
"urls": [
"https://www.idealista.com/venta-viviendas/madrid-madrid/",
"https://www.idealista.pt/comprar-casas/lisboa/"
],
"maxPages": 2,
"fetchDetails": true
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/idealista-scraper").call(run_input={
"mode": "search",
"market": "es",
"operation": "sale",
"locations": ["madrid-madrid"],
"maxListings": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/idealista-scraper').call({
mode: 'search',
market: 'es',
operation: 'sale',
locations: ['madrid-madrid'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Fetch Detail Pages and run limits

Max Pages Per Search and Max Listings bound how much of a search this actor scans, not how many rows are pushed. idealista serves at most about 60 pages (roughly 1,800 listings) per single search. Search-mode filters are added to the search itself, so idealista only returns matching listings and the pages read are spent on results you asked for; each result is also re-checked against your price, size and bedroom limits (on idealista.pt the bedroom limits are applied only through idealista's own T0 to T4+ buckets, see the bedroom rows in the input table). To pull more than 1,800 listings, narrow the search with filters or split it across several locations, or paste idealista search URLs (URL mode). Fetch Detail Pages controls whether the actor opens each listing's own page: on, you get the full record described above; off, you get the search-result fields only, for a faster and cheaper run.

If a run is close to its own platform time limit, the actor stops opening new detail pages and pushes the listing fields it already has for the remaining cards, rather than being cut off with nothing returned. The status message reports how many listings were affected this way.

Resume and recurring updates

Two different features, both off by default:

  • resumeFromRunId continues one specific interrupted or very large crawl. Paste a previous run ID or dataset ID and this run skips every listing already collected there, so you don't pay twice.
  • incrementalMode is for scheduling this actor daily or weekly against the same search. The actor remembers the previous run's listings itself, scoped to the search or URL and filter settings, or to a manual stateKey. Each listing gets a changeType of NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. By default only NEW, UPDATED and REAPPEARED listings are returned; turn on emitUnchanged or emitExpired to also get (and pay for) the rest.

A listing is UPDATED when any returned field differs from the last saved copy; only scrapedAt is always excluded, and ignoreFieldsForChanges excludes more (the saved copy is re-compared with the same ignore list, so changing it does not trigger a wave of UPDATED rows). EXPIRED is only produced once a run has fully scanned the tracked search from start to end, (a pasted URL that starts at page 2 or later never counts as a full scan), with emitExpired on and without resumeFromRunId; a run capped by maxListings or maxPages cannot prove a listing is gone, so it skips expiry detection that run and keeps the previous state as-is. REAPPEARED only ever appears for a listing that was previously marked EXPIRED and is then found again in a later run; with emitExpired left off, a listing never enters the EXPIRED state, so REAPPEARED does not occur either. resumeFromRunId and incrementalMode can be combined to bootstrap a new monitoring campaign from a previous large pull, but only on the first incremental run for a given state key; if that key already has tracked listings, the run fails fast rather than mixing baselines.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (Search by Location) or url (Direct URLs).
marketstringesMarket for Search mode: es, it, or pt. URL mode infers it per URL.
operationstringsalesale, rent, or room (Search mode only).
locationsarraynone (prefill: ["madrid-madrid"])idealista location slugs (Search mode only). Required if mode is search.
urlsarrayone example per supported URL shape (see below)idealista search URLs (URL mode only). Required if mode is url.
minPriceintegernoneMinimum price. Search mode only.
maxPriceintegernoneMaximum price. Search mode only.
minBedroomsintegernoneMinimum bedrooms. Search mode only. Italy counts rooms (locali). On idealista.pt it uses idealista's own T0 to T4+ buckets and is not re-checked per listing, because Portuguese result cards show no room count.
maxBedroomsintegernoneMaximum bedrooms. Search mode only. On idealista.pt it uses idealista's own T0 to T4+ buckets and is not re-checked per listing, because Portuguese result cards show no room count; the top bucket means T4 or more, so a limit of 4 or higher does not exclude larger homes there.
minSizeintegernoneMinimum built area in m2. Search mode only.
maxSizeintegernoneMaximum built area in m2. Search mode only.
bathroomsstringnone1, 2 or 3+ (idealista's own bathrooms filter). Search mode only.
propertyTypesarraynoneAny of flat, penthouse, duplex, loft, house. Search mode only.
featuresarraynoneListings that have every selected feature: elevator, parking, terrace, balcony, garden, pool, airConditioning, storage, wardrobes. Search mode only.
conditionsarraynoneAny of newBuild, good, toRenovate. Search mode only.
publishedWithinstringnone24h, 48h, week or month. idealista.com (Spain) only; ignored with a warning on Italy and Portugal. Search mode only.
sortBystringnone (idealista's relevance order)priceAsc, priceDesc, newest, pricePerSqmAsc, pricePerSqmDesc, sizeDesc, sizeAsc or priceDrops. With a listing cap, the sort decides which listings are collected first. Search mode only.
maxPagesinteger0Pages per search (30 listings per page). 0 means no limit of your own: the actor stops at idealista's own ceiling of 60 pages per search; a run is also bounded by Max Listings.
maxListingsinteger100Total listings scanned across all searches. 0 means unlimited.
maxConcurrencyinteger6Parallel detail-page fetches (1 to 12) when Fetch Detail Pages is on.
fetchDetailsbooleantrueOpen each listing's own page for coordinates, advertiser, phone, full description, photos, bathrooms, condition, orientation and heating.
proxyobjectnone (prefill: Apify Proxy, RESIDENTIAL group); the actor applies the same setup when this field is left outConnection settings. Residential proxy in the listing's country works best.
resumeFromRunIdstringnoneContinue one specific interrupted run: paste a previous run or dataset ID.
incrementalModebooleanfalseRecurring monitoring of the same search: only new, updated and reappeared listings are returned on later runs.
stateKeystringnoneName an Incremental mode monitoring campaign, or share state across differently configured runs.
emitUnchangedbooleanfalseIncremental mode: also return unchanged listings (extra rows, extra billing).
emitExpiredbooleanfalseIncremental mode: also return expired listings once a run fully scans the tracked search (extra rows, extra billing).
ignoreFieldsForChangesarraynoneIncremental mode: field names (or dotted paths such as coordinates.latitude) left out of change detection. They stay in the output but never make a listing UPDATED or appear in changedFields.
mcpConnectorsarraynoneOptional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstringnoneNotion connector only: page under which records are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"id": "00000001",
"url": "https://www.idealista.com/inmueble/00000001/",
"market": "ES",
"operation": "sale",
"title": "Piso en Calle Ejemplo",
"propertyType": "flat",
"price": 450000,
"priceText": "450.000 EUR",
"pricePerM2": 4737,
"previousPrice": 480000,
"priceDropped": true,
"currency": "EUR",
"size": 95.0,
"rooms": 3,
"bathrooms": 2,
"floor": "3rd floor with lift",
"hasLift": true,
"hasTerrace": true,
"hasHomeStaging": false,
"orientation": "South facing",
"heating": "Central heating",
"condition": "Second hand, good condition",
"constructionYear": 1985,
"energyConsumptionRating": "D",
"energyEmissionsRating": "D",
"reference": "REF-0001",
"lastUpdatedText": "Listing updated on 1 January",
"description": "Full advertiser description text appears here when fetchDetails is on.",
"latitude": 40.0000,
"longitude": -3.0000,
"address": "Example District, Example City",
"neighborhood": "Example District",
"city": "Example City",
"province": "Example Province",
"photoCount": 24,
"isBranded": true,
"isProfessionalAd": true,
"hasVideo": true,
"has3DTour": false,
"hasFloorPlan": true,
"advertiserName": "Sample Agency",
"advertiserType": "professional",
"phone": "+34 000 000 000",
"features": ["95 m2 construidos", "3 habitaciones", "2 baños", "Terraza"],
"images": ["https://img4.idealista.com/blur/WEB_DETAIL/0/id.pro.es.image.master/00/00/00/000000000.jpg"],
"imageCount": 24,
"imageTags": [{"url": "https://img4.idealista.com/blur/WEB_DETAIL/0/id.pro.es.image.master/00/00/00/000000000.jpg", "tag": "Cocina"}],
"tags": ["price drop"],
"source": "www.idealista.com",
"scrapedAt": "2026-01-01T00:00:00.000000+00:00"
}

The dataset has three views: Listings Overview (price, size, rooms, location), Listing details (the full record with coordinates, advertiser and photos) and Changes (incremental mode) (changeType and changedFields).

Plan Requirement

A residential connection is required. idealista protects its sites with anti-bot checks that refuse datacenter connections, so a run on a datacenter proxy returns nothing and fails. Keep Residential selected under Connection; the default setting already does, and the actor retries with a different connection when one is refused. Choose a connection in the listing's country (Spain, Italy), because exits are accepted unevenly and a refused attempt is simply retried.

Free plan Apify accounts cannot use residential proxies; add residential proxy credit in the Apify Console under Proxy. If no results page can be loaded at all, the run fails with: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later." When the proxy connection itself is refused, the message says so instead: either that the proxy connection was refused for this account because the plan does not include proxy access, or that residential proxies are unavailable on this run and the backup connection could not load the pages.

Known limits: idealista.pt (Portugal) sits behind a stricter browser check than Spain and Italy and may be refused even on residential connections, and individual listing pages are also refused more often than search pages. When listing pages are refused, the actor still returns the search-result fields for those listings. Both limits depend on the connection and change over time.

FAQ

How much does it cost?

You pay per record returned to the dataset, plus an optional detail-enrichment charge only for records that were actually enriched with a detail-page fetch and pushed (records suppressed by Incremental mode are never charged for enrichment). The Pricing tab shows the current rates. Use Max Listings to cap the cost of any run.

This actor collects only publicly available listing data. You are responsible for how you use it: follow idealista's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Advertiser names, phone numbers and photos may carry their own rights or privacy considerations, separate from the factual listing data.

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW, UPDATED and REAPPEARED listings for the same search, and unchanged ones are not billed unless you turn on Emit unchanged. REAPPEARED only ever appears for a listing that was previously marked EXPIRED, and EXPIRED itself only happens when Emit expired listings is on and an earlier run fully scanned the tracked search without a cap or a resume getting in the way.

Which URLs can I paste in URL mode?

URL mode: supported URL shapes. With mode set to url and the Search URLs field left untouched, the actor now scrapes one example per shape below (previously the field had no default). Replace the list with your own links to scrape only those.

ShapeExample
Search (sale)https://www.idealista.com/venta-viviendas/madrid-madrid/
Paginated (pagina-N.htm), starts at that pagehttps://www.idealista.com/venta-viviendas/madrid-madrid/pagina-2.htm
Path filter (con-...)https://www.idealista.com/venta-viviendas/madrid-madrid/con-metros-cuadrados-mas-de_80/
Sorted (?ordenado-por=)https://www.idealista.com/venta-viviendas/madrid-madrid/?ordenado-por=precios-asc
Rent searchhttps://www.idealista.com/alquiler-viviendas/madrid-madrid/
Districthttps://www.idealista.com/venta-viviendas/madrid/centro/
Provincehttps://www.idealista.com/venta-viviendas/madrid-provincia/
Neighbourhood (/geo/)https://www.idealista.com/geo/venta-viviendas/canorroto/
Agency page (/pro/)https://www.idealista.com/pro/engel-volkers-madrid/
Other property type (garages)https://www.idealista.com/venta-garajes/madrid-madrid/
Language prefix (/en/), normalisedhttps://www.idealista.com/en/venta-viviendas/madrid-madrid/
Map view, rewritten to the list URLhttps://www.idealista.com/venta-viviendas/madrid-madrid/mapa-google
Italy searchhttps://www.idealista.it/vendita-case/roma-roma/
Italy paginated (lista-N.htm)https://www.idealista.it/affitto-case/milano-milano/lista-2.htm

Agencies directories, new-build promotion pages and single listing pages are not search pages: the actor logs a warning for each and skips them. Portugal links follow the same search grammar but are not part of the default examples.

If none of the pasted URLs is a supported search page (for example only single listing pages or agency directories), the run fails with a message saying so instead of finishing with an empty result; each unsupported URL is reported once in the log.

The search filters (price, size, bedrooms, bathrooms, property types, features, condition, freshness and sort order) apply only in Search mode. In URL mode, the pasted URL's own filters apply exactly as idealista built them; the actor does not re-apply the filter fields on top of a pasted URL.

Why did my run fail instead of returning an empty dataset?

If every attempt to read the search results is refused, the run fails outright with a clear message instead of returning zero listings, so "no matches for this search" is never confused with "the site could not be read". If only part of a run was refused, for example one location out of several, the run still succeeds and returns what it found, with a status message noting the run is incomplete. If a run is nearing its own platform time limit, it stops opening new detail pages and returns the listing fields it already has for the remaining listings instead of being cut off with nothing pushed; the status message reports how many listings were affected.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each listing into Notion, Linear or Airtable.

🔗 Want more real estate data?

Pair this actor with these related scrapers from the same team:

🏠 Fotocasa.es
Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths...
🏠 Immowelt.de Scraper
Scrape detailed property listings from Immowelt.de into clean structured data. Extract...
🏠 Immobiliare.it Scraper
Extract property listings from Immobiliare.it with clean structured data including...
🏠 SeLoger Scraper
Scrape SeLoger.com properties for sale and rent. Search by location with price, room and...
🏠 Zonaprop Argentina
Scrape Zonaprop.com.ar property listings across Argentina. Extract 140+ fields including...
🏠 Cian RU
Collect property listings from Cian.ru by search filters or direct URLs. Returns...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.