Portugal Real Estate Scraper (Imovirtual, OLX, Idealista) avatar

Portugal Real Estate Scraper (Imovirtual, OLX, Idealista)

Pricing

from $5.00 / 1,000 listing with contact details

Go to Apify Store
Portugal Real Estate Scraper (Imovirtual, OLX, Idealista)

Portugal Real Estate Scraper (Imovirtual, OLX, Idealista)

One normalized dataset from Imovirtual, OLX, CustoJusto and Idealista: price, EUR/m2, T0-T5 typology, parish/municipality, private seller vs agency (native portal flags), phone, AMI licence, no-agencies flag, price history and days on market. Built for Portuguese agents, CRMs and market analysts.

Pricing

from $5.00 / 1,000 listing with contact details

Rating

0.0

(0)

Developer

Shalon Soluções Tecnologicas

Shalon Soluções Tecnologicas

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Portugal Real Estate Scraper — Imovirtual, OLX, CustoJusto, Idealista (one schema)

Scrape Portuguese property portals into one normalized dataset: price, €/m², typology (T0–T5), parish / municipality / district, private seller vs. agency, phone, AMI licence, "no agencies" flag, price history and days on market. Built by a Portuguese proptech founder for real-estate agents, CRMs and market analysts who need Portugal data that is actually usable — not four portals with four different field names.

Why this scraper

This actorTypical single-portal scrapers
PortalsImovirtual, OLX, CustoJusto, Idealista (via orchestration), SuperCasa (soon)one
Schemaone ImovelListing for every portalper-portal fields
Private vs. agencynative portal flags (isPrivateOwner, business, companyAd) — never guessedusually missing
PhoneImovirtual (agencies + private), OLX (via portal API), Idealistavaries
"Não aceito agências"noAgenciesFlag — from the portal's own flag on CustoJusto, text detection elsewhere
Same property on 4 portalsrecognized and marked (duplicateOf), or not delivered at all — and not chargeddelivered 4 times, you clean it up
Phone numbersall of them (phones[]) — agencies commonly publish two: office landline and agent mobilethe first one, if any
Price history & days on marketpersistent across runs (priceHistory, priceChangePct, daysOnMarket)
LocationPortuguese admin hierarchy: district / municipality / parish, plus GPS when the portal has itfree text

Input

{
"portals": ["imovirtual", "olx", "custojusto"],
"operation": "sale",
"propertyType": "apartment",
"locations": ["lisboa", "cascais", "porto"],
"sellerType": "private",
"maxItemsPerPortal": 300,
"fetchDetails": true,
"priceHistory": true,
"deduplicate": "drop"
}
  • locations: district or municipality names, lowercase, no accents (lisboa, setubal, vila nova de gaia). Municipalities are resolved to each portal's own geography.
  • startUrls: alternatively paste search-result URLs from any supported portal; the portal is detected from the domain.
  • sellerType: "private" filters on the portal where possible and always on the output.
  • fetchDetails: true opens the listing page (phone, full description, energy certificate, year built). Doubles the requests — it is a separate, more expensive event.
  • idealistaMode: "actor" (default) runs Idealista through a Store actor that uses the mobile API — far cheaper than a browser behind DataDome. Billed to your account by that actor. "browser" uses the built-in Playwright adapter (needs residential proxy).

Output — one real item (phone masked)

{
"id": "imovirtual:19268265",
"portal": "imovirtual",
"url": "https://www.imovirtual.com/pt/anuncio/apartamento-t3-com-estacionamento-e-vista-desafogada-sobre-o-rio-sob-ID1iQyt",
"operation": "sale",
"propertyType": "apartment",
"title": "Apartamento T3 com estacionamento e vista desafogada sobre o rio",
"price": 525000,
"currency": "EUR",
"pricePerM2": 3454,
"typology": "T3",
"bedrooms": 3,
"bathrooms": 2,
"areaM2": 152,
"floor": "floor_3",
"yearBuilt": 2013,
"energyCertificate": "A",
"condition": "used",
"district": "Lisboa",
"municipality": "Vila Franca de Xira",
"parish": "Alverca do Ribatejo e Sobralinho",
"locationRaw": "Rua do Bom Jesus, Sobralinho, Alverca do Ribatejo e Sobralinho, Vila Franca de Xira, Lisboa",
"latitude": 38.920174,
"longitude": -9.024194,
"sellerType": "agency",
"sellerName": "Century21 Nações",
"phone": "+3512189xxxxx",
"phones": ["+3512189xxxxx", "+3519123xxxxx"],
"agencyLicense": "AMI 10786",
"noAgenciesFlag": false,
"publishedAt": "2026-09-07",
"firstSeenAt": "2026-09-08T08:51:41.849Z",
"daysOnMarket": 1,
"priceHistory": [{ "seenAt": "2026-09-08T08:51:41.849Z", "price": 525000 }],
"priceChangePct": null,
"duplicateOf": null,
"duplicateOfPortal": null,
"duplicateOfUrl": null,
"images": ["https://ireland.apollo.olxcdn.com/v1/files/…/image;s=1280x1024;q=80"],
"scrapedAt": "2026-09-08T08:51:41.849Z"
}

Every field exists for every portal; what a portal does not publish comes back as null, never as a missing key. raw keeps the portal's original fields for anything not mapped.

Portal coverage (validated 2026-09-15)

PortalSourcePrivate/agencyPhoneNotes
Imovirtualembedded JSONnative flagagencies + private sellersAMI licence, GPS, year built, energy
OLXportal's public JSON APInative flagyes, via the portal's phone endpointOLX limits phone reveals per session; the actor rotates sessions
CustoJustoembedded JSONnative flagno (portal requires login)native noSalesmen ("no agencies") and previous price
IdealistaStore actor (orchestrated)mappedyes0,55 $/1 000 charged by that actor to your account
SuperCasabehind a Cloudflare challenge; on the roadmap

How often is there a phone

Measured on 2026-09-15, Lisbon, real runs — not an estimate:

PortalListings with at least one phoneNotes
Imovirtual~100% of agency listings, and 4 in 6 published two numbersthe strongest source
OLX~15–30%OLX allows roughly two phone reveals per IP before returning Disallowed for this user; the actor rotates sessions, so coverage rises with residential proxy and falls without
CustoJusto0%the portal requires a login to show any number

If phone coverage is what you are buying, run Imovirtual and Idealista, and treat OLX as a bonus. We would rather tell you this here than have you find out after paying.

Watch mode — only what is new

New listings are worth more than old ones. A private seller who posts today takes ten calls from agencies within 48 hours; whoever reaches them first wins. So deliver lets you ask for the delta instead of the whole market:

ValueWhat you get
all (default)every listing found
newonly listings this actor has never seen before
new-or-changednew ones, plus listings whose price moved since the last run

Listings you already know are not delivered and not charged. Measured on 2026-09-15, OLX, Lisbon, private sellers only: a second pass examined 40 listings, delivered 8, and skipped 32 as already seen — the whole run cost $0.0035. Schedule it hourly and you get a handful of genuinely new ads per pass instead of re-importing the same market every time.

In watch mode maxItemsPerPortal caps listings examined, not delivered — otherwise the actor would page through an entire portal hunting for new ads that may not exist yet.

Needs priceHistory: true; that is where the state between runs lives.

How many new listings are there, really

Measured the same day, OLX Lisbon, private sellers, for sale — the full set, not a sample:

WindowNew listings
last 24 hours6
last 3 days21
last 7 days48
last 30 days163

Between 4 and 9 per day, steady across two weeks. That is the honest size of this feed for one district on one portal: small enough that one person can work every single one — which is the point.

The same property, four times

Portugal's portals overlap heavily. Run four single-portal scrapers over Lisbon and the same apartment arrives four times, with four ids and often four slightly different prices. Cleaning that up is the job you inherit.

This actor does it for you. deduplicate takes three values:

ValueWhat happens
mark (default)every listing is delivered; repeats carry duplicateOf, duplicateOfPortal and duplicateOfUrl pointing at the first one
dropeach property is delivered once — and the repeats are not charged
offno comparison at all

Two listings are only merged when two independent pieces of evidence agree: same phone and same area (±2%); or same GPS to four decimals (~11 m) and same typology; or same municipality, typology, area (±2%) and price (±3%). A shared phone alone is not enough — one seller can own two flats. When in doubt it does not merge: an extra row is noise, a collapsed property is information you cannot get back.

Use cases

  • Private-seller leads: sellerType: "private" + fetchDetails: true → name, phone, and whether the ad says "no agencies". Respect that flag.
  • Price-drop radar: schedule daily runs; priceChangePct and priceHistory tell you who lowered the price this week.
  • Market studies: pricePerM2 by parish, average daysOnMarket, share of private vs. agency listings.
  • CRM feed: run on a schedule, receive a webhook, or read the dataset by API (JSON / CSV / Excel).

Pricing

Pay per event — you pay per listing delivered, nothing else:

EventPriceWhen
listing$0.002one listing from search results (fetchDetails: false)
listing-with-details$0.005one listing with the detail page opened — phone, description, energy, year
Actor start$0.005 / GBper run

Set a maximum spend per run in the Console; the actor stops cleanly when it is reached.

Proxies

Imovirtual, OLX and CustoJusto work with datacenter proxies (included). Idealista in browser mode needs a residential proxy with country PT; the actor enforces it.

Data comes from public listing pages. Seller names and phone numbers are personal data under the GDPR — you are responsible for the lawful basis of what you do with them, and for Portugal's rules on unsolicited commercial contact (Lei 41/2004). Honour noAgenciesFlag. Do not republish descriptions or photos.

Local development

npm install && npx playwright install chromium
npm test # 12 tests, no browser needed
npm run start:dev # reads storage/key_value_stores/default/INPUT.json
apify push # deploy