# Imovirtual Portugal Property Listings Scraper (`jungle_synthesizer/imovirtual-portugal-property-listings-scraper`) Actor

Portugal is a live, foreign-capital-heavy residential market and a hole in our Iberian coverage — we hold Spanish

- **URL**: https://apify.com/jungle_synthesizer/imovirtual-portugal-property-listings-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Real estate, Business
- **Stats:** 2 total users, 1 monthly users, 95.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 record scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Portugal Property Listings Database — Imovirtual Scraper

Scrapes property listings from [Imovirtual](https://www.imovirtual.com), Portugal's largest real estate marketplace. Returns pricing, typology, location, energy certificate, and agent contact details for apartments, houses, land, garages, warehouses, commercial units, and room rentals — sale and rent, nationwide.

***

### Imovirtual Scraper Features

- Covers the full national matrix — every deal type (comprar/sale, arrendar/rent) across seven property categories, not just one search URL
- Returns Portugal-native fields: T-typology (T0, T1, T2…), área útil, distrito/concelho/freguesia, and the A+ through F energy certificate scale
- Extracts agent and agency contact details, including phone numbers, where the listing exposes them
- Pulls GPS coordinates, construction year, floor, and condition on top of the standard price and area fields
- Filterable by deal type and property type, so a run can target just rentals in one category instead of the whole country
- Handles pagination across thousands of result pages per category automatically — you point it at Portugal, not at page 1

***

### Who Uses Imovirtual Property Data?

- **Cross-border property investors** — screen the Portuguese market by district and price band before ever booking a flight
- **Short-let and rental underwriters** — compare asking rents against the sale-price data from the same run, or build a yield model from both sides of the market
- **Price-index builders** — track price-per-square-metre trends by typology and distrito over time
- **Relocation and golden-visa advisors** — pull current inventory for clients instead of screenshotting a search page
- **Market researchers** — measure inventory mix (new build vs. existing, agency vs. private) across regions

***

### How Imovirtual Scraper Works

1. Pick your deal types (sale, rent, or both) and property types — or leave the defaults to cover everything Imovirtual lists.
2. The scraper walks every matching category nationwide, page by page, and visits each listing it finds for the fields a search results page doesn't show.
3. Records stream into the dataset as they're collected, so a large run is usable before it finishes.
4. Hit your item cap or a spend limit mid-crawl? Resume it later without paying twice for what you already have — see below.

***

### Input

```json
{
  "maxItems": 500,
  "dealTypes": ["comprar", "arrendar"],
  "propertyTypes": ["apartamento", "moradia"]
}
```

| Field           | Type    | Default                                                                              | Description |
|-----------------|---------|--------------------------------------------------------------------------------------|-------------|
| `maxItems`      | Integer | `10`                                                                                 | Maximum number of listings to scrape. `0` runs the full national matrix — roughly 220,000+ listings across all categories. |
| `dealTypes`     | Array   | `["comprar", "arrendar"]`                                                            | Sale (`comprar`), rent (`arrendar`), or both. |
| `propertyTypes` | Array   | `["apartamento", "moradia", "terreno", "garagem", "armazem", "comercial", "quarto"]` | Which of Imovirtual's own property categories to crawl. `comercial` covers offices, shops and other commercial space as one bucket — Imovirtual doesn't expose a machine-readable subtype split for those. `quarto` (room rentals) only applies when `arrendar` is selected. |
| `resumeCursor`  | String  | —                                                                                    | Cursor from a previous run's Output. Leave empty for a fresh crawl. |

Narrowing to one or two categories is a lot faster than the full default — a run scoped to `arrendar` + `garagem`, for instance, covers a few thousand listings instead of the full corpus.

***

### Imovirtual Scraper Output Fields

```json
{
  "listing_id": "19083651",
  "listing_url": "https://www.imovirtual.com/pt/anuncio/maravilhoso-t3-parque-das-nacoes-ID1i4vP",
  "title": "Maravilhoso T3 | Parque das Nações",
  "deal_type": "comprar",
  "property_type": "apartamento",
  "price_eur": 1595000,
  "price_raw": "1 595 000 €",
  "price_period": "sale",
  "price_per_sqm_eur": 8055.56,
  "typology": "T2",
  "rooms": 3,
  "bathrooms": 2,
  "area_useful_sqm": 198,
  "area_gross_sqm": 198,
  "land_area_sqm": null,
  "floor": "3º andar (de 5)",
  "has_elevator": true,
  "energy_certificate": "B",
  "condition": "usado",
  "construction_year": 1988,
  "district": "Lisboa",
  "municipality": "Lisboa",
  "parish": "Parque das Nações",
  "address": "Rua das Musas - Expo",
  "latitude": 38.768,
  "longitude": -9.094,
  "features": ["ar condicionado", "varanda", "elevador"],
  "description": "Apartamento T3 com vista rio, totalmente remodelado...",
  "advertiser_type": "agency",
  "agency_name": "ZÉNITE IMOVEIS",
  "agency_id": "5199464",
  "agency_url": "https://www.imovirtual.com/pt/empresas/agencias-imobiliarias/zenite-imoveis-ID5199464",
  "agent_name": "Nuno Silveira",
  "agent_phone": "+351937594409",
  "is_exclusive": false,
  "is_promoted": true,
  "image_urls": ["https://..."],
  "images_count": 12,
  "created_at": "2026-03-19T10:56:34Z",
  "pushed_up_at": "2026-10-01T20:00:34+01:00",
  "scraped_at": "2026-10-01T19:33:22.753Z"
}
```

| Field                | Type    | Description                                                                         |
|----------------------|---------|-------------------------------------------------------------------------------------|
| `listing_id`         | String  | Imovirtual's own ad ID                                                              |
| `listing_url`        | String  | Direct link to the listing                                                          |
| `title`              | String  | Listing headline                                                                    |
| `deal_type`          | String  | `comprar` (sale) or `arrendar` (rent)                                               |
| `property_type`      | String  | `apartamento`, `moradia`, `terreno`, `garagem`, `armazem`, `comercial`, or `quarto` |
| `price_eur`          | Number  | Asking price (or monthly rent) in EUR                                               |
| `price_raw`          | String  | Formatted price as shown on the listing                                             |
| `price_period`       | String  | `sale` or `month`                                                                   |
| `price_per_sqm_eur`  | Number  | Price per square metre — sale listings only                                         |
| `typology`           | String  | Portuguese T-typology (T0 = studio, T1, T2…)                                        |
| `rooms`              | Number  | Total divisions (assoalhadas)                                                       |
| `bathrooms`          | Number  | Bathroom count                                                                      |
| `area_useful_sqm`    | Number  | Área útil in square metres                                                          |
| `area_gross_sqm`     | Number  | Área bruta in square metres                                                         |
| `land_area_sqm`      | Number  | Plot/land area — `terreno` listings only                                            |
| `floor`              | String  | Floor, in Portuguese (e.g. "3º andar (de 5)", "Rés-do-chão")                        |
| `has_elevator`       | Boolean | Whether the building has a lift                                                     |
| `energy_certificate` | String  | A+ through F, or "Isento" (exempt)                                                  |
| `condition`          | String  | `novo`, `usado`, `em construção`, or `para recuperar`                               |
| `construction_year`  | Number  | Year built, where disclosed                                                         |
| `district`           | String  | Distrito                                                                            |
| `municipality`       | String  | Concelho                                                                            |
| `parish`             | String  | Freguesia                                                                           |
| `address`            | String  | Street-level address, where disclosed                                               |
| `latitude`           | Number  | GPS latitude                                                                        |
| `longitude`          | Number  | GPS longitude                                                                       |
| `features`           | Array   | Amenities in Portuguese (varanda, garagem, piscina, ar condicionado…)               |
| `description`        | String  | Full listing description, as plain text                                             |
| `advertiser_type`    | String  | `private`, `agency`, or `developer`                                                 |
| `agency_name`        | String  | Listing agency's name, where applicable                                             |
| `agency_id`          | String  | Imovirtual's agency ID                                                              |
| `agency_url`         | String  | Link to the agency's storefront                                                     |
| `agent_name`         | String  | Named contact on the listing                                                        |
| `agent_phone`        | String  | Contact phone number, where disclosed                                               |
| `is_exclusive`       | Boolean | Flagged as an exclusive listing                                                     |
| `is_promoted`        | Boolean | Flagged as promoted/featured                                                        |
| `image_urls`         | Array   | Full-size photo URLs                                                                |
| `images_count`       | Number  | Number of photos on the listing                                                     |
| `created_at`         | String  | When the listing was first published                                                |
| `pushed_up_at`       | String  | Last time the seller refreshed the listing's ranking                                |
| `scraped_at`         | String  | When this record was collected                                                      |

***

### Resuming a large crawl

Every run emits a `resumeCursor` in its Output. If a large crawl stops before it finishes — because it hit `maxItems`, your spend cap (`maxTotalChargeUsd`), or was aborted — start a new run with **the same input** plus that `resumeCursor` to continue from where it left off. The crawl resumes from the queued work the previous run didn't reach.

- You are **not re-charged** for records the earlier run already delivered.
- Resume within your account's run-retention window — on the free tier, roughly your 10 most recent runs. Once the source run is pruned, its `resumeCursor` is no longer valid.
- `resumeCursor` is opaque — supply it unmodified.

***

### FAQ

#### How do I scrape Imovirtual property listings?

Imovirtual Scraper needs no account, login, or API key. Set `maxItems` and your deal/property type filters, run it, and listings stream into your dataset as they're found.

#### What data can I get from Imovirtual?

Pricing, typology, area, energy certificate, location down to the freguesia, GPS coordinates, and agent contact details — 38 fields per listing, covering both the sale and rental markets.

#### Can I filter by deal type or property type?

Yes. Set `dealTypes` to `["comprar"]` or `["arrendar"]`, and `propertyTypes` to any combination of apartamento, moradia, terreno, garagem, armazem, comercial, or quarto. Narrow runs finish faster — the default covers everything.

#### How much does Imovirtual Scraper cost to run?

Pricing follows the pay-per-event model shown on this page, charged per record saved. There's no separate charge for pages visited to find those records.

#### Does this cover rentals as well as sales?

Both. `comprar` is the sale market, `arrendar` is rentals — including room rentals (`quarto`), which don't exist on the sale side.

***

### Need More Features?

Need custom fields, filters, or a different target site? [File an issue](https://console.apify.com/actors/issues) or get in touch.

### Why Use Imovirtual Scraper?

- **National coverage** — walks every deal type and property category Imovirtual publishes, not a single search URL
- **Portugal-native schema** — T-typology, área útil, distrito/concelho/freguesia, and the real energy certificate scale, instead of a generic listing record translated badly
- **Resumable** — a crawl that stops partway picks back up without re-billing records you already have

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

## `maxItems` (type: `integer`):

Maximum number of property listings to scrape across the selected deal/property types. 0 = unlimited (a full national crawl is ~220k+ listings).

## `dealTypes` (type: `array`):

Which deal types to crawl. Defaults to both sale (comprar) and rent (arrendar) listings nationwide.

## `propertyTypes` (type: `array`):

Which property types to crawl, using Imovirtual's own site categories. 'comercial' covers offices, shops and other commercial units — the site does not expose a machine-readable subtype split for those. 'quarto' (room rentals) only applies to arrendar.

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "maxItems": 10,
  "dealTypes": [
    "comprar",
    "arrendar"
  ],
  "propertyTypes": [
    "apartamento",
    "moradia",
    "terreno",
    "garagem",
    "armazem",
    "comercial",
    "quarto"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "maxItems": 10,
    "dealTypes": [
        "comprar",
        "arrendar"
    ],
    "propertyTypes": [
        "apartamento",
        "moradia",
        "terreno",
        "garagem",
        "armazem",
        "comercial",
        "quarto"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/imovirtual-portugal-property-listings-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "maxItems": 10,
    "dealTypes": [
        "comprar",
        "arrendar",
    ],
    "propertyTypes": [
        "apartamento",
        "moradia",
        "terreno",
        "garagem",
        "armazem",
        "comercial",
        "quarto",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/imovirtual-portugal-property-listings-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "maxItems": 10,
  "dealTypes": [
    "comprar",
    "arrendar"
  ],
  "propertyTypes": [
    "apartamento",
    "moradia",
    "terreno",
    "garagem",
    "armazem",
    "comercial",
    "quarto"
  ]
}' |
apify call jungle_synthesizer/imovirtual-portugal-property-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jungle_synthesizer/imovirtual-portugal-property-listings-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lhkJxxg7eOcNWWO9F/builds/vnNOzqn8XC0f0l3Nh/openapi.json
