Fotocasa is one of Spain's main property portals, run by Adevinta. Scraping it turns out to be less about parsing than about four behaviours of its search endpoint that decide whether a dataset is complete, correct and affordable. Every number below was measured against the live site on 18 September 2026 unless another date is given.
What Fotocasa serves without a login
The search results on fotocasa.es are loaded from a JSON endpoint on web.gw.fotocasa.es. It answered with no authentication, no cookies and no special headers — the same response to a bare request as to a full browser. That is the route the Fotocasa Scraper uses, with no browser and no proxy unless it starts being blocked.
A listing row carries a median of 45 populated fields out of 78, measured on 3,184 listings across 16 search profiles. Always present: ID, URL, price, currency, operation, property type, publication date, description, coordinates, postcode and the location hierarchy. Usually present:
| Field | Fill rate | n |
|---|---|---|
surface_m2 | 99.9% | 3,184 |
agency_phone (professional advertisers) | 96.4% | 1,911 |
district | 90.2% | 3,184 |
bathrooms | 73.5% | 3,184 |
rooms | 67.9% | 3,184 |
floor | 45.7% | 3,184 |
price_reduced | 28.3% | 3,184 |
rent_periodicity_id is the instructive exception: 98.9% on 784 rentals and 0% on 2,400 sales, because it only exists on a rental. A single blended rate for it would be true and useless, which is the general argument of measured fill rates, not promises.
Step 1 — pick a location from the ID tree
Fotocasa addresses places with a comma-separated path through its own tree — country, region, province, comarca, municipality, district, neighbourhood. All of Spain is 724,0,0,0,0,0,0,0,0; Madrid city is 724,14,28,173,0,28079,0,0,0; Barcelona province is 724,9,8,0,0,0,0,0,0. Every response carries the child locations of whatever was asked, with their counts, so the Actor can walk the tree for you.
{
"location": "724,14,28,173,0,28079,0,0,0",
"transactionType": "rent",
"propertyType": "home",
"maxItems": 200,
"includeAgencies": true
}The output keeps the tree whole: every row has each level's name and its numeric ID, so grouping and joining across runs works on integers rather than on place names that change with accents and language.
Step 2 — use only filters that filter
Fotocasa's search endpoint does not reject a parameter it does not recognise. It ignores it and returns the unfiltered catalogue with HTTP 200. Five plausible-looking filters were tested that do exactly that, so a filter is only trustworthy once it has been seen to move the count.
The Actor offers only filters that were: minimum and maximum price, minimum rooms, minimum and maximum surface. A minimum price moved the national count from 470,340 to 302,763. The same applies to sorting — relevance, price, newest, surface and rooms were verified to change the order, and nothing else is offered. New-build developments are not offered at all, because that transaction type returned zero results.
Step 3 — plan around page 392
At 30 listings a page, the search stops returning new listings after page 392 — about 11,760 per query. It does not end with an error. It keeps answering HTTP 200 with the same 30 listings, indefinitely. A scraper that waits for a non-200 never stops; one that charges per row bills the same listing hundreds of times.
The Actor stops on repeated IDs instead, and never charges a duplicate. To go past the ceiling it splits a search along the location tree using the child counters in every response. The split was checked for overlap: exactly disjoint in 17 of 18 partitions across 6 provinces and 3 tree levels. The 18th was a node that returns its siblings instead of its children, which the Actor detects and paginates instead of descending.
There is still no download-everything mode. maxItems is a hard cap, at most 50,000 per run, against 470,340 homes for sale reported nationally. Extracting a substantial part of a database is what the EU's sui generis database right, in Directive 96/9/EC, protects against.
Step 4 — decide about detail pages
scrapeDetails adds what exists only on the listing page: street, energy certificate, emissions rating, construction type, plot surface, creation date and a quality score. On 220 detail pages the energy rating letter was present on 99.1% and its kWh/m² value on 100%. The median rises to 58 of 78 fields, measured on 30 listings.
The cost is bandwidth: a detail page weighs about 614 KB against 9.4 KB for a listing, 65.3 times more on 220 pages. That is why it is off by default and billed as its own event.
The street address deserves its own caveat. Fotocasa decides how precisely to show an address. On 150 detail pages the street name came back on 72.0% and the street number — shipped only when Fotocasa marks the address exact — on 22.0%. Every row carries address_is_exact and address_visibility_mode, so filter on precision rather than assuming it.
Two hosts, two robots.txt answers
The robots.txt on www.fotocasa.es, fetched on 10 October 2026, has 297 Disallow lines. Its pagination block disallows every search page from /l/2 onward, and a separate block disallows three city paths:
# Pagination
Disallow: /*/l/2*
Disallow: /*/l/3*
...
Disallow: /*/l/39*
Disallow: /*/madrid/*
Disallow: /*/barcelona/*
Disallow: /*/valencia/*The search endpoint lives on a different origin, web.gw.fotocasa.es, whose robots.txt returned 404 on the same day. RFC 9309 says that when robots.txt is unavailable with a 4xx status, a crawler may access any resource on that server. The listings come from there.
Detail pages are different: they are on www. Measured on 750 detail URLs, 287 (38.3%) fall under the Madrid, Barcelona and Valencia rules. The Actor honours those rules only when respectRobotsTxt is on, and it is off by default — a choice the user makes, not one the Actor hides. The broader argument for treating the file as a specification is in reading robots.txt as a specification.
What a run costs
$0.00095 per listing, $0.002 per agency, $0.006 per detail page and $0.00001 to start. A thousand listings is about 95 cents; the same thousand with detail pages is about $6.95. Duplicates, error rows, listings without a price and rows whose advertiser had to be redacted are never charged.
The agency dataset is the cheap win. Agency name, phone, logo and profile URL are already in the search response, so includeAgencies builds a deduplicated agency table at zero extra requests — roughly 7 distinct agencies per 30 listings. Private advertisers never enter it. One reference run of 2,000 listings took 435 seconds, about 16,568 listings an hour.
For how Fotocasa sits next to the Romanian and Korean portals, see the three portals compared; for the same coverage problem on an Argentine portal, see how to scrape Zonaprop.
