# Immobiliare.it Scraper - Italy Property Listings & Prices (`scrapewise/immobiliare-scraper`) Actor

Scrape Immobiliare.it sale and rent listings in Italy: price, price per m², surface, rooms, zone, agency, photos and price cuts. Search by URL or city with filters. Schedule it daily: only new listings and price drops. Error rows are free.

- **URL**: https://apify.com/scrapewise/immobiliare-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 3 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.85 / 1,000 listing delivereds

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

## Immobiliare.it Scraper: Italy property listings, price per m² and price drops

Scrape [Immobiliare.it](https://www.immobiliare.it), Italy's largest real estate portal, **without an account,
cookies or a browser**. Paste a search URL with your filters, or give a city, zone, province or region with
contract (sale or rent), property type, price, surface and rooms. Every listing comes with price, **price per m²**,
surface, rooms, bathrooms, floor, zone and neighbourhood, address as published (agency listings), coordinates, photos, the agency
and the price cut Immobiliare.it shows on the listing.

Built for **daily monitoring**: schedule the same search every morning and get **only the listings that are new**,
or **only the ones whose price changed**, with the previous price and the drop in euros and percent. A quiet day
costs nothing.

### At a glance

- **Price per 1,000 listings, Free plan:** US$ 1.00
- **Full listing page (optional):** US$ 2.00 per 1,000, on top
- **Fee per run start:** None
- **Search by Immobiliare.it URL or by location + filters:** Yes
- **Sale, rent and auctions; homes, rooms, offices, shops, warehouses, garages, land:** Yes
- **Only new listings since the last run (`onlyNew`):** Yes, free when nothing is new
- **Price tracking between runs (`trackPriceChanges`, `onlyChanges`):** Yes
- **Price per m²:** Yes, on every row
- **Advertiser contact data:** Never (see below)
- **Error rows (bad URL, unknown place, no results):** Free, with an `errorCode`

### One real row

From a test run on 2026-10-06 (location "Milan", rent, apartment, full listing pages on), shortened:

```json
{
  "type": "listing",
  "id": "133279376",
  "url": "https://www.immobiliare.it/annunci/133279376/",
  "title": "2-room flat via Magolfa 32, Navigli - Darsena, Milan",
  "contract": "rent",
  "propertyType": "2-room flat",
  "price": 1300,
  "priceText": "€ 1,300/month",
  "currency": "EUR",
  "pricePerSqm": 20.0,
  "surfaceSqm": 65.0,
  "rooms": 2,
  "bedrooms": 1,
  "bathrooms": 1,
  "floor": "1°, with lift",
  "isPriceReduced": false,
  "originalPrice": null,
  "city": "Milan",
  "zone": "Navigli",
  "neighbourhood": "Navigli - Darsena",
  "address": "via Magolfa",
  "latitude": 45.45,
  "longitude": 9.1737,
  "mainPhoto": "https://pwm.im-cdn.it/image/2022965726/xxl.jpg",
  "photoCount": 25,
  "advertiserType": "agency",
  "agencyName": "Bricks Srl",
  "isNew": true,
  "energyClass": "B",
  "energyPerformanceIndex": 52,
  "heating": "central, floor heating, powered by methane",
  "buildingYear": 2015,
  "floorsInBuilding": 4,
  "condoFees": "€ 250/month",
  "condoFeesMonthly": 250.0,
  "deposit": 3900.0,
  "contractDetails": "Rent, 4+4",
  "features": ["Closet", "External exposure", "Optic fiber", "Security door"],
  "virtualTourUrls": ["https://my.matterport.com/show/?m=ZgU6MLBZA68"],
  "createdAt": "2026-10-06T09:47:48Z",
  "updatedAt": "2026-10-06T13:10:15Z",
  "hasDetails": true
}
```

A listing that Immobiliare.it marks as reduced carries the cut too, for example
`"isPriceReduced": true, "originalPrice": 1250, "price": 1100, "priceReductionPct": 12.0, "priceReducedAt": "2026-09-17"`.

### What you can do with it

- **Investors:** watch a city or a zone every morning for new listings under a price per m², and catch every price
  drop on what you already saw (`trackPriceChanges` + `onlyChanges`).
- **Agencies and brokers:** follow the competition's new mandates and price cuts in your area, and see which
  agencies publish the most in each neighbourhood.
- **Relocation and rental search:** a daily alert of new rentals in Milan, Rome, Bologna or Turin that match budget,
  size and rooms, straight into Slack, e-mail or Google Sheets.
- **Price per m² research:** median rent or sale price per m² by zone and neighbourhood, by property type or energy
  class, for valuation, market reports and dashboards.
- **Datasets and AI:** clean, typed rows (numbers as numbers, dates as ISO) with coordinates, ready for maps and models.

### Input

| Field | What it does |
|---|---|
| `startUrls` | Immobiliare.it search URLs with your filters (every filter in the URL is kept), or listing URLs (`/annunci/<id>/`, returned with the full page) |
| `locations` | Cities, provinces, regions or neighbourhoods in English or Italian (`Milan`, `Rome`, `Trastevere`, `Lombardy`); one search each |
| `contract` | `rent` (default) or `sale` |
| `propertyType` | `homes` (all residential, default), `apartment`, `penthouse`, `villa`, `detachedHouse`, `loft`, `room` (rent), `office`, `shop`, `warehouse`, `storage`, `garage`, `land` |
| `minPrice`, `maxPrice` | Euros (monthly rent for rentals) |
| `minSurface`, `maxSurface` | Square metres |
| `minRooms`, `maxRooms` | 1 to 5 (5 = 5 or more) |
| `sortBy` | `newest` (default), `relevance`, `priceLowToHigh`, `priceHighToLow` |
| `includeAuctions` | Default on. Off = sale searches without judicial auctions |
| `maxItems` | Listings per search, default 50. 0 = up to 2,000, the site's own limit |
| `includeDetails` | Default off. Opens each listing's page (one more request, charged apart) |
| `onlyNew` | Default off. Only listings not delivered by this search before |
| `trackPriceChanges` | Default off. Adds the price from your previous run and the change |
| `onlyChanges` | Default off. Only new or repriced listings (turns on price tracking) |
| `proxyConfiguration` | Apify Proxy, datacenter by default |

Apartments for rent in Milan up to EUR 2,000, at least 2 rooms, newest first:

```json
{ "locations": ["Milan"], "contract": "rent", "propertyType": "apartment", "maxPrice": 2000, "minRooms": 2, "maxItems": 100 }
```

Rome for sale, straight from a search URL you set up on the site:

```json
{ "startUrls": ["https://www.immobiliare.it/vendita-case/roma/?prezzoMassimo=400000&superficieMinima=70"], "maxItems": 200 }
```

### Schedule it daily: new listings and price drops

Save your search as a Task, attach a daily Schedule and turn on one of these:

- **`onlyNew`:** each run delivers, and charges, only listings this search has not returned before. The search runs
  newest first and stops at the first page with nothing new, so a daily run reads one or two pages. The first run
  delivers up to `maxItems` and marks everything it read as seen.
- **`trackPriceChanges`:** every row gets `previousPrice`, `priceChange`, `priceChangePct`, `isPriceDrop`,
  `isNewListing`, `firstSeenAt` and `previousSeenAt`, compared with your previous run of the same search.
  Add **`onlyChanges`** and you receive only new listings and listings whose price moved; unchanged ones are free.
  Here `maxItems` counts listings checked, so the daily cost stays flat.

```json
{ "locations": ["Rome"], "contract": "sale", "propertyType": "apartment", "maxPrice": 350000, "maxItems": 300, "trackPriceChanges": true, "onlyChanges": true }
```

The memory lives in a Key-Value Store in your own Apify account (`immobiliare-scraper-state`), one record per search
and filter set (up to 10,000 listings each), so you can inspect it or delete it to start over. Connect Slack, e-mail,
Google Sheets or a webhook to the Task and each morning's news lands where you read it.

### Output fields

Every listing row (`type: "listing"`): `id`, `url`, `title`, `contract` (`sale`, `rent` or `auction`), `isAuction`,
`propertyType`, `category`, `price`, `priceText`, `currency`, `pricePerSqm`, `surfaceSqm`, `rooms`, `roomsText`,
`bedrooms`, `bathrooms`, `floor`, `hasElevator`, `features`, `city`, `province`, `region`, `zone`, `neighbourhood`,
`address`, `latitude`, `longitude`, `description` (first 600 characters on search rows), `mainPhoto`, `photos`,
`photoCount`, `isPriceReduced`, `originalPrice`, `priceReductionPct`, `priceReducedAt`, `advertiserType`
(`agency`, `builder` or `private`), `agencyName`, `agencyId`, `agencyUrl`, `agencyLogo`, `isNew` (Immobiliare.it's
own "new" badge), `isLuxury`, `isProject`, `unitsCount`, `listingTier`, `position`, `searchUrl`, `scrapedAt`.

With price tracking: `isNewListing`, `previousPrice`, `priceChange`, `priceChangePct`, `isPriceDrop`, `firstSeenAt`,
`previousSeenAt`.

With full listing pages (`hasDetails: true`): full `description` (Immobiliare.it's English translation when it has
one) and `descriptionOriginal`, `features` in full, `condition`, `energyClass`, `energyPerformanceIndex`,
`energyStatus`, `heating`, `airConditioning`, `buildingYear`, `floorsInBuilding`, `condoFees`, `condoFeesMonthly`,
`deposit`, `availability`, `contractDetails`, `kitchen`, `propertyDetails`, `streetNumber`, `referenceCode`, every
photo in large size, `floorPlans`, `virtualTourUrls`, `videoUrls`, `createdAt`, `updatedAt`, `listingStatus`. If a
listing page cannot be read, the row still comes with `hasDetails: false` and `detailsError`, and only the listing
is charged.

**No advertiser contact data, by design.** For agencies (companies) you get the agency's name, id, page and logo.
For private advertisers you get only `advertiserType: "private"`: never a name, phone, e-mail or photo, and the location stops at zone and neighbourhood (no street or street number, coordinates rounded to about 1 km), because a private listing can be the advertiser's own home. The agent's
name and phone are never returned, and phone numbers and e-mail addresses inside the description text are replaced
with `[contact removed]`. Use the listing `url` to contact the advertiser through Immobiliare.it.

### Error codes (never charged)

| `errorCode` | Meaning |
|---|---|
| `INVALID_INPUT` | A value the Actor does not understand (minimum above maximum, unknown property type, a URL that is not Immobiliare.it, a map-drawn search with no fixed page) |
| `NOT_FOUND` | Immobiliare.it does not know this place, the search page does not exist, or the listing was removed |
| `NO_RESULTS` | No listing for this search and filters |
| `BLOCKED` | Immobiliare.it's anti-bot check refused every attempt on new IPs; run again or use the RESIDENTIAL proxy group |
| `NOT_REACHED` | The run timeout arrived before this search or listing |
| `UNEXPECTED` | A page came in a shape we did not expect; the rest of the run goes on |

### Pricing

| Event | Per 1,000 |
|---|---|
| Listing delivered | US$ 1.00 |
| Full listing page (only with `includeDetails` or listing URLs) | US$ 2.00 |

A daily `onlyNew` run on a busy Milan search that finds 40 new rentals costs US$ 0.04; with full listing pages,
US$ 0.12. Error rows, duplicates, listings already seen and listings with an unchanged price are free, and there is
no start fee.

### Limitations

- Immobiliare.it shows at most **2,000 listings per search** (80 pages of 25). Split a big city by zone, price range
  or property type to go further.
- Immobiliare.it protects the site with an anti-bot service. The Actor drops IPs that get refused and keeps the ones
  that pass; it never solves captchas. On a bad day a search may come back as `BLOCKED` (free): run it again.
- The Actor reads the English version of the site, so labels (property type, features, condition) are in English.
  Descriptions come in Immobiliare.it's own English translation when there is one, otherwise in the original Italian.
- A search URL with several property types at once is split into one search per type. A search drawn on the map has
  no fixed page and is not supported: pick a city or zone instead.
- This Actor reads public pages only.

### FAQ

**Do I need an Immobiliare.it account or an Italian IP?** No. No login, no cookies, and the default datacenter proxy
works.

**Can I paste a search from my browser?** Yes, in Italian or English. Price, surface, rooms, zones, property type
and sort in the URL are kept.

**How is price per m² computed?** `price / surfaceSqm` as published on the listing. For rentals it is the monthly
rent per m².

**How do I get an alert only when a price drops?** Turn on `trackPriceChanges` and `onlyChanges`, schedule the Task
daily and filter on `isPriceDrop: true` in your integration.

**Can I use it from n8n, Make, Zapier or an AI agent?** Yes, through the Apify app or the Apify MCP server. Error
rows are free, so an agent can explore cheaply.

**What if a run is cut by its timeout?** The Actor stops shortly before the limit and ends successfully with what it
delivered, telling you in the status message how to get the rest.

### Changelog

- **0.1 (2026-10-06):** first version. Search by Immobiliare.it URL or by location with contract, property type,
  price, surface, rooms and sort; sale, rent and auctions; price per m²; the site's own price cuts; optional full
  listing pages; `onlyNew` and price tracking between runs for daily schedules; free error rows.

# Actor input Schema

## `startUrls` (type: `array`):

Immobiliare.it search links copied from your browser after setting the filters on the site, one per line, for example https://www.immobiliare.it/affitto-case/milano/?prezzoMassimo=2000. Every filter in the link is kept. Listing links (https://www.immobiliare.it/annunci/123456789/) also work and come back with the full listing page. Leave empty to search by location below. Each listing is charged once as 'Listing delivered'.

## `locations` (type: `array`):

Italian cities, provinces, regions or neighbourhoods, one per line, in English or Italian, for example Milan, Rome, Trastevere or Lombardy. Each location is a separate search with the filters below, and each row says which search found it. Ignored for the links above.

## `contract` (type: `string`):

Operation to search: For rent (default) or For sale. Sale searches include judicial auctions unless you turn off 'Include auctions'.

## `propertyType` (type: `string`):

Kind of property: Homes (default, every residential type), Apartment, Penthouse or attic, Villa, Detached house, Loft, Room (rent only), Office, Shop or commercial, Warehouse or industrial, Storage, Garage or parking, or Land.

## `minPrice` (type: `integer`):

Only listings at or above this price in euros, as a whole number (monthly rent for rentals), for example 800 or 200000. Empty = no minimum.

## `maxPrice` (type: `integer`):

Only listings at or below this price in euros, as a whole number (monthly rent for rentals), for example 2000 or 500000. Empty = no maximum.

## `minSurface` (type: `integer`):

Only listings with at least this many square metres, for example 50. Empty = no minimum.

## `maxSurface` (type: `integer`):

Only listings with at most this many square metres, for example 120. Empty = no maximum.

## `minRooms` (type: `integer`):

Minimum number of rooms, from 1 to 5, counted the Italian way ('locali': bedrooms plus living rooms, so a one-bedroom flat is usually 2). 5 means 5 or more. Empty = any.

## `maxRooms` (type: `integer`):

Maximum number of rooms, from 1 to 5, counted the Italian way ('locali'). Empty = any.

## `sortBy` (type: `string`):

Immobiliare.it's own orders: Newest first (default, the right choice for daily monitoring), Relevance, Price low to high, or Price high to low. With a limit it also decides which listings you get, for example Price low to high plus 50 returns the 50 cheapest.

## `includeAuctions` (type: `boolean`):

On (default): sale searches keep the judicial auctions Immobiliare.it mixes in (contract 'auction' in the output). Turn off to keep only regular sales; skipped auctions are not charged.

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

Stop each search (each link or each location) after this many listings, for example 50 (default). Immobiliare.it shows 25 per page and at most 2,000 per search (80 pages). 0 = up to 2,000. You pay per listing delivered, so this caps the cost of each search.

## `includeDetails` (type: `boolean`):

Off (default): rows come from the search results (price, size, rooms, address, coordinates, photos, agency). On: also opens each listing's own page and adds the full description (English and original), all features, energy class, heating, condition, condo fees, deposit, year built, floors in the building, every photo, floor plans, virtual tour, and publication and update dates. One extra request per listing, charged as a separate 'Full listing page' event.

## `onlyNew` (type: `boolean`):

For scheduled runs. Remembers which listings each search (with its filters) already returned, in a named key-value store in your account ('immobiliare-scraper-state'), and delivers only listings not seen before. The first run delivers up to the limit and marks everything it read as seen. Seen listings are not delivered, not charged and do not count toward the limit. Forces the newest-first order. Delete the store to start over.

## `trackPriceChanges` (type: `boolean`):

Compares each listing's price with the price seen in your previous runs of the same search (same key-value store) and adds previousPrice, priceChange, priceChangePct, isPriceDrop, isNewListing and firstSeenAt to every row. The limit then counts listings checked, so a daily run keeps the same cost.

## `onlyChanges` (type: `boolean`):

With price tracking: deliver only listings that are new or whose price changed since the last run. Unchanged listings are not delivered and not charged. Turns on 'Track price changes' by itself.

## `proxyConfiguration` (type: `object`):

The default Apify Proxy (datacenter) works: blocked IPs are dropped and the Actor keeps the ones that pass. If the datacenter proxy keeps being blocked, the Actor moves to the residential group on its own when your account has it, with no extra charge.

## Actor input object example

```json
{
  "locations": [
    "Milan"
  ],
  "contract": "rent",
  "propertyType": "homes",
  "sortBy": "newest",
  "includeAuctions": true,
  "maxItems": 50,
  "includeDetails": false,
  "onlyNew": false,
  "trackPriceChanges": false,
  "onlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `resultsCsv` (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 = {
    "locations": [
        "Milan"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/immobiliare-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 = { "locations": ["Milan"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/immobiliare-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 '{
  "locations": [
    "Milan"
  ]
}' |
apify call scrapewise/immobiliare-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapewise/immobiliare-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/ADH9USmnfakoL3o4Q/builds/pcv6OAaRwAcp8ewUG/openapi.json
