Fotocasa Spain Scraper icon

Fotocasa Spain Scraper

Scrape Fotocasa.es property listings for sale and rent across Spain. Extract 140+ fields including prices, floor areas, bedrooms, bathrooms, addresses,…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

Fotocasa Spain Scraper at a glance

Fotocasa Spain Scraper is a ready-to-run Apify actor from abotapi for collecting real estate data. Its documented output includes id, title, change type (incremental mode), price and currency, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Real Estate, Automation, Developer Tools
Region
Europe
Pricing
$2.00 per 1,000 results (Free plan), from $1.00 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
34 options

Scrape Fotocasa.es property listings for sale and rent across Spain. Extract 140+ fields including prices, floor areas, bedrooms, bathrooms, addresses, GPS coordinates, agencies, phone numbers, energy ratings and photos. Covers all regions and property types.

What Fotocasa Spain Scraper can do

  • 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.

Choose what to collect

These inputs let you configure Fotocasa Spain Scraper - Properties, Prices & Agents. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestring · requiredSearch by location/filters, or scrape a list of direct page URLs.

Choices: search, url

locationsarrayPlace names or location slugs (Search mode only). Type a place such as 'Valencia' or 'Alcalá de Henares' and it is resolved on fotocasa.es (the run stops with a clear error if nothing matches), or use a slug such as 'madrid-capital', 'valencia-provincia' or 'madrid-capital/centro'. Leave empty (or use 'espana') for all of Spain.
operationstringBuy, rent, share, rent with option to buy, or business transfer (Search mode only). Share, rent-to-buy and transfer cover homes (share, rent-to-buy) and premises (transfer); other property types fall back to that default.

Choices: comprar, alquiler, compartir, opcion-compra, traspaso

propertyTypestringProperty category (Search mode only).

Choices: viviendas, pisos, casas, duplex, aticos, estudios, lofts, garajes, trasteros, locales, oficinas, naves, terrenos, edificios

sortBystringResult order (Search mode only).

Choices: relevance, newest, price_asc, price_desc, surface_asc, surface_desc

minPriceintegerMinimum price filter. Leave empty for no minimum.
maxPriceintegerMaximum price filter. Leave empty for no maximum.
Show 27 more inputs
More input fields
InputWhat it controls
minRoomsintegerMinimum number of rooms.
maxRoomsintegerMaximum number of rooms.
minBathsintegerMinimum number of bathrooms.
maxBathsintegerMaximum number of bathrooms.
minSurfaceintegerMinimum surface in square metres.
maxSurfaceintegerMaximum surface in square metres.
publicationDatestringKeep only listings published within the window (Search mode only). Applied to the scraped rows, so combine with Sort By = Newest for the fullest coverage.

Choices: , last48h, lastWeek, lastMonth

latitudenumberWith longitude, keep only listings within Radius (km) of this point (Search mode only).
longitudenumberLongitude of the radius centre.
distanceKmintegerRadius around the centre point; 20 km when a centre is set and this is empty.
rentalTypesarrayRent only: long-term and/or temporary rentals. Empty or both = no restriction.
urlsarrayfotocasa.es pages to scrape (URL mode only; filter fields are ignored, the URL's own sort and filters apply on every page). Supported: search pages (city, zone, street area, province, nationwide, rent, rent-to-buy, shared rooms, new build, any property category, /l/N pages, sort and filter query strings, the /en/ and /ca/ language versions), agency pages (/es/pro/, one page, and legacy inmobiliaria links) and single listing pages ending in /d. A listing page is fetched once. Unsupported URLs (m.fotocasa.es, paths without /es/, /en/ or /ca/, other obra-nueva forms) are skipped with a warning in the log. The default lists one example of every supported shape.
fetchDetailsbooleanAdds energy certificate, full feature list, reference, agent/contact name and email from the listing detail page. Slower and increases cost per listing.
maxListingsintegerMaximum total listings to scrape. This is the run cap. Set 0 for unlimited.
maxPagesintegerOptional safety limit on result pages walked per search (~31 listings/page). This does NOT cap the run; leave empty (or 0) for unlimited and let Max items decide when to stop. Only set a value to hard-stop pagination earlier than Max items.
resumeFromRunIdstringOptional: 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. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead.
incrementalModebooleanTurn this on for daily or recurring monitoring. The first run returns all matching listings as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED listings. Compared between runs: price, reduced price, surface, rooms, bathrooms, location, title, description, features, availability flags and agency/contact summary fields (changedFields names what moved). Never compared (but still returned): photo/media URLs (multimedia, images, imageUrl, previewImage, photoUrls), per-session visited/favourite flags and the listing-age object (date) and the daily age counter in dateOriginal (diff, unit), the derived zipCode and publicationDate, the raw agency profile object, plus anything you add in Ignore fields. Turn on "Emit unchanged" or "Emit expired" only when you also want those listings returned (and billed). State is kept separately for each search/URL and filter/detail setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from run ID above.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search/URL and filter/detail settings, different searches then never mix state with each other.
emitUnchangedbooleanOff by default. Turn on to also return listings that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.
emitExpiredbooleanOff by default. Turn on to also return listings that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max items capped it or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.
changeScopestringAll fields (default): any compared field moving makes a listing UPDATED. Price and availability only: only price, reduced price, price per m2, price type and occupied/discarded flags count; every other edit (description, photos, agency) leaves the listing UNCHANGED, so a price monitor is not billed for them. Listings are still returned in full unless Compact updates is on.

Choices: all, priceAndStock

compactUpdatesbooleanOff by default. When on, UPDATED and EXPIRED rows carry only ids, url, title, current price and a priceChanges object with old and new values. NEW rows stay complete. Compact rows carry no detail-page data, so the detail enrichment charge is not applied to them.
expireAfterMissedScansintegerDefault 1: a listing missing from one complete scan is marked EXPIRED (when Emit expired is on). Raise it to wait for N consecutive complete scans before expiring. EXPIRED means the listing was not found in the search results, not proof that it was delisted or sold.
ignoreFieldsForChangesarrayOptional. Field names (dotted paths such as address.city are supported) that must never make a listing UPDATED or appear in changedFields. The fields are still returned. Photo URLs, visited/favourite flags and the daily listing-age counters are already ignored by default.
mcpConnectorsarrayOptionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON. The complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).
notionParentPageUrlstringURL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

idID (text)
titleTitle (text)
changeTypeChange type (incremental mode) (text)
rawPricePrice (number)
currencyCurrency (text)
surfaceSurface (m²) (number)
roomsRooms (number)
bathsBaths (number)
propertyTypeType (text)
cityCity (text)
neighborhoodNeighborhood (text)
latitudeLat (number)
Show 21 more fields
longitudeLng (number)
agencyNameAgency (text)
phonePhone (text)
urlURL (link)
changedFieldsChanged fields (incremental mode) (text)
firstSeenAtFirst seen (incremental mode) (date)
lastSeenAtLast seen (incremental mode) (date)
referenceReference (text)
energyCertificateEnergy certificate (text)
extraFeaturesExtra features (text)
constructionTypeConstruction type (text)
qualityRateQuality rate (text)
agentNameAgent (text)
antiquityAntiquity (age bucket) (number)
isAuctionedAuctioned (text)
isRentedWithTenantsRented with tenants (text)
hasPhoneVisibilityPhone visible (text)
contractsContracts (array)
clientAliasAlias (text)
clientTypeClient Type (text)
clientUrlAgency URL (link)

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "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"
}

Ways to use this data

  • 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.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does Fotocasa Spain Scraper return?

The documented output for Fotocasa Spain Scraper includes id, title, change type (incremental mode), price, currency, surface (m²), rooms and baths. Availability of each field depends on the source page and the selected mode.

How much does Fotocasa Spain Scraper cost?

It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

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.

What happens if I run URL mode without entering any URLs?

Behaviour change: the URLs field now ships with a default list holding one example of every supported URL shape, so a URL-mode run with the field untouched scrapes those examples (capped by Max items) instead of failing with "no URLs provided". Replace the list with your own URLs. A single listing URL (ending in /d) returns that one listing in full from one page fetch, and a search URL's sort and filter query strings apply on every result page. URLs that cannot be scraped (m.fotocasa.es, paths without /es/, /en/ or /ca/, obra-nueva pages other than the ".../obra-nueva/l" form) are skipped with a warning in the log; if none of the pasted URLs is supported the run fails with a message that names each rejected URL and the reason.

Which dataset views are there?

The dataset has four views: Listings Overview, Listing Detail (fetchDetails), Changes (incremental mode) and Agency & Contact. The views only choose which columns are shown; every field is always in the full dataset.

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.

Ready to collect with Fotocasa Spain Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.