Zonaprop Argentina - Properties, Prices & Agencies
Pricing
from $1.00 / 1,000 property results
Zonaprop Argentina - Properties, Prices & Agencies
Scrape Zonaprop.com.ar property listings across Argentina. Extract 140+ fields including USD/ARS prices, price per m², expenses, area, rooms, bedrooms, bathrooms, GPS, descriptions, photos, agency contacts, phone and WhatsApp. Supports buy, rent, temporary listings, filters, sorting and URLs.
Pricing
from $1.00 / 1,000 property results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
7
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share
Zonaprop Scraper: Property Listings, Prices & Agency Contacts Across Argentina
Zonaprop Scraper turns zonaprop.com.ar into a clean, structured properties feed. Search any city or neighborhood in Argentina with buy, rent or temporary rent filters, or paste any number of zonaprop search URLs, and get back one flat record per property with price in both USD and ARS, expenses, area, rooms, bedrooms, bathrooms, GPS coordinates, the full description, every photo, and the agency or owner contact including phone and WhatsApp. Results are collected page by page up to a single hard cap you control, then exported to JSON, CSV or Excel, or pulled straight into your app through the API.
Why This Scraper?
- 150+ named fields per property, including USD and ARS prices, price per square metre, expenses, areas, rooms, garages, age, GPS, the full description and the photo set.
- Agency and owner contacts: name, type, profile URL, phone and WhatsApp number.
- Two input modes: build searches from location names plus filters, or paste zonaprop URLs of any supported shape (search, agency and single property pages).
- Filters that follow you into URL mode: price, currency, area, room, bedroom, bathroom and agency filters narrow both a location search and a pasted URL.
- Incremental monitoring: scheduled runs return only new, changed and reappeared listings, and three dataset views (Overview, Agency & Contacts, Detail) organise the output.
- Fails loudly, bills fairly: if the site refuses every request the run stops with a clear error, and an empty search finishes with an empty dataset and no placeholder row.
Use Cases
- Real estate portals and PropTech teams: build a comparison site or search index of Argentina listings with price, area and location data.
- Investors and analysts: track price per square metre, expenses and inventory mix across neighborhoods and cities.
- Lead generation and CRM tools: pull agency and owner phone and WhatsApp contacts for outreach lists.
- Market researchers: monitor buy versus rent inventory and pricing trends over time.
- Mapping and listing apps: feed GPS coordinates, photos and descriptions into your own map or UI.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
postingId | "00000000" |
title | "Bright 2-bedroom apartment in Palermo" |
description | "Sunny apartment, fully equipped, close to transport and shops." |
operationType | "Venta" |
propertyType | "Departamentos" |
price | 185000 |
currency | "USD" |
priceUsd / priceArs | 185000 / null |
expenses | 80000 |
totalArea / coveredArea | 72 / 65 |
rooms | 3 |
bedrooms | 2 |
bathrooms | 1 |
garages | 1 |
neighborhood | "Palermo" |
city / province | "Capital Federal" / "Capital Federal" |
latitude / longitude | -34.588 / -58.43 |
publisherName | "Jane Doe Propiedades" |
publisherType | "agency" |
publisherPhone / publisherWhatsapp | "5491100000000" / "5491100000000" |
mainImage / photoCount | "https://example.com/photo-1.jpg" / 2 (equal to the length of images) |
url | "https://www.zonaprop.com.ar/propiedades/clasificado/example-00000000.html" |
Every record also carries featuresDetail (each feature with its category, label, value and unit) and publicationPlanTypes. Property pages (single-property URLs and Fetch full description) add publicationDate (when the ad went online), publishedAgo, viewCount, floorPlanUrls and the property's own feature groups: amenities, featuresDetailGroups and one featuresDetail row per feature with its group name as categoryName (search cards alone leave these groups empty). It also carries the property age, amenities, the full photo array, the modified and scraped timestamps, and a set of alias fields that mirror the field names used by other property-scraper outputs (for example id, name, location, amount, geolocation and whatsapp), so a downstream pipeline built for a competitor's field names keeps working without changes.
How to Use
- Pick a mode:
search(build a search from locations and filters) orurl(paste one or more zonaprop search URLs). - Fill in the fields for that mode: locations, operation and property type for search mode, or the URLs to paste for URL mode. Price, currency, area, room and bedroom filters apply in both modes.
- Set Max listings to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Search by location and filters:
{"mode": "search","locations": ["Palermo", "Belgrano"],"operationType": "sale","propertyType": "apartment","minPrice": 100000,"maxPrice": 300000,"currency": "USD","sortBy": "price-asc","maxListings": 100}
Paste one or more search URLs:
{"mode": "url","urls": ["https://www.zonaprop.com.ar/casas-venta-cordoba.html","https://www.zonaprop.com.ar/departamentos-alquiler-palermo.html"],"maxPages": 5,"maxListings": 200}
Search with the full, untruncated description fetched per property:
{"mode": "search","locations": ["Capital Federal"],"operationType": "rent","fetchDetails": true,"maxListings": 50}
Search with a bounded connection budget:
{"mode": "search","locations": ["Mendoza"],"operationType": "sale","maxListings": 300,"residentialCap": 150,"trafficBudgetMb": 200}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/zonaprop-scraper").call(run_input={"mode": "search","locations": ["Palermo"],"operationType": "sale","maxListings": 50,})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["price"], listing["currency"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/zonaprop-scraper').call({mode: 'search',locations: ['Palermo'],operationType: 'sale',maxListings: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
URL mode: supported shapes
| Shape | Example | What you get |
|---|---|---|
| Search page | https://www.zonaprop.com.ar/departamentos-venta-palermo.html | All listings of the search, page by page |
| Search page, later page | .../departamentos-venta-palermo-pagina-2.html | Reading starts at that page |
| Rooms slug | .../departamentos-alquiler-palermo-2-ambientes.html | Listings for that room count |
| Sort slug | .../departamentos-venta-capital-federal-orden-precio-ascendente.html | Listings in the order the URL carries |
| Province or city search | .../inmuebles-venta-cordoba.html | All property types in that location |
| Temporary rent | .../casas-alquiler-temporal-mar-del-plata.html | Temporary rental listings |
| Single property page | .../propiedades/clasificado/<slug>-<id>.html | One row for that property |
| Agency page | .../inmobiliarias/<agency>_<id>-inmuebles.html | The agency's listings |
| Agency page, later page | .../inmobiliarias/<agency>_<id>-inmuebles-pagina-2.html | Reading starts at that page |
The agency directory (/inmobiliarias.bum) is not supported and is skipped with a warning. Non-www and mobile hosts are normalised to www.
Default list. If you switch to URL mode and leave the URLs field unedited, the run scrapes the nine example URLs above (one of each shape) instead of failing with no URLs. Clear the field and add your own URLs to scrape only those.
Incremental mode
Turn on incrementalMode for scheduled monitoring. The first run returns every listing as NEW; later runs return only NEW, UPDATED and REAPPEARED listings. Each row carries changeType, changedFields, firstSeenAt and lastSeenAt. emitUnchanged also returns unchanged rows (marked UNCHANGED, billed as normal listings), emitExpired marks listings that disappeared (only after a complete scan), stateKey names the campaign and ignoreFieldsForChanges lists fields that must not trigger UPDATED. Single-property pages you paste are tracked too (separately from search rows), so an unchanged property page is neither returned nor billed on later runs. The saved state is updated while the run is going, so a stopped or timed-out run does not make the next one return everything again.
Billing
The Pricing tab shows the current rates; this is what the actor charges:
- Actor start: once per run.
- Property result: once per row saved to the dataset (listings, single-property rows, and
UNCHANGED/EXPIREDrows when you ask for them). - Detail enrichment: once per property page successfully fetched when
fetchDetailsis on, charged right after that page of results is saved. It is never charged for unchanged rows, and not at all whenfetchDetailsis off.
A run that is refused by the site, or an empty search, writes no rows, so no Property result is charged; only the Actor start event applies.
How Max listings and Max pages shape a run
Max listings is the run's single hard cap: the total number of properties returned across every location or URL, split evenly between them. Set it to 0 for no cap. Max pages is an optional extra safety stop on how many result pages (about 30 listings each) are read per location or URL; leave it empty for no page cap, in which case the run is bounded solely by Max listings. Turning on Fetch full description adds one extra request per property to pull the untruncated description text; the search results already include a description, location, GPS, contacts, prices and photos, so most runs never need it.
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 (build from locations and filters) or url (paste search URLs). |
locations | array | none (prefill: ["Capital Federal"]) | Location names to search, e.g. Capital Federal, Palermo, Cordoba. Search mode only. |
operationType | string | sale | Buy (sale), rent, or temporary rent. Search mode only. |
propertyType | string | all | Property category: all, apartment, house, ph, land, office, store, warehouse, country_house, farm, office_practice, building or garage. Search mode only. |
minPrice | integer | none | Minimum price in the listing currency. Applies in both modes, including a pasted URL. |
maxPrice | integer | none | Maximum price in the listing currency. Applies in both modes, including a pasted URL. |
currency | string | any | Keep only listings in this currency: any, USD or ARS. Applies in both modes, including a pasted URL. |
minArea | integer | none | Minimum total area in square metres. Applies in both modes, including a pasted URL. |
maxArea | integer | none | Maximum total area in square metres. Applies in both modes, including a pasted URL. |
minRooms | integer | none | Minimum number of rooms (ambientes). Applies in both modes, including a pasted URL. |
maxRooms | integer | none | Maximum number of rooms (ambientes). Applies in both modes, including a pasted URL. |
minBathrooms | integer | none | Minimum number of bathrooms. Applies in both modes, including a pasted URL. Listings with no stated bathroom count are excluded. |
agenciesOnly | boolean | false | Keep only listings published by an agency (drops private owners). Applies in both modes, including a pasted URL. |
minBedrooms | integer | none | Minimum number of bedrooms (dormitorios). Applies in both modes, including a pasted URL. There is no maximum-bedrooms filter. |
sortBy | string | relevance | relevance, price-asc, price-desc or newest. Search mode only; a pasted URL carries its own order. |
urls | array | one example of each supported shape | Zonaprop URLs for URL mode: search pages (any type, operation, location, rooms or sort slug, temporary rent, -pagina-N to start from a page), agency pages and single property pages. The agency directory is not supported. Non-www and mobile hosts are normalised to www. Location, operation, property type and sort order above are ignored in this mode; the filters above still apply to search pages. |
fetchDetails | boolean | false | Fetch each property page to add the full untruncated description. Off by default. When on, the Detail enrichment event is charged per property page successfully fetched, right after that page of results is saved, so a run that stops early is still billed correctly for what it delivered. The listing already carries a description, location, GPS, contacts, prices and photos. |
maxPages | integer | none (leave empty = unlimited) | Optional safety stop on how many result pages to read per location or URL (about 30 listings per page). Does not cap the run; Max listings does that. |
maxListings | integer | 20 | The run's single hard cap: maximum total listings across all searches. Set 0 for unlimited. |
proxy | object | none (prefill: residential, country Argentina) | Connection settings. When left empty, the actor applies this same residential Argentina configuration automatically, since the site only serves results to an Argentine residential connection. |
allowProxyDowngrade | boolean | true | When on, the run may fall back to a backup connection when the primary connection is refused for the account or keeps failing on a page, and stays on it while it serves results. When off, the run uses only the configured proxy and never escalates to another connection. The residential cap and traffic budget, when set, move the run to the cheaper backup connection once reached whatever this setting says. |
residentialCap | integer | none (empty or 0 = no cap) | Optional ceiling on how many requests may use the primary residential connection in one run. Once reached, the run switches to the cheaper backup connection. |
trafficBudgetMb | integer | none (empty or 0 = no budget) | Optional cap on total downloaded data per run, in megabytes. Once reached, the run switches to the cheaper backup connection. |
resumeFromRunId | string | empty | Paste a previous run ID or dataset ID to continue an interrupted pull: listings already collected there are skipped and not returned or billed again. |
incrementalMode | boolean | false | For scheduled runs: the first run returns every listing as NEW; later runs return only NEW, UPDATED and REAPPEARED listings. Each row gets changeType, changedFields, firstSeenAt and lastSeenAt. |
stateKey | string | none | Optional name for the monitoring campaign. Empty = derived automatically from the mode, locations or URLs, operation, property type and filters. |
emitUnchanged | boolean | false | Also return unchanged listings, marked UNCHANGED. These rows are returned and billed as normal listings; detail enrichment is not run for them. |
emitExpired | boolean | false | Also return listings that are no longer found, marked EXPIRED. Only when the run read every result page of every search to the end (no Max listings cap hit, no Max pages limit, no URL starting past page 1). |
ignoreFieldsForChanges | array | none | Extra field names (dotted paths for nested fields) that must not make a listing count as UPDATED. They are still returned in the output. |
mcpConnectors | array | none | Optional: send a condensed summary of each record to apps you authorized under Integrations (Notion, Linear, Airtable or Apify). |
notionParentPageUrl | string | none | Notion connector only: page (URL or id) 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.
{"postingId": "00000000","postingCode": "AAAAAA","url": "https://www.zonaprop.com.ar/propiedades/clasificado/example-00000000.html","title": "Bright 2-bedroom apartment in Palermo","description": "Sunny apartment, fully equipped, close to transport and shops.","propertyType": "Departamentos","operationType": "Venta","status": "ONLINE","price": 185000,"currency": "USD","priceUsd": 185000,"priceArs": null,"expenses": 80000,"expensesCurrency": "$","totalArea": 72,"coveredArea": 65,"rooms": 3,"bedrooms": 2,"bathrooms": 1,"garages": 1,"age": 8,"address": "Example St 100","neighborhood": "Palermo","city": "Capital Federal","province": "Capital Federal","country": "Argentina","latitude": -34.588,"longitude": -58.43,"mainImage": "https://example.com/photo-1.jpg","images": ["https://example.com/photo-1.jpg", "https://example.com/photo-2.jpg"],"photoCount": 2,"amenities": ["Pool", "Gym"],"publisherName": "Jane Doe Propiedades","publisherType": "agency","publisherPhone": "5491100000000","publisherWhatsapp": "5491100000000","hasWhatsapp": true,"modifiedDate": "2026-01-01T00:00:00-0300","scrapedAt": "2026-01-01T00:00:00+00:00"}
Plan Requirement
zonaprop.com.ar sits behind a bot challenge that a datacenter connection fails most of the time (it is occasionally let through, so results there are unreliable). An Argentine residential connection is required for dependable results, so keep the default connection configuration (residential, country Argentina). If a residential connection is not available on your plan, the actor logs a clear warning and tries a backup connection, which may still return nothing. When no connection can load any page, the run fails with a clear message rather than returning an empty dataset: either "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required", "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Zonaprop pages", or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search."
Cost controls
The actor automatically retries with a different connection when one is refused. To bound connection spend you can also:
- set
residentialCapto limit how many requests use the primary residential connection per run; - set
trafficBudgetMbto cap total downloaded data per run; - leave
allowProxyDowngradeon (the default) so the run falls back to a cheaper backup connection after the primary connection keeps failing, and stays on it for the rest of the run; turn it off to use only the configured proxy (the cap and budget above still apply).
When either the residential cap or the traffic budget is reached, the run continues on the cheaper backup connection instead of stopping.
FAQ
How much does it cost?
You pay a small fee per run start, per property returned, and per property page fetched when you turn on the full-description fetch (see Billing above). The Pricing tab shows the current rates. Use Max listings to cap the cost of any run.
Is it legal to scrape Zonaprop?
This actor collects only publicly available property listing data. You are responsible for how you use it: follow zonaprop's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price and area are generally not protected, but photos and agency data may be subject to third-party rights.
Can I schedule it, or only get new listings?
You can schedule the actor from the Schedules tab like any other actor. Turn on Incremental changes for scheduled runs and the actor remembers each listing between runs (state is kept per search, or per State key you choose). The first run returns everything as NEW; after that you get only NEW, UPDATED and REAPPEARED listings, and listings that did not change are neither returned nor billed. changedFields names exactly what moved. Photo URLs, the antiquity counter (age, yearBuilt, condition), the per-visit viewCount, the daily publishedAgo text and scrapedAt never count as changes, though they are still returned; add more in Ignore fields when detecting changes. In incremental mode, detail enrichment (fetchDetails) and its charge apply only to NEW, UPDATED and REAPPEARED rows, never to unchanged ones, and an incremental run where nothing changed returns an empty dataset. Without incremental mode every run reads the live site from scratch.
What changed in URL mode?
URL mode now accepts search pages, agency pages and single property pages (a property page returns one row with its title, description and main image). The agency directory (/inmobiliarias.bum) is not supported and is skipped with a warning. The URLs field now has a default: if you switch to URL mode and leave it unedited, the run scrapes one example of each shape instead of failing with no URLs. Clear the field and add your own URLs to avoid this.
Why do my price, area and room filters still apply when I paste a URL?
By design. Location, operation type, property type and sort order are only meaningful in search mode, since a pasted URL already encodes them, so they're ignored in URL mode. But price, currency, area, room, bedroom, bathroom and agency filters narrow the results regardless of mode, so they still apply on top of a pasted URL.
Why did my run fail instead of returning an empty dataset?
If URL mode has no search URLs, the run fails immediately with an input error before any request is made, and nothing is charged for results; add at least one zonaprop search URL. If the site refuses every single request, the run stops with a clear error instead of billing you for a result that looks empty but was actually never read. A genuinely empty search, where the site answered but had nothing to show, succeeds with an empty dataset (earlier versions wrote a single placeholder row, which was billed as a result; it no longer does). If you see the connection-failure error, retry with an Argentina residential connection.
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:
| 🚗 Dubizzle.com Scraper Scrape dubizzle.com across the UAE for property, motors, and agent listings. Search by... | 🏠 ImmobilienScout24.de Scraper Extract property listings from immobilienscout24.de, Germany's #1 real estate platform... |
| 🏠 Fotocasa.es Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths... | 🏠 iProperty MY Scraper Scrape property listings from iProperty.com.my for sale or rent: price, PSF, bedrooms... |
| 🏠 Domclick RU Property Scraper Extract property listings from domclick.ru, one of Russia’s largest real estate portals... | 🏠 QuintoAndar Scraper Scrape QuintoAndar property listings across Brazil with 80+ fields, including rent, sale... |
💬 Support
- 🐞 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 contact@abotapi.com.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.