Quick answer
This Actor sat shelved as "anti-bot blocked" for weeks. Half of that was true — idealista does sit behind DataDome, and a plain HTTP client gets a flat 403 on every attempt. The other half wasn't: the search URLs the code was building 404'd at idealista's own origin, and a 404 is not a block. The Idealista Property Scraper covers idealista.com (Spain), idealista.it (Italy), and idealista.pt (Portugal) in one normalized EUR/m² schema, at $0.20 per run plus $0.005 per result row — 1,000 listings run about $5.20.
The 404 that looked like a wall 🚧
We rotated through five residential exit IPs in Spain, straight HTTP client, no browser. DataDome shut every single one down — 403 on all five, including a request to the bare site root. That's a real wall, and it's the reason this Actor got shelved in the first place: the shelve note read "blocked," full stop.
The fix for that half is a browser, not a smarter HTTP client. We drive Camoufox through a same-context warm-up — land on the site root first, then navigate to the target page in the same browser context — and that sequence clears DataDome where a bare TLS-impersonated client can't. That part of the diagnosis was correct.
But swapping the engine didn't fix the run. The search pages still came back 404. And a 404 from idealista's own servers means something specific: the request reached idealista, and idealista is telling you the path doesn't exist — which is a different failure than a WAF turning you away before you ever get there.
The real bug: a URL builder that guessed wrong 🔍
The code was building search URLs as /venta-viviendas/{location}/ straight from a bare city name — location="madrid" became /venta-viviendas/madrid/. That path doesn't exist on idealista. Its real search paths are two-part slugs: {municipality}-{province}. Madrid the city sits in Madrid the province, so madrid-madrid happens to work — which is exactly the trap, because most Spanish municipalities don't share their province's name. Sitges is in Barcelona province, so its working slug is sitges-barcelona, not sitges-sitges. A URL builder that derives the slug by repeating the city name looks correct on the one case anyone tests by hand and is wrong everywhere else.
We didn't try to derive or guess that mapping — a wrong-but-live URL is worse than an obvious 404, because it fails silently on data you didn't ask for. This Actor takes idealista's own two-part slug as input, exactly as it appears in idealista's search URL, and never transforms it. Once the slug was right, a cloud run paginated 20 pages and parsed 571 real listings end to end, for a settled run cost of roughly $1.73 per 1,000 rows before margin. That figure is a search-only floor — no detail-page enrichment — and 92% of it is residential proxy transfer rather than compute, which is why an immediate post-run cost read understates it. Turning on agency-contact enrichment adds a real per-row cost on top, because it costs a second navigation per listing.
What you get per row 📋
One normalized row across all three TLDs — the same schema whether the listing is in Madrid, Rome, or Lisbon:
| Field | What it is |
|---|---|
price, price_per_sqm
|
Asking price and EUR/m², published or computed |
area_sqm, rooms, bathrooms
|
Normalized size and layout |
energy_rating |
EU EPC letter, A–G |
location_city, location_province, latitude, longitude
|
Geocoded location |
agency_name, agency_phone, agent_reference_id
|
Lister enrichment, when publicly exposed |
listing_owner_type |
particular or professional
|
listed_date, updated_date
|
ISO-8601 dates |
Country, operation (sale/rent), and property type ride along as normalization keys, so a single run can mix Spanish, Italian, and Portuguese listings without you reconciling three different schemas afterward.
Is idealista hard to scrape? 🛡️
Yes, and we don't pretend otherwise — DataDome is a real wall, which is why we run a full browser engine with a warm-up navigation instead of a bare HTTP client, and why every request goes out through a residential proxy pinned to the listing's own country rather than a shared pool that can silently return the wrong country's results at a clean 200. What this run also proves is that "blocked" and "the URL was wrong" produce the same symptom from a distance — an empty or failing run — and only looking at the actual response code tells you which one you're fighting.
What it costs
Pay-Per-Event: a $0.20 actor-start fee plus $0.005 per result row. A thousand listings across any mix of ES/IT/PT runs about $5.20. No API key, no login, and Apify gives every new account $5 of free credit to try it with no card on file.
Do I need to know idealista's internal slug format?
Yes — the location input is idealista's own two-part municipality-province slug, which you can copy straight off any idealista.com/.it/.pt search URL. The README documents the format and the Sitges/Madrid distinction above.
Can one run cover more than one country?
Yes — set countries to any combination of ES/IT/PT, or pass direct search URLs. Each country runs independently, so one blocked or misconfigured country never stops the others.
Top comments (0)