Imovirtual Scraper - Portugal Real Estate Listings
Pricing
from $0.30 / 1,000 property listing extracteds
Imovirtual Scraper - Portugal Real Estate Listings
Scrape Imovirtual apartments, houses, land and rentals across Portugal. Search by location or URL and get price, T typology, bedrooms, area, parish, features, photos, seller and first-listed date, plus optional GPS and full description.
Pricing
from $0.30 / 1,000 property listing extracteds
Rating
5.0
(1)
Developer
Automation Lab
Maintained by CommunityActor stats
0
Bookmarked
67
Total users
25
Monthly active users
2 hours ago
Last modified
Categories
Features
Share
Imovirtual Portuguese Real Estate Scraper
Extract property listings from Imovirtual, a leading Portuguese real estate portal, for apartments, houses, land and garages, for sale or rent. Get prices, T typology, bedrooms, parish-level location, features, photos, seller details and first-listed dates.
What does it do?
Imovirtual Scraper extracts structured listings by location or from Imovirtual search result URLs. You can apply inclusive price, area and bedroom bounds or keep only private-owner listings; pagination continues until your maxItems matching-listing limit is reached, the search is exhausted, or Imovirtual blocks a long scan.
- Search by location — set
location(porto,lisboa/sintra,lisboa/lisboa/benfica),transactionandpropertyType, or paste a search URL - Four property types — apartments, houses, land and garages
- Sale or rent —
transaction, or comprar/arrendar in the URL - Any Portuguese location — Lisbon, Porto, Braga, Faro and all regions/councils/parishes (the Algarve is
faroon Imovirtual) - Portuguese typology —
typology(T0, T2, T3) and numericbedrooms - Rich search rows — price, area, floor, features, photos, first-listed date, council, parish and neighbourhood
- Optional full details —
includeDetailsadds full description, GPS coordinates, bathrooms, build year, energy certificate, condition, heating and amenities - Direct listing filters — inclusive
minPrice,maxPrice,minAreaM2,maxAreaM2,minBedroomsandmaxBedroomsbounds - Private-owner workflow — set
privateOwnerOnlyto skip agency listings - Duplicate-safe multi-URL runs — overlapping searches emit and charge each listing only once
The scraper reads data from Imovirtual's server-side-rendered HTML (Next.js __NEXT_DATA__ JSON), so it works without a headless browser or proxy setup.
Scrape public Imovirtual property listings for repeatable Portugal market research. Extract structured fields such as price, location/address, property type, area, T typology, bedrooms, features, images, agency/agent data where available, and listing URLs. Export to JSON/CSV/Excel, schedule recurring runs, or call the actor through the Apify API.
Best for PropTech teams, investors, brokerages, and researchers tracking Portugal sale/rental supply, pricing, and listing changes.
Who is it for?
🏠 Real Estate Investors
Monitor the Portuguese market for price trends, deal-finding, and portfolio research in Lisbon, Porto, the Algarve, and emerging regions.
📊 Market Research Analysts
Build datasets of active listings to track median prices, price-per-sqm by parish, transaction volume, and market saturation in any area.
🌍 Expat & Digital Nomad Platforms
Portugal is among Europe's most popular expat destinations. Aggregate Imovirtual data for relocation guides, rental market overviews, or comparison tools.
🏢 Real Estate Agencies & Proptech
Monitor competitor listings, track new-to-market properties, or enrich your CRM with market-wide listing data.
📈 Financial & Academic Research
Study Iberian real estate pricing, urban growth patterns, and housing affordability using live listing data.
🤖 AI & Data Science Teams
Build property valuation models, location scoring algorithms, or investment analytics tools using structured Imovirtual data.
Why use this scraper?
- No browser needed — HTTP + SSR JSON extraction; fast and cost-efficient.
- Full pagination — Automatically handles Imovirtual's 36-items-per-page search results.
- Complete location hierarchy — district, council, parish, neighbourhood and street.
- Both sale and rental — Set
transaction, or use comprar/arrendar in the search URL. - Photo URLs included — Large-resolution images for every listing.
- Agency or private owner — Distinguishes between agency-listed and owner-listed properties.
- Honest run status — every run ends with how many listings it delivered against your limit and why it stopped.
What data does it extract?
| Field | Description | Example |
|---|---|---|
listingId | Unique Imovirtual listing ID | 19100936 |
url | Full URL to the listing page | https://www.imovirtual.com/pt/anuncio/... |
title | Listing title | T3 na Penha de França, Lisboa |
shortDescription | Short description when the search result has one (usually empty now; use includeDetails for the description) | null |
estate | Property type | FLAT, HOUSE, TERRAIN, GARAGE |
transaction | Sale or rent | SELL, RENT |
price | Asking price | 428000 |
currency | Price currency | EUR |
pricePerSqm | Price per square metre (derived from rent and area for rentals) | 6114 |
areaM2 | Usable floor area (m²) | 70 |
terrainAreaM2 | Plot/terrain area (m²) | null |
rooms | Imovirtual total-room label, counting the living room (THREE is a T2) | ONE, TWO, THREE, FOUR, MORE |
bedrooms | Bedrooms from the T number; T0 is 0 | 2 |
typology | Portuguese typology | T2 |
floor | Floor label | GROUND, FIFTH |
floorNumber | Floor as a number; ground is 0 | 5 |
city | Address city, otherwise the council | Lisboa |
council | Council (concelho) | Lisboa |
district | Administrative district | Lisboa |
province | Address province, otherwise the district | Lisboa |
parish | Parish | Penha de França |
neighborhood | Neighbourhood or street area | Avenida do Uruguai |
street | Street name | Rua Doutor Oliveira Ramos |
agencyName | Agency or private owner name | ComprarCasa Foros de Amora |
agencyId | Agency ID on Imovirtual | 1277149 |
agencyType | Agency type | AGENCY |
advertiserType | Advertiser class | private_person, business |
isPrivateOwner | Private owner listing? | false |
isExclusive | Exclusive offer? | false |
developmentTitle, developmentUrl | New-development project | null |
features | Feature tags | ["BALCONY", "GARDEN"] |
photos | Array of large photo URLs | ["https://..."] |
photoCount | Photos on the listing | 9 |
dateCreated | Listing creation date | 2026-10-22T10:32:37Z |
firstListedAt | First appearance on Imovirtual, for time on market | 2026-10-22T10:32:37+00:00 |
pushedUpAt | Last bumped/renewed date | 2026-11-08T11:36:10Z |
isPromoted | Promoted/featured ad? | false |
searchUrl | Search that produced the row | https://www.imovirtual.com/pt/resultados/... |
scrapedAt | When the run read the listing | 2026-11-08T12:00:00.000Z |
With includeDetails on, each row also has description, latitude, longitude, bathrooms, buildYear, energyCertificate, condition, buildingType, heating, market (PRIMARY or SECONDARY), amenities, availableFrom and modifiedAt. These fields are null or empty without it. Phone numbers are not included.
How to use it
Step 1 — Choose a location or run your search
The quickest way is to fill Location, Transaction and Property type in the input. To use the site's own filters, visit imovirtual.com and filter by:
- Transaction type (buy or rent)
- Property type (apartment, house, land or garage)
- Location (city, district, parish)
Copy the resulting URL from your browser address bar.
Step 2 — Paste the URL into the actor
In the Start URLs field, paste one or more Imovirtual search result URLs. Filled Start URLs take priority over Location.
Example URLs:
https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboahttps://www.imovirtual.com/pt/resultados/arrendar/apartamento/porto/portohttps://www.imovirtual.com/pt/resultados/comprar/moradia/faro
Use search URLs for apartments (apartamento), houses (moradia), land (terreno) or garages (garagem). Imovirtual ignores other property words in the URL, such as comercial or loja, and returns ordinary apartments from across Portugal, which would still be charged.
Step 3 — Set optional filters and your limit
Use minPrice / maxPrice for an inclusive budget range, minAreaM2 / maxAreaM2 for inclusive usable-area bounds, minBedrooms / maxBedrooms for typology, or enable privateOwnerOnly. Set Max items to control how many matching listings to extract. See the Pricing section below for per-listing costs by plan tier.
Step 4 — Run and export
Download results as JSON, CSV, Excel, or XML from the dataset.
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
startUrls | string[] | empty | Imovirtual search result URLs to scrape; take priority over location |
location | string | empty | Location such as porto, lisboa/sintra, lisboa/lisboa/benfica, or todo-o-pais |
transaction | string | sale | sale or rent, with location |
propertyType | string | apartment | apartment, house, land or garage, with location |
minPrice | number | empty | Inclusive minimum listing price |
maxPrice | number | empty | Inclusive maximum listing price |
minAreaM2 | number | empty | Inclusive minimum usable floor area in m² |
maxAreaM2 | number | empty | Inclusive maximum usable floor area in m² |
minBedrooms | integer | empty | Inclusive minimum bedrooms; 2 means T2 or larger |
maxBedrooms | integer | empty | Inclusive maximum bedrooms |
privateOwnerOnly | boolean | false | Keep only listings marked as private-owner listings |
includeDetails | boolean | false | Open each listing page for full description, GPS, bathrooms and more |
maxItems | integer | 100 | Maximum unique matching listings to extract across all URLs |
maxRequestRetries | integer | 3 | Retry attempts for failed HTTP requests |
Example input
{"startUrls": ["https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboa","https://www.imovirtual.com/pt/resultados/comprar/moradia/porto"],"minPrice": 150000,"maxPrice": 400000,"minAreaM2": 60,"maxItems": 100}
Example output
{"listingId": 19297476,"url": "https://www.imovirtual.com/pt/anuncio/apartamento-t3-para-venda-ID1iY9C","title": "Apartamento T3 para venda","shortDescription": null,"estate": "FLAT","transaction": "SELL","price": 950000,"currency": "EUR","pricePerSqm": 5191.26,"areaM2": 183,"terrainAreaM2": null,"rooms": "FOUR","bedrooms": 3,"typology": "T3","floor": "FIFTH","floorNumber": 5,"city": "Lisboa","council": "Lisboa","district": "Lisboa","province": "Lisboa","parish": "Arroios","neighborhood": "Alameda - Praça do Chile - Almirante Reis","street": "Alameda Dom Afonso Henriques","agencyName": "RE/MAX PLACE STRADA","agencyId": 4193825,"agencyType": "AGENCY","advertiserType": "business","isPrivateOwner": false,"isExclusive": false,"developmentTitle": null,"developmentUrl": null,"features": ["TOP_FLOOR"],"photos": ["https://ireland.apollo.olxcdn.com/v1/files/eyJ...image;s=1280x1024;q=80"],"photoCount": 39,"dateCreated": "2026-10-03T16:10:02Z","firstListedAt": "2026-10-03T16:10:02+00:00","pushedUpAt": "2026-11-08T11:25:19Z","isPromoted": false,"searchUrl": "https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboa","scrapedAt": "2026-11-08T12:02:03.130Z"}
This row is shortened to one photo, and the includeDetails fields, which are null or empty here, are left out.
How much does it cost to scrape Imovirtual listings?
This actor uses pay-per-result pricing — you only pay for listings successfully extracted, never per run.
| Apify plan | Price per listing |
|---|---|
| Free | $0.000575 |
| Bronze | $0.0005 |
| Silver | $0.00039 |
| Gold | $0.0003 |
| Platinum | $0.0002 |
| Diamond | $0.00014 |
From November 23, 2026 the price will be $0.002 per listing on Free and Bronze, $0.0018 on Silver, and $0.0016 on Gold, Platinum and Diamond. The tables and estimates on this page show the price before that date.
Calculated bulk-cost examples (not event unit prices)
| Apify plan | 1,000 listings | 10,000 listings |
|---|---|---|
| Free | $0.575 | $5.75 |
| Bronze | $0.50 | $5.00 |
| Silver | $0.39 | $3.90 |
| Gold | $0.30 | $3.00 |
| Platinum | $0.20 | $2.00 |
| Diamond | $0.14 | $1.40 |
A typical Lisbon apartment search returns up to 7,000+ listings.
No flat fee per run — you only pay for what you extract.
Tips
- Keep runs fast with search rows — Leave
includeDetailsoff unless you need coordinates or the full description; search rows already include price, typology, location and features. - Combine multiple search URLs — Pass several URLs in
startUrlsto merge results across regions in a single run. ThemaxItemslimit applies globally, and overlapping searches keep the first occurrence of each listing without storing or charging duplicates. - Combine URL and Actor filters — Keep transaction, property type, location, and room criteria in the Imovirtual URL, then use
minPrice,maxPrice,minAreaM2,maxAreaM2, orprivateOwnerOnlydirectly in Actor input. Numeric bounds are inclusive. - Recommended maxItems by use case:
- Quick market snapshot: 100–500 items (~$0.05–$0.25 at BRONZE)
- Regional analysis: 1,000–5,000 items (~$0.50–$2.50 at BRONZE)
- Full national scrape: 50,000+ items (~$25 at BRONZE, ~$7 at DIAMOND tier)
- Schedule regular runs — Use Apify's scheduler to run the actor daily or weekly and track price trends over time.
- Export to CSV for Excel/Sheets analysis — Use the dataset's CSV export for quick pivot table analysis in Excel or Google Sheets.
Integrations
Connect Imovirtual data to the tools your team already uses:
- Google Sheets — Use the Apify → Google Sheets integration to push new listings into a spreadsheet automatically. Great for tracking Lisbon price trends week-over-week.
- Airtable — Route extracted listings into an Airtable base as property pipeline records. Filter by parish, price range, or room count using Airtable views.
- Slack notifications — Set up a webhook trigger to post new Algarve listings to a Slack channel whenever the actor runs, so your team never misses a fresh deal.
- Make (Integromat) / n8n — Wire the actor's dataset output into multi-step automation workflows — filter by price, enrich with Google Maps data, or post to a CRM.
- BigQuery / data warehouse — Export large datasets directly to cloud storage via Apify's built-in integrations for long-term price trend analysis.
- OpenAI / Claude — Use the MCP integration (see below) to ask AI assistants to analyse the scraped data, generate summaries, or filter listings by natural language criteria.
Use with AI via MCP
Imovirtual Scraper is compatible with the Apify MCP server, letting you use it directly from AI assistants like Claude, Cursor, or VS Code Copilot.
Claude Code setup
$claude mcp add --transport http "https://mcp.apify.com?tools=automation-lab/imovirtual-scraper&token=YOUR_APIFY_TOKEN"
Claude Desktop / Cursor / VS Code JSON config
{"mcpServers": {"apify": {"type": "http","url": "https://mcp.apify.com?tools=automation-lab/imovirtual-scraper&token=YOUR_APIFY_TOKEN"}}}
Example AI prompts
Once connected, you can ask your AI assistant:
- "Scrape all Lisbon apartments for sale under €400,000 and show me the cheapest 10 by price-per-sqm."
- "Get the first 200 rental listings in Porto and calculate the average monthly rent by parish."
- "Find all private-owner listings in Faro — skip agency listings — and export them as a CSV."
Limitations
- Search rows by default — Without
includeDetails, the Actor reads only search result pages, so the full description, GPS, energy certificate and other detail fields are empty. Turn onincludeDetailsto open each listing page at the same price per listing. Phone numbers are not available either way. - Four property types — Apartments, houses, land and garages. Commercial searches are not supported.
- Imovirtual Portugal only — This actor targets
imovirtual.com. For Spain, use a separate Idealista or Fotocasa scraper. - Max 36 listings per page — Imovirtual paginates at 36 items/page. The actor handles pagination automatically and, for filtered runs, may inspect additional pages to find
maxItemsmatching listings. - Long scans can stop early — Filters are applied after each page is read, so a very sparse filter (such as a narrow price range with
privateOwnerOnly) can scan hundreds of pages to find a few listings, andincludeDetailsopens one extra page per listing. Imovirtual can answer either with HTTP 403. The run then keeps what it found and its status says how many listings it delivered and why it stopped. Narrow the search with a location or property type in the URL rather than relying on filters alone.
FAQ
Can I scrape all listings in Portugal?
Yes — use broad regional URLs (e.g. /comprar/apartamento/ without a location filter) and set maxItems to a high value. Imovirtual has ~200,000+ active listings.
Does it work for rental listings?
Yes — use URLs with /arrendar/ instead of /comprar/.
Can I scrape land and garages?
Yes — set propertyType to land or garage, or use /terreno/ or /garagem/ in the URL path.
Can I scrape commercial properties?
Not at the moment. Imovirtual ignores /comercial/ in the URL and returns ordinary apartments from across Portugal, so do not use it.
How do I search the Algarve?
Use faro, which is how Imovirtual names the Algarve: set location to faro or use /faro in the URL. algarve returns a 404 and the run fails at no charge.
Are price and usable-area bounds inclusive?
Yes. A listing exactly equal to minPrice, maxPrice, minAreaM2, or maxAreaM2 is included. Listings with a missing price or usable area are excluded only when that corresponding numeric filter is set.
How do I keep only private-owner listings?
Set privateOwnerOnly to true. The Actor filters on the existing normalized isPrivateOwner value and does not charge for filtered-out agency listings.
What happens when search URLs overlap?
Each Imovirtual listing is emitted at most once per run. Duplicate rows do not count toward maxItems and are not charged; the first occurrence keeps the input URL and page order.
Do I need a proxy? No. The Actor requests Imovirtual directly, and there is no proxy setting to configure.
How fresh is the data? Data is live at the time of the run. Imovirtual updates listings continuously.
What if the scraper returns 0 results?
Read the run's status message: it says how many listings were delivered and why the run stopped. Check that your URL points to a search results page (not a listing detail page) and contains /resultados/, or that the location exists on Imovirtual. A search with no matching listings ends as succeeded with 0 results and no charge.
Why is my run failing or returning partial results? The run status names the cause. If Imovirtual fails partway through, saved rows are kept and charged, and the status gives the delivered count; run again for the rest. If nothing could be read, the run fails and costs nothing.
Legality and disclaimer
This actor scrapes publicly accessible data from Imovirtual's website. It does not bypass any authentication or access controls. Users are responsible for ensuring their use of scraped data complies with applicable laws and Imovirtual's terms of service. This tool is intended for research, analysis, and internal business purposes only.
Data handling
- What is collected: the locations and URLs you enter, and public listing data from Imovirtual, including agency and advertiser names. No login, buyer data or phone numbers are used.
- Who sees what: Imovirtual sees the requests. No AI service receives your input or results.
- Storage and deletion: your input, dataset and run logs stay in your Apify account under its retention settings, and you can delete them there. The Actor keeps nothing between runs. Do not put secrets in search URLs.
- Error reports: failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair; secret fields and URL queries are removed and reports are retained for 30 days.
- Not affiliated: this Actor is not affiliated with or endorsed by Imovirtual.
- Support: use the Issues tab on this Actor's page.
API usage
You can run this actor programmatically via the Apify API or SDK.
Node.js (ApifyClient)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });const run = await client.actor('automation-lab/imovirtual-scraper').call({startUrls: ['https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboa'],maxItems: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python (ApifyClient)
from apify_client import ApifyClientclient = ApifyClient(token='YOUR_API_TOKEN')run = client.actor('automation-lab/imovirtual-scraper').call(run_input={'startUrls': ['https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboa'],'maxItems': 100,})for item in client.dataset(run['defaultDatasetId']).iterate_items():print(item)
cURL
curl -X POST \'https://api.apify.com/v2/acts/automation-lab~imovirtual-scraper/runs?token=YOUR_API_TOKEN' \-H 'Content-Type: application/json' \-d '{"startUrls": ["https://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa/lisboa"],"maxItems": 100}'
Build a production real-estate data workflow
Use this actor as one source in a repeatable property-data pipeline: scrape listings from the source site, export structured JSON/CSV/Excel, schedule refreshes, and send results to your dashboard, CRM, warehouse, or AI/LLM workflow.
Scrape public Imovirtual property listings for repeatable Portugal market research. Extract structured fields such as price, location/address, property type, area, rooms/beds/baths, images, agency/agent data where available, and listing URLs. Export to JSON/CSV/Excel, schedule recurring runs, or call the actor through the Apify API.
Best for PropTech teams, investors, brokerages, and researchers tracking Portuguese sale/rental supply, pricing, and listing changes.
For broader coverage, combine it with related Automation Lab actors:
- UK and Europe: Rightmove Scraper, ImmoScout24 Germany Real Estate Scraper, Imovirtual Scraper, RE/MAX Portugal Scraper, Sreality.cz Real Estate Scraper, Pisos.com Real Estate Scraper
- US residential listings: Zillow Scraper, Redfin Scraper, Realtor.com Scraper
- Middle East / South Asia: PropertyFinder Scraper, Zameen Property Scraper
Related actors
Looking for real estate data from other European portals? Browse the Apify Store real estate collection for scrapers covering Spain, Italy, France, and more.
Server API: search Imovirtual listings over HTTP
Imovirtual Scraper is also a Server Actor. Besides normal runs, it answers short HTTP requests directly, without starting a run for each search. Copy the server URL from the Actor's Server tab (do not build it from the Actor name) and authenticate with your Apify token. Use normal Actor runs for several searches or more than 100 listings.
curl -sS "$SERVER_URL/search?location=lisboa/lisboa&transaction=sale&propertyType=apartment&maxItems=20" -H "Authorization: Bearer $APIFY_TOKEN"curl -sS "$SERVER_URL/search?location=porto&transaction=rent&minBedrooms=2&maxPrice=1500&includeDetails=true&maxItems=10" -H "Authorization: Bearer $APIFY_TOKEN"
| Method and path | Input | Output and charge |
|---|---|---|
GET / | None | ready: true, the routes and limits; no scraping or charge |
GET /search | Query location (Imovirtual location words separated by /, such as lisboa/lisboa, porto or todo-o-pais) or url (one Imovirtual search results URL), not both; with location, optional transaction (sale or rent, default sale) and propertyType (apartment, house, land, garage; default apartment); optional maxItems 1–100 (default 20), includeDetails (true/false, default false; adds description, coordinates, energy certificate and more from each listing page; slower), minPrice, maxPrice, minAreaM2, maxAreaM2, minBedrooms, maxBedrooms, privateOwnerOnly (true/false) | {ok,count,results} with the same listing records as a normal run's dataset items, in Imovirtual's order; one Property listing extracted event (result) per returned listing; no start fee |
A search with no matching listings, or a location Imovirtual does not know, returns an error and is free. Each request has a 60-second deadline and a 1 MiB response cap, and one server works on at most four requests at once. Nothing is cached. Errors use { "ok": false, "error": { "code": "...", "message": "...", "retryable": false } }: 400 INVALID_INPUT (also for a url that is not a search results page); 402 spending limit; 404 NO_RESULTS or unknown route; 405 wrong method; 413 RESPONSE_TOO_LARGE; 502 UPSTREAM_ERROR or charging failure; 503 server busy or stopping; 504 TIMEOUT. Failed requests are free. Retry only when retryable is true. The Server tab shows the full OpenAPI description.