Fotocasa.es $1💰 Buy, Rent & Property Details avatar

Fotocasa.es $1💰 Buy, Rent & Property Details

Pricing

from $1.00 / 1,000 listing scrapeds

Go to Apify Store
Fotocasa.es $1💰 Buy, Rent & Property Details

Fotocasa.es $1💰 Buy, Rent & Property Details

From $1/1K. Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths, address, GPS, agency, phone, energy rating, photos and 140+ fields. Buy and rent, all regions, all property types.

Pricing

from $1.00 / 1,000 listing scrapeds

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

0

Monthly active users

19 hours ago

Last modified

Share

Fotocasa.es Scraper: Property Listings, Prices & Agency Contacts

Fotocasa.es Scraper turns fotocasa.es into a clean property-data feed for Spain. Get price, surface, rooms, bathrooms, full address, GPS coordinates, agency name and phone, and 140+ fields per listing, for both buy and rent, every region and every property type. Search by location and filters, or paste direct fotocasa.es search-result URLs, switch on per-listing detail enrichment for energy rating and agent contact, then export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • 140+ fields per listing. Every record carries both camelCase and snake_case field names, so the output drops into any existing pipeline without remapping.
  • Buy and rent, every region, every property type. Flats, houses, duplexes, penthouses, studios, lofts, garages, offices, warehouses, land and more.
  • Rich location data. City, neighborhood and precise latitude/longitude on every listing, straight from the search results.
  • Agency and contact details on every listing, plus optional agent name, email and listing reference when detail enrichment is on.
  • Two input modes. Search by location with filters, or feed direct fotocasa.es search-result URLs; either way you choose whether to fetch full listing details.
  • Built for monitoring. Incremental mode tracks one saved search across scheduled runs and classifies each listing as new, updated or unchanged by default (reappeared needs Emit expired listings), without you pasting any run id.
  • Fails loudly, not silently. A run where every request was refused stops with a clear error instead of billing an empty result as if the search itself came back with nothing.

Use Cases

  • Real estate investors: track price per square metre across neighborhoods to spot undervalued listings.
  • Proptech platforms and aggregators: build a structured buy-and-rent property feed for Spain to power search or comparison tools.
  • Relocation and expat services: monitor new listings in target cities so clients hear about matches quickly.
  • Market researchers and appraisers: build historical price and surface datasets for a city or region.
  • Agencies and portals: track how competitor listings price and how long they stay on the market, using Incremental mode's change history.

Data You Get

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

FieldExample
id"1_000000000"
propertyId"000000000"
title"Calle de Ejemplo, Centro"
rawPrice295000
currency"EUR"
pricePerSqm4538.46
surface65
rooms3
baths2
floor"4"
propertyType2
propertySubtype1
operation"sale"
city"Madrid"
neighborhood"Centro"
latitude40.4168
longitude-3.7038
agencyName"Example Agency SL"
clientAlias"Example Agency"
clientType"professional"
phone"+34000000000"
images["https://static.fotocasa.es/images/ads/0000?rule=original"]
photosCount12
url"https://www.fotocasa.es/es/comprar/vivienda/madrid-capital/centro/000000000/d"

Every listing also carries a description, publication date, promotion/highlight flags (isNew, isNewConstruction, isVirtualTour, isTop, ...) and dozens of id/type fields (transactionTypeId, typeId, subtypeId, clientTypeId, ...) in both camelCase and snake_case. energyCertificate, reference, extraFeatures, constructionType, groundSurface, qualityRate, purchaseType, agentName, agentEmail, contactName and creationDate stay empty on every record unless fetchDetails is on, since they only come from the listing's own detail page. When Incremental mode is on, every returned record also carries changeType (NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED), changedFields, firstSeenAt and lastSeenAt.

How to Use

  1. Pick a mode: search (location + filters) or url (direct fotocasa.es search-result URLs).
  2. For search mode, set Locations, Operation, Property Type, Sort By and any price/rooms/baths/surface filters. For URL mode, paste one or more fotocasa.es search-result URLs; filter fields are ignored in this mode.
  3. Turn on Fetch full details if you need energy rating, full features, reference and agent/contact name and email from each listing's own page.
  4. Set Max items to control run size and cost, then click Start. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search a city for homes to buy:

{
"mode": "search",
"locations": ["madrid-capital"],
"operation": "comprar",
"propertyType": "viviendas",
"maxListings": 50
}

Rent search with filters and sorting:

{
"mode": "search",
"locations": ["barcelona-capital"],
"operation": "alquiler",
"minPrice": 800,
"maxPrice": 1500,
"minRooms": 2,
"sortBy": "price_asc",
"maxListings": 100
}

Direct search URLs with full detail enrichment:

{
"mode": "url",
"urls": ["https://www.fotocasa.es/es/comprar/viviendas/valencia-capital/todas-las-zonas/l"],
"fetchDetails": true,
"maxListings": 200
}

Daily monitoring of one search, with expiry tracking:

{
"mode": "search",
"locations": ["madrid-capital"],
"operation": "comprar",
"propertyType": "pisos",
"incrementalMode": true,
"emitExpired": true,
"maxListings": 0
}

Run it from your code

Python:

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

JavaScript:

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

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

Full-catalogue runs and resuming

To walk an entire search (not just a page or two), set Max items to 0 and leave Max Pages Per Search empty (or 0): the actor then paginates until the site itself runs out of results. If a full-catalogue run is interrupted (platform migration, manual abort, or a fresh run days later to pick up new listings), pass the previous run's id as Resume from run ID: the actor pages through that run's dataset, seeds its dedup set with the listing ids already collected there, and then scrapes only new listings. An interrupted run also checkpoints its own seen-listing state during the run and resumes from it automatically on a platform migration; that checkpoint is cleared once a run finishes cleanly.

Incremental mode and REAPPEARED/EXPIRED

resumeFromRunId continues one specific interrupted run. Incremental mode is for the opposite case: you schedule this actor to run the same search again and again (daily, weekly) and want only what changed, without pasting any id. Turn it on and the actor keeps a baseline in its own key-value store, keyed on the search/URL and every filter and fetchDetails setting (raising or lowering Max items/Max Pages between runs never forks a new baseline). Each listing is then classified:

  • NEW: not seen before.
  • UPDATED: a tracked field changed; changedFields lists which ones.
  • UNCHANGED: nothing changed. Suppressed by default (not returned, not billed); turn on emitUnchanged to get the full snapshot every run instead.
  • REAPPEARED: this only ever fires for a listing whose stored state was already marked not-present by an earlier run, which only happens once that earlier run had emitExpired on and completed a full, uncapped, non-resumed scan. It is never the outcome for an ordinary unchanged or first-seen listing.
  • EXPIRED: was tracked, no longer found. Only produced when emitExpired is on, and only once a run has proven a complete scan of the tracked search: a maxListings/maxPages cap, or a resumeFromRunId run, skips expiry detection entirely for that run rather than risk tombstoning a listing that simply wasn't reached yet.

Turning on incrementalMode together with resumeFromRunId is only allowed to bootstrap a brand-new monitoring baseline; if that state key already has tracked listings from an earlier run, the actor fails fast, before any scraping, and asks you to drop Resume from run ID or pick a different State key.

Send results into your apps (MCP connectors)

Beyond the dataset, this Actor can send a condensed summary of each listing straight into the tools you already use, via Model Context Protocol (MCP) connectors. The full record is always kept in the dataset; the connector receives a readable summary (title plus key fields) per item.

Supported connectors: Notion, Linear, Airtable, and Apify.

  1. Authorize the connector once under Apify → Settings → Integrations.
  2. Select one or more in the mcpConnectors input.
  3. (Notion only) Set notionParentPageUrl to the page under which one page per listing is created.
  4. Optionally cap how many listings are forwarded with maxNotifyListings (default 50).
{
"mode": "search",
"locations": ["madrid-capital"],
"operation": "comprar",
"maxListings": 50,
"mcpConnectors": ["notion"],
"notionParentPageUrl": "https://www.notion.so/your-workspace/Listings-0000"
}

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (location + filters) or url (direct URLs).
locationsarrayno default (prefill: ["madrid-capital"])Location slugs, e.g. madrid-capital, barcelona-capital/centro. Search mode only; leave empty for all of Spain.
operationstringcomprarcomprar (buy) or alquiler (rent). Search mode only.
propertyTypestringviviendasProperty category, e.g. viviendas, pisos, casas. Search mode only.
sortBystringrelevancerelevance, newest, price_asc, price_desc, surface_asc or surface_desc.
minPriceintegerno defaultMinimum price filter (EUR). Search mode only.
maxPriceintegerno defaultMaximum price filter (EUR). Search mode only.
minRoomsintegerno defaultMinimum number of rooms. Search mode only.
maxRoomsintegerno defaultMaximum number of rooms. Search mode only.
minBathsintegerno defaultMinimum number of bathrooms. Search mode only.
maxBathsintegerno defaultMaximum number of bathrooms. Search mode only.
minSurfaceintegerno defaultMinimum surface in square metres. Search mode only.
maxSurfaceintegerno defaultMaximum surface in square metres. Search mode only.
urlsarrayno default (prefill: one sample search URL)Direct fotocasa.es search-result URLs. URL mode only; filter fields above are ignored in this mode.
fetchDetailsbooleanfalseAdds energy certificate, full feature list, reference and agent/contact name and email from the listing detail page. Slower and increases cost per listing.
maxListingsinteger20Maximum total listings to scrape. This is the run's sole cap. Set 0 for unlimited.
maxPagesintegerno defaultOptional safety limit on result pages walked per search (~31 listings/page). Does NOT cap the run; leave empty (or 0) for unlimited and let Max items decide when to stop.
resumeFromRunIdstringno defaultOptional: paste a previous run id (or its dataset id) to continue that run. Listings already saved there are skipped, so this run only adds new ones.
incrementalModebooleanfalseTurn on for daily or recurring monitoring of the same search: classifies every listing NEW / UPDATED / UNCHANGED by default (REAPPEARED and EXPIRED need Emit expired listings too).
stateKeystringno defaultOptional, incremental mode only. Names a monitoring campaign so its state stays stable, or so two differently-configured runs can deliberately share one baseline.
emitUnchangedbooleanfalseIncremental mode only. Also return (and bill) listings unchanged since the last run, marked UNCHANGED.
emitExpiredbooleanfalseIncremental mode only. Also return (and bill) synthetic EXPIRED rows for tracked listings that no longer appear, produced only after a complete, uncapped scan of the tracked search.
proxyobjectResidential proxy, Spain (ES) exitProxy used for all requests. Residential with an ES exit is enabled by default, which fotocasa.es requires for reliable access.
residentialCountriesarray["ES"]Country codes used for the residential proxy fallback rotation.
maxResidentialRequestsinteger10000Caps how many requests may use the residential proxy in one run, to control cost. Once spent, the run auto-downgrades to a cheaper connection tier. Set 0 to disable the residential tier entirely.
backupProxyUrlstringno defaultOptional. A full proxy URL used as a last-resort failover when the Apify proxy is unavailable (for example on a restricted plan).
mcpConnectorsarrayno defaultOptional: send a summary of each listing to apps you authorized under Integrations.
notionParentPageUrlstringno defaultNotion connector only: page under which one page per listing is created.
maxNotifyListingsinteger50Cap on listings forwarded to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing. Shown with fetchDetails on, which is why the detail-only fields below are populated.

{
"id": "1_000000000",
"propertyId": "000000000",
"title": "Calle de Ejemplo, Centro",
"rawPrice": 295000,
"currency": "EUR",
"pricePerSqm": 4538.46,
"surface": 65,
"rooms": 3,
"baths": 2,
"floor": "4",
"propertyType": 2,
"propertySubtype": 1,
"operation": "sale",
"transactionTypeId": 1,
"city": "Madrid",
"neighborhood": "Centro",
"address": { "locality": "Madrid", "neighborhood": "Centro", "coordinates": { "lat": 40.4168, "lng": -3.7038 } },
"latitude": 40.4168,
"longitude": -3.7038,
"agencyName": "Example Agency SL",
"clientAlias": "Example Agency",
"clientType": "professional",
"phone": "+34000000000",
"reference": "REF-00000",
"energyCertificate": { "energyEfficiencyRatingType": "C" },
"images": ["https://static.fotocasa.es/images/ads/0000?rule=original"],
"photosCount": 12,
"description": "Bright reformed home in a well-connected central area.",
"url": "https://www.fotocasa.es/es/comprar/vivienda/madrid-capital/centro/000000000/d"
}

Plan Requirement

The default proxy setting (residential, Spain exit) works out of the box and is what fotocasa.es needs for reliable access; you can change it under Connection. Large or frequent runs should keep an eye on Residential request budget to control cost, since the run automatically falls back to a cheaper connection tier once that budget is spent.

FAQ

How much does it cost?

You pay per run start, per listing returned, and an optional per-listing surcharge for detail enrichment only when fetchDetails is on. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.

This actor collects only publicly available property listing data. You are responsible for how you use it: follow fotocasa.es's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts like price and surface are generally usable, but photos, descriptions and agency branding may be subject to third-party rights.

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 and updated listings by default; unchanged ones are not returned or billed unless you turn on Emit unchanged listings, and reappeared listings only show up once you also use Emit expired listings.

Why does a pasted "URL" search page ignore my filter fields?

In url mode the search-result URL fully defines the query, exactly as it was built on fotocasa.es, so the price/rooms/baths/surface filter fields in the input are ignored on purpose. Build the filters into the URL on the site itself, or switch to search mode to use the filter fields.

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

If every request to fotocasa.es was refused (rate-limited, blocked, or no readable response at all), the run fails with a clear message instead of silently completing as if the search itself came back empty, so "nothing was found" is never confused with "nothing could be read". Retry after a few minutes, or switch to a residential proxy with a Spain (ES) exit. A genuinely empty search, on the other hand, still succeeds and reports quietly with no billable row.

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 results into Notion, Linear or Airtable.

🔗 Want more real estate data?

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

🏠 Idealista Scraper
From $1/1K. Scrape Idealista properties across Spain, Italy, and Portugal. Extract 35+...
🏠 Funda in Business Scraper
Scrape Funda in Business commercial listings: offices, retail, industrial, catering and...
🔌 MediaMarkt.es Scraper
Scrape MediaMarkt Spain (mediamarkt.es) products: current price, strike-through original...
🏠 Zonaprop Argentina
Scrape Zonaprop.com.ar property listings across Argentina. Extract 140+ fields including...
🛒 Decathlon.es
Scrape Decathlon Spain (decathlon.es) sporting goods: current price plus strike-through...
🛒 LeroyMerlin.es Scraper
Scrape Leroy Merlin Spain (leroymerlin.es) DIY and home-improvement products: price...

👉 Browse all abotapi scrapers

💬 Support & custom scrapers

  • 🐞 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 abotapi@proton.me or message Telegram @abotapi.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.