Fotocasa Scraper
Scrape fotocasa.es homes for sale and rent: price, price per m2, surface, rooms, floor, neighbourhood, coordinates, agency or private seller.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
location,transactionType,propertyType(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.00065 per listing = $0.65 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Listing returned | One property listing returned in the dataset. Diagnostic rows and listings dropped by your filters are not charged. | $0.00065 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-20, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
location | Type a town, district or neighbourhood the way it appears in Fotocasa's own search box: "Madrid", "Valencia", "Barrio de Salamanca", "Marbella". The "-capital" in their URLs is part of the address, not the name. The Actor looks it up and takes the match with the most live listings, so a bare province name gets you the province; use Area size below to pin it to a town. Leave empty if you are pasting search URLs. | string |
transactionType | Which market to read. Only used with the Place field above; a pasted URL already says which one it is. | string |
propertyType | Only used with the Place field above. | string |
locationLevel | Which size of area the place name should resolve to. Automatic takes whichever match has the most live listings, which for a province name means the whole province. Only used with the Place field above. | string |
maxItems | Hard cap on how many listings the run delivers, across every search. You are charged per listing delivered, so this is also your spending cap. | integer |
startUrls | Paste search pages straight from fotocasa.es, for example https://www.fotocasa.es/es/comprar/viviendas/barcelona-capital/todas-las-zonas/l — whatever filters you set on the site come with the URL. The Actor pages through each one until it runs out of results or hits your maximum. One URL per line. | array |
sortType | Newest first is the default because Fotocasa's own relevance order shuffles between requests, which makes deep paging return the same listing twice. Only used with the Place field above. | string |
advertiser | Keep only listings from estate agencies, or only from private sellers. Fotocasa has no server-side filter for this, so the Actor reads the page and drops the rest — you are not charged for anything it drops. | string |
minPrice | In euros. For rentals this is the monthly rent. | integer |
maxPrice | In euros. For rentals this is the monthly rent. | integer |
minSurface | Built surface in square metres, as Fotocasa reports it. Applied by Fotocasa before anything is charged. | integer |
maxSurface | Built surface in square metres. Leave empty for no upper limit. | integer |
minRooms | Bedrooms, not total rooms. Fotocasa caps this filter at 10. | integer |
maxRooms | Bedrooms, not total rooms. Leave empty for no upper limit. | integer |
minBathrooms | Bathrooms. Fotocasa caps this filter at 10. | integer |
maxBathrooms | Bathrooms. Leave empty for no upper limit. | integer |
What you get
A structured dataset — each result includes fields like:
pricepricePeriodpricePerM2surfaceM2roomsbathroomsfloorpropertySubtypeneighbourhoodmunicipalityprovincepostcodelatitudelongitudeadvertiserTypeadvertiserNamepublishedAturlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Developer & Research Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
GitHub Scraper
Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.
Stack Overflow / Stack Exchange Scraper
Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.
Package Registry Scraper (npm + PyPI)
Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.
arXiv Scraper
Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.
OpenAlex Scholarly Works Scraper
Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.
Crossref Scholarly Works Scraper
Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.
Where this tool sits
- Categories
- Developer & Research Tools
Fotocasa Scraper
Pulls property listings off fotocasa.es, the Spanish portal for homes to buy and rent, and hands you back one clean row per listing. Price, price per m², surface in square metres, rooms, bathrooms, floor, the address down to the neighbourhood, real coordinates, the feature list, whether the advertiser is an estate agency or a private seller, every photo URL, the description, the publication date and the link to the listing itself.
No Fotocasa account. No API key. No cookies to paste in.
Start with the part that usually gets buried
Fotocasa's default relevance ordering shuffles between requests. Ask for the same search page twice, ten seconds apart, and the first listing is usually a different one. That is their behaviour, not a bug in this Actor, and it means deep paging under relevance order will hand you the same property twice. So this Actor sorts by newest first by default and de-duplicates every run by listing id. You can switch back to Fotocasa's relevance order if you want it — the option is there — but now you know why it is not the default.
A few other things worth knowing before you spend anything:
- Floor is only on about half the listings. Measured on a live Valencia rental search: 15 of 30
rows carried a floor. Fotocasa does not make advertisers fill it in. Same story for neighbourhood (13 of 30) and condition (16 of 30). Price, surface, rooms, coordinates and the address hit 30 of 30.
- This reads search results, not the individual listing pages. Everything above comes from the
search response. Things that only exist on a listing's own page — the energy certificate rating, the agency's internal reference number, the full amenity checklist — are not here.
- Typing a place name gets you Fotocasa's best match, which is not always the one you pictured.
Type "Valencia" and you get the province, because that is where most of the listings are. Set Area size to *Town or city* and you get the city. And note that the -capital you see in their URLs is part of the address, not part of the name: their search box has never heard of "Madrid Capital", only "Madrid". If you want to be certain, build the search on fotocasa.es and paste the URL instead. That path does no guessing at all.
Two ways to tell it what you want
Paste a search URL. Go to fotocasa.es, set whatever filters you like, copy the address bar:
{
"startUrls": [
"https://www.fotocasa.es/es/comprar/viviendas/barcelona-capital/todas-las-zonas/l",
"https://www.fotocasa.es/es/alquiler/viviendas/madrid-capital/todas-las-zonas/l?minPrice=900&maxPrice=1600"
],
"maxItems": 500
}
Whatever the site put in that URL comes along with it. This is the path to use when you already know exactly what you want, or when the filter you need is not in the list below.
Or describe it. The Actor looks the place up against Fotocasa's own place list and builds the search for you:
{
"location": "Barrio de Salamanca",
"transactionType": "sale",
"propertyType": "homes",
"minPrice": 400000,
"maxPrice": 900000,
"minRooms": 2,
"minSurface": 80,
"advertiser": "private",
"sortType": "publicationDate",
"maxItems": 250
}
You can do both in the same run. The URLs get read first, then the built search, and the whole run is de-duplicated together.
Input fields
| Field | What it does |
|---|---|
location | A town, district or neighbourhood as Fotocasa's search box knows it: Madrid, Valencia, Barrio de Salamanca, Marbella |
locationLevel | Which size of area the name should resolve to: auto, MUNICIPALITY, PROVINCE, REGION, DISTRICT, NEIGHBORHOOD |
transactionType | sale or rent |
propertyType | homes, garages, offices, premises, land, rural-houses, buildings, storage-rooms |
startUrls | Fotocasa search URLs, one per line |
maxItems | Hard cap on listings delivered. Also your spending cap |
sortType | publicationDate, price, pricem2, surface, scoring |
advertiser | any, agency, private |
minPrice / maxPrice | Euros. Monthly rent for rentals |
minSurface / maxSurface | Square metres |
minRooms / maxRooms | |
minBathrooms / maxBathrooms | |
proxyConfiguration | Leave it alone unless you need a specific network |
The price, surface, room and bathroom filters are applied by Fotocasa itself, so they narrow the result set before anything is charged. The advertiser filter is the exception: Fotocasa has no server-side switch for it, so the Actor reads the page and drops the rows that do not match. You are not charged for the rows it drops. The run tells you how many there were.
What a row looks like
This is a real row, lightly trimmed for width, from a Valencia rental search:
{
"id": "190879807",
"url": "https://www.fotocasa.es/es/alquiler/vivienda/valencia-capital/aire-acondicionado-calefaccion-amueblado/190879807/d",
"transactionType": "rent",
"propertyType": "home",
"propertySubtype": "intermediate floor",
"price": 1400,
"priceText": "1.400 €",
"pricePeriod": "month",
"pricePerM2": 17.5,
"surfaceM2": 80,
"rooms": 3,
"bathrooms": 2,
"floor": "4",
"floorCode": 9,
"condition": "good",
"isNewConstruction": false,
"neighbourhood": "Els Orriols",
"district": "Rascanya",
"municipality": "Valencia",
"province": "Valencia",
"postcode": "46019",
"latitude": 39.49541071132765,
"longitude": -0.36959676906258937,
"advertiserType": "agency",
"advertiserName": "HOUSINGANYWHERE",
"advertiserUrl": "https://www.fotocasa.es/es/pro/housinganywhere/",
"phone": null,
"features": ["furnished", "washing_machine", "tv", "pets_allowed", "laundry"],
"images": ["https://static.fotocasa.es/images/ads/7f4cc921-08a3-4102-8657-88f1b434907d?rule=original"],
"imageCount": 6,
"hasFloorPlan": false,
"hasVirtualTour": false,
"description": "Esta apartmento en Valencia, ofrece un espacio habitable...",
"publishedAt": "2026-09-20T01:01:51.013Z",
"page": 1,
"position": 1,
"scrapedAt": "2026-09-20T00:06:55.372Z"
}
A few notes on individual fields, because guessing at them wastes your time:
priceis a number,priceTextis Fotocasa's own formatting. Sort and filter on the number.pricePeriodisnullon a sale andmonthon almost every rental. Other values exist
(week, day, season, year) and show up on holiday lets.
pricePerM2is worked out here, not supplied by Fotocasa — it isprice ÷ surfaceM2, rounded
to two decimals. On a rental that makes it rent per square metre *per month*, which is the number Spanish rental analysts actually use, but it is worth saying out loud.
flooris a readable string:"basement","ground floor","1"through"15", or
"above floor 15". floorCode is Fotocasa's own integer, kept alongside it. Three of their codes never appeared in the sample used to work the mapping out, so a listing carrying one of those gets floor: null and keeps its floorCode. Better a blank than a wrong floor.
featuresuses Fotocasa's own key names —terrace,elevator,pets_allowed,
air_conditioner, community_pool and so on. They are not translated, because translating them would mean inventing names that do not match anything on their site.
advertiserTypeisagencyorprivate. This is the one people ask for most, and it is
genuinely there on every row.
phoneis the number Fotocasa publishes on the search card. Quite often there isn't one.
Pricing and what actually bills
You pay per listing delivered, and for starting the run. That is the whole of it.
These are free and are labelled so you can filter them out:
- the sample row an empty run returns, marked
_sample: true - every diagnostic row, marked
_diagnostic: true: a search that returned nothing, a URL that was
not a Fotocasa address, a run that ran out of time
- rows dropped by the
advertiserfilter - duplicates removed during paging
So a run that finds nothing costs you the start fee and nothing else, and a run that stops early still only bills the listings it actually handed you. The current per-listing figure is on the Pricing tab of this page.
maxItems is a hard ceiling, checked before every row. Set it and you cannot be surprised.
What this does not do
- It does not open individual listing pages. No energy certificate, no agency reference number,
no full amenity checklist, no floor plan images. Those live one click deeper and would cost you roughly one extra page fetch per property.
- It does not do map-polygon or draw-your-own-area searches. Fotocasa supports those on the
site; this Actor works from place names and search URLs.
- It does not reach anything behind a Fotocasa login. No saved searches, no contact history, none of
professional tools.
- It does not give you a listing's history. You get the price as it stands when you run it.
previousPrice is filled only when Fotocasa itself is advertising a price drop, which is rare.
- It does not translate anything. Descriptions come back in the language the advertiser wrote
them in, which is Spanish, and occasionally Catalan.
- It cannot invent a field the advertiser left blank. See the fill rates at the top.
FAQ
Can I scrape all of Madrid? Yes. A Madrid sale search reports roughly 11,700 live listings and the pager keeps going well past where you would want to stop. Set maxItems to what you actually need. You are charged per listing, so "everything" is a bill, not a setting.
How many listings per page does it read? Thirty or thirty-one, which is what Fotocasa returns. Over four consecutive pages of a filtered Valencia rental search it delivered 120 unique listings with zero duplicates.
Does it work for rentals as well as sales? Both, and holiday lets and room shares too if you paste those URLs. transactionType covers the two common ones; the rest come through a pasted URL.
Can I filter to private sellers only? Yes, advertiser: "private". Be aware that on most Spanish searches the great majority of listings are agency listings, so a private-only run over a small area can come back nearly empty. That is the market, not the Actor.
Why does my "Valencia" search return the whole province? Because Fotocasa's place list has a province called Valencia with about 18,500 live ads and a city called Valencia with about 3,700, and on Automatic the Actor takes whichever has more. Set Area size to *Town or city* and you get the city. The run log always names the match it chose and the other candidates it saw, so you can check.
I typed "Madrid Capital" and got nothing. That is Fotocasa's URL slug, not a place name — their own search box does not recognise it either, and returns street names. Type Madrid. The Actor strips a trailing "Capital" for you, but the plain name is what to reach for.
Do I need a proxy? No. The Actor goes out from the container's own address and only reaches for rotating datacenter addresses if Fotocasa refuses it. If you have your own proxy servers you can supply them and they will be used exactly as given.
What happens if Fotocasa changes the page? The Actor reads the JSON payload Fotocasa's own front end hydrates from, not the HTML around it, so a visual redesign does not touch it. If that payload ever moves, the run writes a free NO_DATA_BLOCK diagnostic row rather than quietly returning nothing.
Can I run it on a schedule? Yes, it is an ordinary Actor. Sort by publicationDate, keep maxItems small, and de-duplicate against your own store on id to watch new listings appear in an area.