Zap Imóveis Scraper - Properties, Prices & 80+ Fields
Pricing
from $1.00 / 1,000 results
Zap Imóveis Scraper - Properties, Prices & 80+ Fields
Scrape Zap Imóveis sale, rental and new-development listings by city, filters or URL. Extract 80+ fields including prices, fees, addresses, GPS, agencies, CRECI, amenities, nearby POIs, scores, H3 location data and media.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
27
Total users
5
Monthly active users
6 days ago
Last modified
Categories
Share
ZAP Imoveis Scraper: Brazil Property Listings with Price, Contacts and Location Data
ZAP Imoveis Scraper turns zapimoveis.com.br, one of Brazil's largest property portals, into structured data. Get price, condo fee, IPTU, full address, GPS coordinates, agency contact details, license numbers, AI-tagged amenities and the platform's own quality score for sale, rental and new-development listings. Search a city with filters, or paste any ZAP search URL and walk its result pages, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- 80+ structured fields per listing, including price, condo fee, IPTU (monthly and yearly), full address, GPS, agency contact, agency tier and CRECI license number, plus around 40 ZAP-only fields.
- Location intelligence nobody else exposes: an H3 spatial-hash array at three resolutions for spatial joins, a curated points-of-interest list (bus stops, train stations, pharmacies, markets), and gentrification-style "valuable zones" tags.
- AI-tagged amenities plus the platform's own Listing Quality Score (LQS, 0 to 100), the same signal ZAP uses to rank cards.
- Verbatim raw passthrough (
raw.listing,raw.account,raw.medias), so any field the platform adds later shows up in your dataset automatically, without waiting on an update. - Two ways to collect: search by city with structured filters, or paste any ZAP search URL and the actor walks its pagination forward from wherever that URL points.
- Built for recurring monitoring: Resume from run ID continues one interrupted run without re-charging what it already collected, and Incremental mode tracks a saved search over time, classifying every listing as new, updated, unchanged, expired or reappeared.
- Optional export into your apps: pipe results into Notion, Linear or Airtable through MCP connectors, in addition to the dataset.
Use Cases
- Real estate investors and analysts: compare price per square meter, condo fees and IPTU across neighborhoods to spot mispriced listings.
- PropTech and valuation tools: feed structured listings with GPS, POIs and H3 index straight into a pricing or heatmap model.
- Lead generation for agencies and brokers: collect seller names, phones, WhatsApp numbers, tiers and CRECI license numbers for a target city.
- Market researchers: track new-development (lancamento) launches across a city or region over time.
- Automated workflows: pipe fresh or changed listings into Notion, Airtable or a spreadsheet for a house search or a client-facing shortlist.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
id | "0000000001" |
url | "https://www.zapimoveis.com.br/imovel/apartamento-sample/id-0000000001/" |
title | "Sample Listing Title" |
price | 450000 |
currency | "BRL" |
business | "SALE" (also "RENTAL") |
property_type / unit_types | "UNIT" / ["APARTMENT"] |
bedrooms / bathrooms / parking_spaces | 2 / 2 / 1 |
usable_area | 80 |
city / state_code | "Sao Paulo" / "SP" |
neighborhood | "Centro" |
zip_code | "01000000" |
latitude / longitude | -23.5500 / -46.6333 |
monthly_condo_fee | 850 |
iptu | 220 |
lqs | 90 |
location.h3 | [{"index":"...","resolution":7},{"index":"...","resolution":8}] |
location.pois_list | ["BS:Sample Bus Stop","CS:Sample Market"] |
attributes.ai_amenities | ["GARAGE","ELEVATOR"] |
entities.seller.name / .tier | "Sample Agency" / "GOLD" |
entities.seller.license_number | "00000-F-SP" |
contact.whatsapp | "+5500000000000" |
media.images[0].url | "https://resizedimgs.zapimoveis.com.br/img/.../000-fit-in-800x600.webp" |
raw | the complete source listing, account and media objects |
Every record also carries the full namespaced objects behind these flat fields, so nothing is lost: identity (external, source and legacy IDs), source_context (the URL or location that seeded this listing plus its page number), timestamps, content.description, pricing.offers (one entry per business type ZAP has active for that unit, since a property can be listed for both sale and rent), availability, the full location object (street, geocoding precision, valuable zones), media.videos, and entities.seller's complete profile (verified flag, billing address, logo). When Incremental mode is on, each record additionally carries changeType, changedFields, firstSeenAt and lastSeenAt.
How to Use
- Pick a mode:
search(city plus filters) orurl(paste ZAP search links and walk their pagination). - For
search, fill in Locations and the filters you need; forurl, paste the links (filters are ignored, pagination starts where each URL points). - Set Max Listings (and optionally Max Pages Per Search) to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search a city for rentals:
{"mode": "search","locations": ["Sao Paulo, SP"],"businessType": "RENTAL","maxPages": 5,"maxListings": 100,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "BR" }}
Search multiple cities, sale apartments only, with a price and bedroom filter:
{"mode": "search","locations": ["Sao Paulo, SP", "Rio de Janeiro, RJ", "Curitiba, PR"],"businessType": "SALE","propertyType": "APARTMENT","minPrice": 300000,"maxPrice": 800000,"minBedrooms": 2,"maxListings": 200,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "BR" }}
New development launches (lancamentos):
{"mode": "search","locations": ["Sao Paulo, SP"],"businessType": "SALE","listingType": "DEVELOPMENT","maxPages": 5,"maxListings": 100,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "BR" }}
Paste a ZAP URL and walk its pagination:
{"mode": "url","urls": ["https://www.zapimoveis.com.br/aluguel/imoveis/sp+sao-paulo/","https://www.zapimoveis.com.br/venda/apartamentos/rj+rio-de-janeiro/?precoMaximo=500000&quartos=2"],"maxPages": 10,"maxListings": 250,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "BR" }}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/zapimoveis-scraper").call(run_input={"mode": "search","locations": ["Sao Paulo, SP"],"businessType": "RENTAL","maxListings": 100,"proxy": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "BR"},})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["price"], listing["city"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/zapimoveis-scraper').call({mode: 'search',locations: ['Sao Paulo, SP'],businessType: 'RENTAL',maxListings: 100,proxy: { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'], apifyProxyCountry: 'BR' },});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Resume and recurring updates
- Resume from run ID (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips every listing already collected there, so you don't pay twice. It does not classify anything. - Incremental mode (
incrementalMode) is for scheduled runs over the same saved search. It remembers the previous run itself, keyed on a hash of your locations, URLs and filters (or on astateKeyyou set), so nothing needs to be pasted between runs. Each listing is classifiedNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),EXPIREDorREAPPEARED.EXPIREDrows requireemitExpiredto be on and a run that walked every page of every planned search without hitting a cap; a capped or resumed run cannot tell "gone" apart from "not yet reached", so it skips that classification for the run rather than guessing. A listing is classifiedREAPPEAREDwhen it shows up again after an earlier run marked itEXPIRED, soREAPPEAREDonly appears once a previous run has usedemitExpiredwith a full scan; that later run itself does not needemitExpiredon or a full scan to report it. The two features are not meant to be combined: once a real Incremental baseline exists for a search, running it withresumeFromRunIdat the same time is refused, since a resumed run is only a partial scan.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search for filter-based collection, url for pasted-URL pagination |
locations | array[string] | none (prefill: ["Sao Paulo, SP"]) | Cities to search (search mode). Free-form, diacritics optional; each entry resolves to a canonical ZAP location |
businessType | string | SALE | SALE or RENTAL |
listingType | string | USED | USED (resale) or DEVELOPMENT (lancamento) |
propertyType | string | ANY | ANY, APARTMENT, HOME, PENTHOUSE, STUDIO, ALLOTMENT_LAND, FARM, OFFICE, COMMERCIAL_BUILDING, SHED_DEPOSIT_WAREHOUSE, BUSINESS |
minPrice | integer | none | Minimum price in BRL |
maxPrice | integer | none | Maximum price in BRL |
minBedrooms | integer | none | Minimum bedrooms |
minBathrooms | integer | none | Minimum bathrooms |
minParkingSpaces | integer | none | Minimum parking spots |
minUsableArea | integer | none | Minimum usable area in m² |
maxUsableArea | integer | none | Maximum usable area in m² |
sortBy | string | relevance | relevance, price-asc, price-desc, newest, or area-desc |
urls | array[string] | none (prefill: one sample search URL) | ZAP search-page URLs to walk (URL mode only); filter fields above are ignored |
maxPages | integer | none (empty walks every result page) | Optional bound on result pages walked per search or URL, up to 24 listings per page; when empty, Max Listings becomes the effective stopping rule |
maxListings | integer | 20 | Total maximum number of listings to return across all searches; 0 for unlimited (still bounded by Max Pages Per Search) |
resumeFromRunId | string | none | ID of a previous run (or dataset) of this actor; listings already there are skipped, so this run returns only new ones |
incrementalMode | boolean | false | Track this same search across scheduled runs and classify each listing (see "Resume and recurring updates") |
stateKey | string | none (auto-derived from the search scope) | Name or share this monitoring campaign's saved state |
emitUnchanged | boolean | false | Also return (and bill) listings unchanged since the last Incremental run |
emitExpired | boolean | false | Also return (and bill) listings that disappeared since the last Incremental run, as EXPIRED rows, when this run completed a full scan |
proxy | object | none (prefill: Apify Proxy, groups ["RESIDENTIAL"], country BR) | Connection settings; the site rejects requests without a residential-style exit, see Plan Requirement below |
mcpConnectors | array | none | Optional: send a summary of each record to apps you authorized under Integrations |
notionParentPageUrl | string | none | Notion connector only: page under which item pages are created |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run; does not affect the dataset |
Output Example
Sample shape: values are illustrative placeholders, not from a live listing.
{"identity": {"id": "0000000001","external_id": "REF-0001","source_id": "00000000-0000-0000-0000-000000000000","provider_id": null,"fingerprint": null,"image_source_id": null,"legacy_id": null},"source_context": {"url": "https://www.zapimoveis.com.br/imovel/.../id-0000000001/","source_url": "https://www.zapimoveis.com.br/aluguel/imoveis/sp+sao-paulo/","page_index": 1,"seed": { "id": "BR>Sao Paulo>NULL>Sao Paulo", "type": "location", "value": "Sao Paulo, SP" }},"timestamps": {"published_at": "2026-01-01T00:00:00.000Z","created_at": "2026-01-01T00:00:00.000Z","updated_at": "2026-01-01T00:00:00.000Z","delivered_at": null},"content": {"title": "Sample Listing Title","description": "Sample description text.","ai_searchable_amenities": "Garage, Elevator"},"pricing": {"amount": 450000,"currency": "BRL","offers": [{"business_type": "SALE","amount": 450000,"currency": "BRL","monthly_condo_fee": 850,"iptu": 220,"iptu_period": "MONTHLY","yearly_iptu": 2640,"rental_period": null,"rental_warranties": [],"monthly_rental_total_price": null}]},"availability": {"status": "ACTIVE","show_price": true,"accept_exchange": null,"resale": false,"transacted": false,"non_activation_reason": null},"location": {"street": "Sample Street","neighborhood": "Centro","city": "Sao Paulo","state_code": "SP","zip_code": "01000000","full_address": "Sample Street Centro Sao Paulo SP","coordinates": { "latitude": -23.5500, "longitude": -46.6333, "source": "GOOGLE" },"h3": [{ "index": "0000000000000000", "resolution": 7 },{ "index": "0000000000000000", "resolution": 8 },{ "index": "0000000000000000", "resolution": 9 }],"pois_list": ["BS:Sample Bus Stop", "CS:Sample Market", "PH:Sample Pharmacy"],"valuable_zones": [{ "name": "Sample Zone", "category": "DISTRICT" }]},"media": {"images": [{ "id": "00000000000000000000000000000000", "url": "https://resizedimgs.zapimoveis.com.br/img/vr-listing/00000000000000000000000000000000/vivareal-fit-in-800x600.webp" }],"videos": [],"other": [],"video_tour_link": null},"attributes": {"business": "SALE","listing_type": "USED","property_type": "UNIT","unit_types": ["APARTMENT"],"merged_amenities": ["GARAGE", "ELEVATOR"],"ai_amenities": ["GARAGE", "ELEVATOR"],"lqs": 90,"condominium_name": "Sample Condominium","rooms": { "bedrooms": 2, "bathrooms": 2, "suites": 1, "parking_spaces": 1 },"area": { "usable_area": 80, "total_area": null }},"entities": {"seller": {"account_id": "00000000-0000-0000-0000-000000000000","name": "Sample Agency","profile_url": "https://www.zapimoveis.com.br/imobiliaria/0000/","license_number": "00000-F-SP","tier": "GOLD","verified": true,"is_chat_enabled": true}},"contact": {"phones": ["1100000000", "11900000000"],"whatsapp": "11900000000","chat": null},"id": "0000000001","url": "https://www.zapimoveis.com.br/imovel/.../id-0000000001/","title": "Sample Listing Title","price": 450000,"city": "Sao Paulo","state_code": "SP","lqs": 90,"raw": { "listing": {}, "account": {}, "medias": [], "link": {}, "account_link": {} }}
Plan Requirement
ZAP rejects requests that arrive from typical datacenter address ranges, so a working run needs a residential-style connection. The input form's Proxy Configuration field is prefilled with Apify Proxy, groups ["RESIDENTIAL"], country BR, and keeping that prefilled value in place is what makes extraction work. If Proxy Configuration is left empty or switched away from a residential group, requests are refused and the run finishes with zero listings and a warning explaining the fix. Before scheduling large or frequent runs, confirm that Residential proxy access is included on your Apify plan; the Pricing tab on apify.com shows what each plan includes.
FAQ
How much does it cost?
You pay per listing returned, at the rate your Apify plan applies to this actor. The Pricing tab on the actor page shows current rates. Use Max Listings to cap what any single run can return.
Is it legal to scrape ZAP Imoveis?
This actor collects only publicly available listing data. You are responsible for how you use it: follow ZAP Imoveis's terms and the laws that apply to you, and get legal advice before any commercial redistribution of contact details or leads.
Can I track a saved search and get only what changed?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then classifies every listing against what that same search returned last time, and unchanged listings are not billed unless you turn that on. Getting EXPIRED rows additionally needs Emit expired listings on and a run that completes a full scan without a page or listing cap cutting it short; REAPPEARED then appears in later runs for any listing that comes back after being marked EXPIRED.
What's the difference between Resume from run ID and Incremental mode?
Resume from run ID continues one specific interrupted run using a pasted run or dataset ID: it skips listings that run already collected and adds no classification. Incremental mode is for a recurring, scheduled search: it remembers that search's own state automatically between runs, with nothing to paste, and classifies each listing as new, updated, unchanged, expired or reappeared. The two are not meant to be combined once a real Incremental baseline already exists, since a resumed run only completes a partial scan.
Why did a run return zero listings instead of failing with an error?
The actor needs to reach ZAP through a connection the site accepts. If every request is refused, most commonly because the configured proxy has no residential-style access, the run finishes normally but with zero listings and a warning that points at the fix. The run stops with an explicit failure only when a pasted Resume from run ID cannot be resolved, or when Resume from run ID is combined with Incremental mode after a baseline already exists for that search. Filters that are too narrow, such as a tight price range or an uncommon bedroom count, can also legitimately return zero listings with no error at all.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
🔗 Want more real estate data?
Pair this actor with these related scrapers from the same team:
| 🏠 QuintoAndar Scraper Scrape QuintoAndar property listings across Brazil with 80+ fields, including rent, sale... | 🛒 Americanas Brazil Scrape Americanas Brazil (americanas.com.br) by keyword, department or pasted link... |
| ⚽ Netshoes Brazil Scrape sportswear and footwear from netshoes.com.br. Search by keyword with the store's... | 🔌 Casas Bahia Brazil Electronics & Home Goods Scraper Scrape products from Casas Bahia Brazil by keyword, department, or URL. Filter by brand... |
| 🧩 Mercado Livre Brazil Scrape Mercado Livre Brazil by keyword or URL. Filter by category, brand, price... | 🛒 Drogasil Brazil Pharmacy, Health & Beauty Scraper Scrape Drogasil (drogasil.com.br) medicines, health and beauty products by keyword... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.