ActorStack.dev
Real estatev0.1.12updated 18 September 2026

Fotocasa Scraper — Spain Real Estate Data & Agencies

No login. No session cookies. No browser.

Extracts property listings for sale and rent from Fotocasa, one of Spain's main property portals, through the same public search endpoint the website calls. Every row carries the price, the surface, the GPS point, Fotocasa's eight-level location hierarchy with its numeric IDs and, for professional advertisers, the agency with its phone.

oswaldocarabano/fotocasa-scraper

input.json
{
  "location": "724,14,28,173,0,28079,0,0,0",
  "transactionType": "rent",
  "propertyType": "home",
  "maxItems": 200,
  "includeAgencies": true
}
Version
v0.1.12
Memory
512 MB
Browser
none
Proxy
None by default; falls back to a Spanish residential IP if blocked

Short answer

The Fotocasa Scraper extracts Spanish property listings from Fotocasa without a login or a browser: price, surface (filled on 99.9% of 3,184 measured listings), GPS coordinates, the full location hierarchy with Fotocasa's own IDs, photos tagged by room, and the agency phone for professional advertisers (96.4% of 1,911). A listing returns a median of 45 populated fields out of 78. Pricing is $0.00095 per listing, $0.002 per agency and $0.006 per optional detail page, and duplicates, error rows and listings without a price are never charged.

Key points

  • The Fotocasa Scraper reads the public search endpoint that fotocasa.es itself calls, so it needs no account, no session cookie and no browser.
  • Fill rates come from 3,184 listings across 16 search profiles measured on 18 September 2026: surface 99.9%, district 90.2%, bathrooms 73.5%, rooms 67.9%.
  • Fotocasa's search stops returning new listings after page 392 and then repeats the same 30 with HTTP 200, so the Actor detects the end of a search by duplicate IDs rather than by status code.
  • Searches larger than 11,760 listings are split along Fotocasa's own location tree, which measured exactly disjoint in 17 of 18 partitions across 6 provinces.
  • A detail page costs about 65 times the bandwidth of a listing (n = 220), which is why street, energy certificate and construction type are an opt-in, separately priced event.
  • Private advertisers were 11.7% of 2,164 listings sampled in rural provinces, and the Actor redacts their contact fields, including phone numbers typed into the description.
On this page11 sections

What it does

Extracts property listings for sale and rent from Fotocasa, one of Spain's main property portals, through the same public search endpoint the website calls. Every row carries the price, the surface, the GPS point, Fotocasa's eight-level location hierarchy with its numeric IDs and, for professional advertisers, the agency with its phone.

output — one row
{
  "id": 186965592,
  "url": "https://www.fotocasa.es/es/comprar/vivienda/campillos/no-amueblado/186965592/d",
  "operation": "buy",
  "property_type": "home",
  "price": 93000,
  "currency": "EUR",
  "surface_m2": 300,
  "rooms": 3,
  "bathrooms": 1,
  "latitude": 37.04998,
  "longitude": -4.8671,
  "postal_code": "29320",
  "region": "Andalucía",
  "province": "Málaga",
  "province_id": 29,
  "municipality": "Campillos",
  "municipality_id": 29032,
  "published_at": "2025-07-03T14:35:58.327Z",
  "photo_count": 28,
  "room_types_photographed": ["kitchen", "bathroom", "living room", "exterior", "bedroom"],
  "agency_name": "Example Inmobiliaria",
  "agency_phone": "+34900000000",
  "is_professional_advertiser": true,
  "energy_certificate_rating": "G",
  "address_is_exact": true,
  "from_cache": false,
  "data_age_hours": 0
}

Why this one

The location tree arrives whole

Every Fotocasa listing row carries country, region, province, municipality, district and neighbourhood with Fotocasa's numeric ID beside each name. Grouping and joining across runs then works on IDs instead of on strings that change with accents and language, and the same IDs are what the Actor uses to split a large search into disjoint pieces.

End of pagination detected by content, not status

Past page 392 Fotocasa's search keeps answering HTTP 200 with the same 30 listings. A scraper that trusts the status code loops forever or bills duplicates. The Fotocasa Scraper stops on repeated IDs and never charges a duplicate.

Filters that were checked to filter

Fotocasa silently ignores parameters it does not recognise and returns the whole catalogue with HTTP 200. Every filter and sort value in the Fotocasa Scraper's input was verified to change the result against the live API; five plausible-looking filters that change nothing were left out.

An agency dataset at zero extra requests

The agency name, phone, logo and profile URL are already inside the search response, so `includeAgencies` writes a deduplicated `agencies` dataset without a single extra request. Private advertisers never enter it.

Use cases

  • Build a priced, geolocated dataset of a Spanish province, city or neighbourhood for sale or rent.
  • Track asking prices and price reductions over time with a scheduled run and `published_at`.
  • Build a lead list of professional real estate agencies with their business phones.
  • Compare energy certificates, construction type and plot surface across a market using detail pages.
  • Join listings to other data on Fotocasa's numeric location IDs instead of on place names.

Input

Every field has a default, and the defaults are deliberately small so a first run is cheap enough to inspect before you commit to a sweep. This table mirrors the Actor's own input schema field for field.

FieldDefaultWhat it does
locationstring"724,0,0,0,0,0,0,0,0"LocationFotocasa location ID (`combinedLocationIds`). Defaults to all of Spain. Madrid city is `724,14,28,173,0,28079,0,0,0`; the Actor walks the tree below whatever you pass.
transactionTypeselect"sale"Operation`sale` or `rent`. New-build is not offered because it returns zero results against the live API.
propertyTypeselect"home"Property type`home`, `commercial`, `land`, `garage` or `storage`.
sortByselect"relevance"Sort by`relevance`, `price`, `newest`, `surface` or `rooms` — only sort values verified to change the order, because Fotocasa ignores unknown ones silently. `sortDescending` defaults to true.
minPriceinteger—Minimum / maximum price (EUR)With `maxPrice`, `minRooms`, `minSurface` and `maxSurface`. Each was verified against the live API: a minimum price moved the national count from 470,340 to 302,763.
maxItemsinteger1000Maximum listingsHard cap for the run, up to 50,000. There is no download-everything mode.
scrapeDetailsbooleanfalseAlso scrape the detail pagepersonal dataAdds street, energy certificate, creation date, construction type, plot surface and quality score. About 65 times the bandwidth of a listing, billed as a separate event.
includeAgenciesbooleanfalseAlso build an agency datasetWrites a separate `agencies` dataset at zero extra requests. Private advertisers are never included.
respectRobotsTxtbooleanfalseRespect robots.txt on the websitepersonal dataOff by default. When on, the Actor honours the robots.txt of www.fotocasa.es for detail pages, which skips detail pages under some city paths. It has no effect on listings, which come from an API host that publishes no robots.txt.
maxCacheAgeDaysinteger7Maximum cache age (days)Serve from cache when the stored copy is younger than this. 0 always fetches fresh.
maxConcurrencyinteger5Maximum concurrency1 to 10. The API answered 24 parallel requests without a non-200; the default stays well below that.

Output and fill rates

A field being in the schema is not the same as it having a value. The percentages below were counted on real runs; the sample sizes are in Measurements. Anything not listed here is not promised.

FieldFilledMeaning
idinteger100%Fotocasa's listing ID. The join key across runs.
pricenumber100%Asking price, with `currency` and `operation`. Listings without a price are not delivered or charged.
surface_m2number99.9%Surface in square metres.
roomsinteger67.9%Room count as published.
bathroomsinteger73.5%Bathroom count as published.
floorinteger45.7%Floor, where the listing states it.
latitudenumber100%With `longitude` and `coordinates_accuracy`.
provincestring100%With `region`, `municipality` and their numeric IDs (`province_id`, `municipality_id`…).
districtstring90.2%With `district_id`.
neighborhoodstring64.9%With `neighborhood_id`.
published_atdatetime100%When the listing was published on Fotocasa.
price_reducednumber28.3%Set when Fotocasa flags a price reduction.
rent_periodicity_idintegernot measuredRentals only: 98.9% of 784 rentals and 0% of 2,400 sales, so the blended rate is meaningless and not shown.
room_types_photographedstring[]81.5%Rooms the photos show — kitchen, bathroom, terrace, bedroom… At least one tagged photo on 81.5% of 840 listings.
agency_phonestring96.4%Professional advertisers only; the rate is of 1,911 professional listings. Private advertisers' contacts are redacted.
has_elevatorboolean44%One of the amenity flags: air conditioning 49.4%, heating 39.9%, terrace 29.0%, pool 6.4%, parking 3.7%.
energy_certificate_ratingstring99.1%Detail pages only, n = 220. With `energy_certificate_value` (100%) and the emissions rating and value.
street_namestring72%Detail pages only, n = 150. `street_number` only when the address is exact: 22.0%.
address_is_exactbooleannot measuredWith `address_visibility_mode`, so rows can be filtered by address precision.
from_cachebooleannot measuredWith `fetched_at` and `data_age_hours`, on every row.

Every key is always present. A field that exists but is empty comes back as explicit null, so a parser never has to guess.

Datasets

Different record types go to different datasets, so the main table never carries columns that are blank on most rows.

  • defaultOne row per property listing, with the detail-page fields when `scrapeDetails` is on.billed
  • agenciesOne row per professional agency found, when `includeAgencies` is on.billed

Pricing

Pay per delivered result. Charges are applied as each row is produced rather than in a lump at the end, so an aborted run bills only for what it actually gave you.

EventPriceNotes
actor-startActor start$0.00001Charged once per run.
propertyProperty listing$0.00095One delivered listing. Never charged for duplicates, errors or listings without a price.
agencyReal-estate agency$0.002One professional agency with name, phone, logo and profile URL. Opt-in.
property-detailDetail page$0.006Street, energy certificate, creation date, construction type and plot surface. Opt-in.

Measurements

Each figure is shown with the method that produced it. A benchmark without a method is a marketing claim wearing a number's clothes.

Fill-rate sample

3,184 listings

16 search profiles against the live site on 18 September 2026. Every listing fill rate on this page comes from that sample unless another n is stated.

Fields per listing

Median 45 of 78; 58 of 78 with detail pages

45 measured on the 3,184-listing sample; 58 measured on 30 listings with detail pages.

Pagination ceiling

Page 392 (~11,760 listings per query)

Past page 392 the search API repeats the same 30 listings with HTTP 200. Detected by duplicate IDs.

Location split

Disjoint in 17 of 18 partitions

18 partitions across 6 provinces and 3 tree levels. The 18th case returns siblings instead of children; the Actor detects it and paginates instead of descending.

Detail page cost

65.3x a listing's bandwidth

Measured on 220 detail pages: about 614 KB against 9.4 KB.

Private advertisers

11.7% of 2,164 listings

Sampled in rural provinces, where private advertisers concentrate. Fotocasa published a phone for 0% of the 253 private advertisers in that sample.

Throughput

16,568 listings per hour

One reference run of 2,000 listings in 435 seconds at 512 MB, 73 requests, all direct with no proxy.

What it will not do

Stated plainly so you can judge fit before spending anything.

  • No download-everything mode: `maxItems` is a hard cap, with a maximum of 50,000 per run.
  • A single search query cannot page past 392 pages, about 11,760 listings; larger searches are split by location.
  • New-build developments (transaction type 4) are not offered, because the live API returned zero results for them.
  • Street number only when Fotocasa marks the address as exact, which was 22.0% of 150 detail pages measured.
  • Detail pages are off by default and cost about 65 times a listing in bandwidth.
  • Four fields that came back empty on every measured listing — storage room, furnished flag, photo-report flag and external contact — are not in the output at all.

Privacy

  • Professional agencies' names and phones are business contact data and are always delivered.
  • Private advertisers' contact fields are redacted, and phone numbers typed inside their descriptions (found in 2.4% of 124 private listings) are stripped.
  • An advertiser type the Actor has not verified is treated as private: the row is redacted, flagged with `is_professional_advertiser: false` and not charged.
  • Removal requests: privacy@actorstack.dev

See also the data removal process.

Frequently asked questions

Does the Fotocasa Scraper need an account or a login?
No. The Fotocasa Scraper uses no account, no session cookie and no browser. It reads the same public search endpoint the fotocasa.es website calls, which answered without any authentication or special headers when measured.
Can I get real estate agency phone numbers from Fotocasa?
Yes, for professional agencies: the phone came back on 96.4% of 1,911 professional advertisers measured. Private individuals are excluded, because Fotocasa published no phone for any of the 253 measured and the Actor redacts their contact details.
How many Fotocasa listings can one run return?
Up to the `maxItems` cap of 50,000. One search query stops at page 392, about 11,760 listings, so larger searches are split along Fotocasa's location tree, which measured disjoint in 17 of 18 partitions.
Does the Fotocasa Scraper return the street address?
Partly. On detail pages the street name came back on 72.0% of 150 measured and the street number only when Fotocasa marks the address as exact, which was 22.0%. Every row carries `address_is_exact` so you can filter by precision.
Does the Fotocasa Scraper follow Fotocasa's robots.txt?
Listings come from web.gw.fotocasa.es, which returned 404 for robots.txt when checked on 10 October 2026. Detail pages come from www.fotocasa.es, whose robots.txt disallows some city paths; the Actor honours it only when `respectRobotsTxt` is on, and that switch is off by default.

Guides for this Actor