VivaReal & ZAP Imóveis Scraper
Scrape Brazilian real estate listings from VivaReal and ZAP Imóveis: price, condo fee, IPTU, area, rooms, address, coordinates, advertiser and photos.
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,portal,business(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.0014 per property = $1.4 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Property returned | One property listing returned in the dataset. Diagnostic rows and the labelled sample row are not charged. | $0.0014 |
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 | A Brazilian city or neighbourhood, written the way it is written there: "Pinheiros, São Paulo", "Copacabana, Rio de Janeiro", "Curitiba", "Balneário Camboriú". The portal's own place lookup decides the match, and the run log tells you which one it picked. | string |
portal | VivaReal and ZAP Imóveis run on one shared listing index, so both return the same properties. This only decides which site the listing URL points at, and the order results come back in. | string |
business | Sale (venda) or rental (aluguel). Rental rows also carry the monthly total with condo fee and IPTU added. | string |
listingType | USED is the ordinary resale market. DEVELOPMENT is new-build launches (lançamentos), a much smaller pool — a few thousand nationally rather than millions. | string |
maxItems | Hard cap on rows across every search in this run (1–5000). You are charged per listing returned. Sample and diagnostic rows are never charged. | integer |
startUrls | Paste search pages or single listing pages from either portal. A search page works best when it still carries its "?onde=" parameter — that is where the portal keeps the place id. A single listing page must end in -id-<number>/. | array |
unitTypes | Leave empty for everything. These are the portal's own codes. | array |
bedroomsMin | Minimum number of bedrooms (quartos). | integer |
bathroomsMin | Minimum number of bathrooms (banheiros). | integer |
parkingMin | Minimum number of parking spaces (vagas). | integer |
priceMin | Sale price, or monthly rent when you are searching rentals. | integer |
priceMax | Sale price, or monthly rent when you are searching rentals. | integer |
areaMin | Minimum área útil in square metres. | integer |
areaMax | Maximum área útil in square metres. | integer |
locationIds | For repeat runs where you already know the exact place. These look like BR>Sao Paulo>NULL>Sao Paulo>Zona Oeste>Pinheiros and appear in the run log whenever a location is resolved. Using them skips the place lookup and guarantees the same area every time. | array |
What you get
A structured dataset — each result includes fields like:
imageUrltitlepricecondoFeeiptuusableAreabedroomsbathroomsparkingSpacesneighborhoodcitystateAcronymadvertiserTypeadvertiserNameupdatedAturllistingIdExport 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
VivaReal & ZAP Imóveis Scraper — Brazilian property listings
Point it at a Brazilian city or neighbourhood and it returns one row per property advert: asking price, condomínio, IPTU, área útil, bedrooms, bathrooms, parking, the full address with coordinates, the amenity list, who is advertising it, every photo and the link back to the listing. Sale and rental both work.
Start with the limit, because it decides whether this is the right tool for you: the portals stop paging any single search at 1,500 results. Ask for São Paulo and you will get 1,500 rows out of the million-plus that exist. That is the portal's own window, not a setting here, and no scraper gets past it. The way round it is to split the job by neighbourhood, by price band or by property type, then run several searches. A Pinheiros three-bedroom search between R$800k and R$1.5m comes back complete. "Every flat in Brazil" does not.
What one row looks like
Real row, trimmed to the interesting parts, pulled on 19 September 2026:
{
"listingId": "2814207417",
"portal": "VivaReal",
"url": "https://www.vivareal.com.br/imovel/apartamento-2-quartos-pinheiros-zona-oeste-sao-paulo-com-garagem-85m2-venda-RS2650000-id-2814207417/",
"title": "Apartamento com 2 Quartos à venda, 85m²",
"businessType": "SALE",
"listingType": "USED",
"currency": "BRL",
"price": 2650000,
"condoFee": 2060,
"iptu": 890,
"iptuPeriod": "YEARLY",
"usableArea": 85,
"bedrooms": 2,
"bathrooms": 1,
"suites": 0,
"parkingSpaces": 1,
"unitFloor": 13,
"amenities": ["POOL", "GYM", "ELEVATOR", "BARBECUE_GRILL", "GATED_COMMUNITY"],
"street": "Rua Dona Ana Neri",
"streetNumber": "581",
"neighborhood": "Pinheiros",
"zone": "Zona Oeste",
"city": "São Paulo",
"stateAcronym": "SP",
"zipCode": "01522000",
"latitude": -23.559503,
"longitude": -46.615471,
"advertiserType": "agency",
"advertiserName": "Santucci Broker Negócios Imobiliários",
"advertiserLicense": "31016-J-SP",
"phones": ["11999782608"],
"whatsapp": "11999782608",
"imageCount": 30,
"createdAt": "2024-05-29T20:07:12.572Z",
"updatedAt": "2026-08-26T17:47:06.754Z"
}
Rentals carry two extra numbers that matter in Brazil: price is the monthly rent on its own and rentalTotalPrice is what the tenant actually pays each month once condomínio and IPTU are added. Measured on a Pinheiros rental pull: R$12,800 rent, R$14,860 total. Budget filters that ignore the condomínio are why so many Brazilian rental searches lie to you.
Input
Everything except the place is optional.
{
"location": "Pinheiros, São Paulo",
"portal": "vivareal",
"business": "SALE",
"listingType": "USED",
"bedroomsMin": 3,
"priceMin": 800000,
"priceMax": 1500000,
"maxItems": 200
}
location. Write it the way a Brazilian would: Pinheiros, São Paulo, Copacabana, Rio de Janeiro, Curitiba, Balneário Camboriú. A bare name is read as the city; add the city after a comma when you mean a neighbourhood. That matters more than it sounds, because São Paulo is also the name of a neighbourhood in Belo Horizonte. The run log names the place it picked on the first line, so a wrong match shows up there rather than in the data. Fifteen of fifteen test phrasings, accented and not, resolved to the place a person would have meant.
portal. VivaReal and ZAP Imóveis run on one shared listing index. Same properties, same ids, same prices. What changes is which site the url points at and the order results come back in. Pick whichever one your team already uses. Checked across eight identical searches on 19 September 2026: the match counts agreed to the row every time.
startUrls. Paste search pages or single listing pages from either site instead of filling in fields. A listing page has to end in -id-<number>/. A search page works best when it still has its ?onde= parameter, because that is where the portals keep the place id; copy the URL straight out of the address bar after you have run the search on the site and it will. A plain SEO path like /venda/sp/sao-paulo/zona-oeste/pinheiros/ also works, since the last part of the path gets sent through the place lookup, but that is a guess at your intent rather than a certainty.
Filters. bedroomsMin, bathroomsMin, parkingMin, priceMin, priceMax, areaMin, areaMax, unitTypes. These are applied by the portal, not filtered out afterwards, so the count in the log is the real count and you are not charged for rows that get thrown away. Verified: a three-bedroom search between R$800k and R$1.5m returned ten rows, all with exactly three bedrooms, all inside the band.
locationIds, for repeat runs. Once the log has told you that "Pinheiros, São Paulo" resolves to BR>Sao Paulo>NULL>Sao Paulo>Zona Oeste>Pinheiros, put that string here and the place lookup is skipped entirely. Same area every run, no ambiguity.
What you get charged for
One charge per listing row delivered. Nothing else bills:
- An empty input writes a single labelled sample row and stops. Not charged.
- A place the portal does not recognise writes a diagnostic row saying so. Not charged.
- A URL that is not from either site writes a diagnostic row naming the URL. Not charged.
- A search that finds nothing writes a diagnostic row. Not charged.
- A refused request writes a diagnostic row after the retries run out. Not charged.
Diagnostic rows are marked _diagnostic: true and the sample row _sample: true, so a filter on those two fields separates paid rows from free ones. The rate itself is on the pricing tab of this page.
What this does not do
- It cannot go past 1,500 rows in one search. Covered at the top; it is the single thing most
likely to surprise you.
- The count in the log is the portal's index count, not the headline on the website. For
Pinheiros the index reports 45,589 matches while the site's own page says 23,566. The rows are real either way, and every one of them opens on the live site, but the two numbers are counted differently and I could not reproduce the site's arithmetic. Treat the log count as a rough sense of scale and the rows as the truth.
- Neighbourhood searches bleed slightly into the neighbours. Over 270 Pinheiros rows, 261 were
in Pinheiros and 9 were in Cerqueira César, Butantã and Itaim Bibi. That is the portal's own behaviour, not a bug here. Every row carries neighborhood, so filter on it if you need a hard boundary.
- No sold prices and no price history. The portals do not publish either. A row is what the
advert says today.
- No login-only data. No saved searches, no lead forms, no messaging an advertiser, no account
of any kind is created or used.
- About one row in four has no coordinates, and it varies a lot by city. Measured over 720 rows
across eight cities: 77% carried a point, from 49% in Belo Horizonte up to 92% in Curitiba. Some advertisers hide the exact position. latitude and longitude come back null rather than guessed, so a map build should expect to drop rows rather than plot a wrong pin.
advertiserTypeisagency,owneror null. It comes from the portal's own contract flag.
Over 240 sampled rows it read agency on 232 and owner on 8. Private sellers are genuinely rare on these two sites, which is worth knowing before you build a for-sale-by-owner pipeline on it.
- New developments (lançamentos) are a small pool. Around 3,900 nationally against millions of
resale adverts. Set listingType to DEVELOPMENT and expect hundreds, not thousands.
- Descriptions are the advertiser's text. HTML is stripped and line breaks kept; nothing is
summarised, translated or cleaned up beyond that.
Questions people actually ask
Is this the VivaReal API or the ZAP Imóveis API? Both, and it is the same one. The two portals are run by the same company on one shared listing index, which is why a listing id from one resolves on the other. The portal input decides which site's URLs you get back.
Can I scrape a whole city? Not in one go; see the 1,500 limit. Split it. For São Paulo, running one search per neighbourhood gets you a lot further than one search for the city, and running each of those split by price band gets you further again.
Do I need a Brazilian IP address, a proxy or an account? No. Leave the proxy field alone; the Actor handles its own routing and rotates to another address when the portal refuses one. If you have your own proxy servers and a reason to use them, put them in proxyConfiguration.proxyUrls and they will be used as-is.
How fresh is the data? Live at the moment of the run. Every row carries updatedAt from the advertiser's last edit, so you can tell a listing refreshed last week from one that has sat untouched since 2024.
Why did I get fewer rows than maxItems? Either the search genuinely has fewer matches (the log says how many the portal reports), or you hit the 1,500 window, or duplicate ids were dropped. The same property is sometimes advertised by several agencies; ids are deduplicated within a run, so you are charged once for it, not three times.
What currency are the prices in? Brazilian reais, always. currency is "BRL" on every row. price, condoFee and iptu are plain numbers with no formatting, so they go straight into a spreadsheet or a database column.
Can I get the advertiser's phone number? It is in phones and whatsapp when the advertiser published it, which is most of the time. It is the number shown on the public listing page, nothing more.
Does it work for commercial property and land? Yes. Set unitTypes to OFFICE, BUSINESS, COMMERCIAL_PROPERTY, COMMERCIAL_BUILDING, FARM or one of the land types. usageTypes on each row tells you RESIDENTIAL or COMMERCIAL.
Output fields
listingId · portal · url · title · description · businessType · listingType · propertyType · unitTypes · usageTypes · currency · price · rentalTotalPrice · rentalPeriod · condoFee · iptu · iptuPeriod · usableArea · totalArea · bedrooms · bathrooms · suites · parkingSpaces · unitFloor · amenities · street · streetNumber · neighborhood · zone · city · state · stateAcronym · zipCode · fullAddress · latitude · longitude · advertiserType · advertiserName · advertiserId · advertiserLicense · advertiserTier · phones · whatsapp · publicationType · status · imageUrl · imageCount · images · createdAt · updatedAt · searchLocation · position · scrapedAt
amenities is the portal's own code list: POOL, GYM, ELEVATOR, BARBECUE_GRILL, GATED_COMMUNITY and about 160 others. They are passed through untranslated so they stay stable across runs. advertiserLicense is the CRECI registration number where the advertiser is a licensed agency.