# DotProperty & Lamudi Real Estate - Philippines Property Scraper (`abotapi/dotproperty-com-ph-scraper`) Actor

Scrape Philippines property listings from dotproperty.com.ph and lamudi.com.ph with exact map-pin coordinates, price, beds, baths, areas, facilities, full photo galleries, and agent contact details. Covers houses, condos, apartments, townhouses, villas, land, offices and commercial units, for.

- **URL**: https://apify.com/abotapi/dotproperty-com-ph-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listing results

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

## DotProperty.com.ph and Lamudi.com.ph Scraper: Philippines Property Listings with Exact Map Coordinates

DotProperty.com.ph and Lamudi.com.ph Scraper turns the two largest property portals in the Philippines into one clean real estate data feed. Search by location, rent or sale, and property type, paste in search-result pages, or paste direct listing links, and get price, bedrooms, bathrooms, usable and land area, exact map-pin coordinates, facilities, the full photo gallery and agent contact details for houses, condos, apartments, townhouses, villas, land and offices. Every row carries a source field so you always know which portal it came from. Schedule it to run on a recurring basis with Incremental mode to get only what changed, then export the dataset to JSON, CSV or Excel, or read it through the API.

### Why This Scraper?

- **Two portals, one dataset.** DotProperty.com.ph and Lamudi.com.ph in the same run; every row carries a `source` field so you can always tell which portal it came from. Portals are walked one at a time and share the same **Max listings** budget in the order listed, so a small budget with both portals selected can return only the first portal's rows; raise **Max listings** if you want a real mix of both.
- **Exact map-pin coordinates.** Latitude and longitude come from each listing's own detail page, not a rough city-level guess.
- **Full listing detail on demand.** Price with currency and rent period, property type, bedrooms, bathrooms, usable and land area, floor, facilities, full description, complete photo gallery and agent contact details, switched on with one setting.
- **Three ways to start.** Build a search from location, operation and property-type filters, paste search-result pages, or paste direct listing links from either portal; all three are auto-classified.
- **Built for recurring monitoring.** Incremental mode tags every listing NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED against your own saved baseline, so a scheduled run reports only what changed.
- **Resume without losing progress.** Continue one interrupted run from a pasted run or dataset id; listings it already collected are skipped, not re-scraped and not billed again.
- **Pay only for what was actually collected.** The per-listing detail-enrichment fee applies only to listings whose detail page was successfully read; a listing that could not be enriched keeps its search-result fields and is not charged the extra fee.

### Use Cases

- **Real estate investment research:** track prices, price per square meter and unit availability for condos, houses and land across Metro Manila, Cebu and other cities.
- **Broker and agency lead generation:** collect agent names, phone numbers and profile links attached to active listings in a target area.
- **Rental market monitoring:** schedule recurring runs with Incremental mode to catch new listings and price changes on a rent-focused search.
- **Map-based property tools:** feed the exact latitude and longitude from listing detail pages into your own map, comparables or valuation tool.
- **Competitive monitoring for developers and agencies:** watch a development's or area's listings for new units, price changes, and units marked EXPIRED when withdrawn.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `source` | `"dotproperty"` (also `"lamudi"`) |
| `id` / `listing_id` | `"example-0000-1111-2222-000000000001"` |
| `url` | `"https://www.dotproperty.com.ph/ads/example-condo-for-sale-in-example-city_example-0000-1111-2222-000000000001"` |
| `title` | `"2 Bedroom Condo for Sale in Example City"` |
| `operation` | `"sale"` (also `"rent"`) |
| `property_type` | `"Condo"` (singular, capitalised: Condo, House, Townhouse, Villa, Apartment, Land, Office, Commercial) |
| `price` | `6500000` |
| `currency` | `"PHP"` |
| `price_period` | `"month"` (rent listings only) |
| `price_per_sqm` | `130000` |
| `bedrooms` / `bathrooms` | `2` / `2` |
| `usable_area_sqm` / `land_area_sqm` | `50` / `null` (land area applies to houses, land and townhouses) |
| `latitude` / `longitude` | `14.5547` / `121.0244` |
| `location_source` | `"detail_page"` (set once the detail page supplied the coordinates) |
| `region` / `city` | `"Metro Manila"` / `"Example City"` (lamudi listings only) |
| `facilities` | `["Swimming pool", "Gym", "24-hour security"]` |
| `images` / `image_count` | `["https://img.example.com/listing/1.jpg", "https://img.example.com/listing/2.jpg"]` / `2` |
| `agent_name` / `agent_phone` | `"Example Realty Group"` / `"+63 900 000 0000"` |
| `agent_listing_count` | `42` |
| `changeType` | `"NEW"` (also `"UPDATED"`, `"UNCHANGED"`, `"REAPPEARED"`, `"EXPIRED"`; Incremental mode only) |

Every listing also carries a full description and a breadcrumb trail of location names. dotproperty listings additionally carry a floor number (the unit's floor level on condos and apartments), `floors` (the building's storey count, on house, townhouse and villa listings), the portal's own listing-ID text, and an agent profile URL and verified-seller flag; lamudi listings additionally carry a street address, car park count, contract duration on rentals, and a list of nearby points of interest with their own coordinates. Incremental mode adds `changedFields`, `firstSeenAt` and `lastSeenAt` alongside `changeType`.

Additional fields on every row: `scraped_at` (UTC time of collection) and `posted_at` (date derived from the portal's relative "N days ago" text, day precision, approximate for months and years, `null` when unparseable). Detail enrichment also adds the portal's raw text fields where present: `price_raw`, `specs_raw`, `description_html`, `location_text`, `agent_info_text`, `agent_location` and `contact_email`. Dot Property rows also fill `property_type`, `operation`, `region`, `city` and `area` from the listing's location trail. All fields are nullable.

**Volatile fields:** `posted_ago`, `agent_listing_count`, `scraped_at`, `posted_at`, `price_raw`, `specs_raw`, `description_html`, `location_text`, `agent_info_text` and `contact_email` are never treated as a change in Incremental mode (they are still returned). Add your own names with `ignoreFieldsForChanges`.

### How to Use

**URL mode.** Set `mode` to `url` and paste pages into `urls` (`startUrls` is accepted as an alias). Supported shapes: dotproperty search pages by location, operation and property type (including the apex host without `www`), `?page=N`, filter and sort query strings, single listing pages (`/ads/...`), agency and publisher pages; lamudi rent and buy search pages (with `?page=N`, filters and `sorting=newest`), single listing pages (`/property/...`) and agent pages (`/real-estate-agent/...`). If you leave `urls` unedited, it holds 16 example URLs, one per shape, so URL mode scrapes those examples (capped by Max listings). Replace them with your own pages, or clear the field, before running.

1. Pick a **mode**: `search` (build a search from filters) or `url` (paste one or more dotproperty.com.ph or lamudi.com.ph pages).
2. In search mode, choose the portals, operation (sale or rent), property types and locations, plus any price, bedroom or floor-area filters.
3. Set **Max listings** (and optionally **Max pages**) to size the run, and choose whether to fetch full detail pages.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search condos for sale in Makati on both portals:**

```json
{
  "mode": "search",
  "sites": ["dotproperty", "lamudi"],
  "operation": "sale",
  "propertyTypes": ["condos"],
  "locations": ["Makati"],
  "maxItems": 50
}
```

**Filtered search: houses for rent in Cebu with a price, bedroom and area floor:**

```json
{
  "mode": "search",
  "sites": ["dotproperty"],
  "operation": "rent",
  "propertyTypes": ["houses"],
  "locations": ["Cebu"],
  "minPrice": 20000,
  "maxPrice": 60000,
  "minBedrooms": 3,
  "minSqm": 100,
  "maxItems": 100
}
```

**Paste search or listing pages from either portal:**

```json
{
  "mode": "url",
  "urls": [
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati",
    "https://www.lamudi.com.ph/rent/metro-manila/quezon-city/apartment/"
  ],
  "maxItems": 100
}
```

**Recurring monitoring: only new, changed or withdrawn condo listings:**

```json
{
  "mode": "search",
  "sites": ["dotproperty"],
  "operation": "sale",
  "propertyTypes": ["condos"],
  "locations": ["Makati"],
  "incrementalMode": true,
  "emitExpired": true,
  "maxItems": 300
}
```

For EXPIRED to ever fire, **Max listings** has to be set comfortably above the search's real total, so the run reaches the natural end of every search and pasted URL instead of stopping early on the cap. `maxItems: 0` is rejected by the input form (the minimum is 1); leave it at a real number sized to your search, and narrow the scope (one portal, one city, one property type) to keep run time and cost predictable.

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/dotproperty-com-ph-scraper").call(run_input={
    "mode": "search", "sites": ["dotproperty", "lamudi"], "operation": "sale",
    "propertyTypes": ["condos"], "locations": ["Makati"], "maxItems": 50,
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(listing.get("title"), listing.get("price"), listing.get("currency"))
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/dotproperty-com-ph-scraper').call({
  mode: 'search', sites: ['dotproperty', 'lamudi'], operation: 'sale',
  propertyTypes: ['condos'], locations: ['Makati'], maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Detail enrichment and what it costs

Billing events: `apify-default-dataset-item` (once per row returned in the dataset), `detail-enrichment` (once per row whose detail page was read successfully, only when **Fetch detail pages** is on or a single listing URL is pasted) and `apify-actor-start` (once per run). Exact rates are on the **Pricing** tab.

**Fetch detail pages** is ON by default. When it is on, listings found through search results or pasted search pages are enriched with exact coordinates, facilities, the full photo gallery, description and agent contact details, and each one that is successfully enriched (a price and exact coordinates were read from its detail page) carries a per-listing detail-enrichment charge. A listing whose detail page could not be read (blocked, removed, or came back with no usable data) keeps only its search-result fields and is never charged that fee. A pasted single-listing URL is always fetched in full and, if it loads and yields a price and exact coordinates, carries the detail-enrichment charge (a page that loads but yields neither keeps its row and is not charged); the **Fetch detail pages** setting has no effect on that path, because a pasted listing page has no separate search-result row to fall back to.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset id and every listing it already collected is skipped, not re-fetched or billed again. The resumed run still walks each search or pasted URL from its first page, so it can take a little longer to catch up, but because only newly-collected listings count against **Max listings**, the run naturally reaches pages the earlier run never got to. If the earlier run stopped because it hit **Max pages** rather than **Max listings**, raise **Max pages** on the resumed run too, or it will stop at the same page again.
- **Incremental mode** (`incrementalMode`) is for recurring runs over the same search. Each listing is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed, and not billed, unless `emitUnchanged` is on), or `EXPIRED`. A listing is only ever marked as no longer present when **Emit expired listings** was on for a run that walked every search and pasted URL to its own natural end, with no **Max listings** cap reached and no Resume involved; a partial or resumed run leaves the previous state untouched instead of guessing. `REAPPEARED` can therefore only happen to a listing that a previous complete, Emit-expired run had already marked EXPIRED and a later run found again; it never fires on a listing's first-ever appearance. `stateKey` is optional: leave it blank to auto-derive the tracked scope from your search filters, or set it to merge two different searches into one monitoring campaign.
- **Ignore fields when detecting changes** (`ignoreFieldsForChanges`) lists extra output field names that must not make a listing `UPDATED` (a name matches at any nesting depth; ignored fields are still returned). These fields are always ignored by default because they change without the listing itself changing, or only restate a field that is compared: `posted_ago` (relative age text that ticks forward daily), `agent_listing_count` (the agent's count of other listings, which moves whenever that agent posts or removes any listing), `scraped_at`, `posted_at`, `price_raw`, `specs_raw`, `description_html`, `location_text`, `agent_info_text` and `contact_email`. `image_count` is kept in the comparison because it only moves when the photo gallery really changes. Changing the ignore set never causes a one-time wave of `UPDATED` rows, because the saved baseline is re-compared with the current ignore set. A pasted search URL that starts at `?page=2` or later never counts as a complete scan, so it cannot mark listings EXPIRED.

### 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 listing, 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**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to 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 | (prefill: `search`) | `search` builds URLs from the filters below; `url` uses pasted dotproperty.com.ph or lamudi.com.ph pages. |
| `sites` | array | (prefill: both portals) | Which portals to search: `dotproperty`, `lamudi`, or both. |
| `operation` | string | `sale` | `sale` or `rent`. |
| `propertyTypes` | array | (prefill: `["properties"]`) | `properties` (all), `houses`, `condos`, `apartments`, `townhouses`, `villas`, `land`, `offices`. |
| `locations` | array | (prefill: `["Metro Manila"]`) | Location names or slugs, e.g. `Metro Manila`, `Makati`, `Cebu`. Search mode only. |
| `minPrice` | integer | - | Minimum price in PHP. Leave empty for no minimum. |
| `maxPrice` | integer | - | Maximum price in PHP. Leave empty for no maximum. |
| `minBedrooms` | integer | - | Minimum number of bedrooms (0 = studio). |
| `minSqm` | integer | - | Minimum usable floor area in square meters. |
| `sort` | string | `newest` | Sort order on dotproperty: `newest`, `min_price`, `max_price`, or `relevance`. Lamudi honours only `newest`; other values keep its default order. |
| `urls` | array | 16 example URLs, one per supported page shape | One or more dotproperty.com.ph or lamudi.com.ph search, listing, agency, publisher or agent pages (`startUrls` is accepted as an alias). URL mode only. Left unedited, URL mode scrapes one example per shape (capped by Max listings). |
| `maxItems` | integer | `20` | Cap on listings collected across all searches and pasted search/category URLs, shared portal by portal in the order listed. Pasted single listing URLs are not counted against this cap; each one is always fetched and billed. |
| `maxPages` | integer | - | Optional page cap per search. Leave empty for no page limit; the run stops at Max listings instead. |
| `fetchDetails` | boolean | `true` | Enrich results with exact coordinates, facilities, full gallery, description and agent contacts. Adds a per-listing detail-enrichment charge for listings it successfully enriches. |
| `proxy` | object | (prefill: Apify Proxy, PH) | Connection settings for the run. |
| `resumeFromRunId` | string | - | Paste a previous run or dataset id to continue that one interrupted crawl. |
| `incrementalMode` | boolean | `false` | Recurring monitoring: remembers the previous run of this same search and classifies each listing as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. |
| `stateKey` | string | - | Optional manual key to control which runs share incremental state. |
| `monitoringMode` | boolean | `false` | Turns on incremental tracking and returns only listings not seen on earlier runs of the same search (NEW or REAPPEARED); with **Emit expired listings** also on, listings no longer found are returned too (EXPIRED) and billed. |
| `resetMonitoringState` | boolean | `false` | One-run reset: discards the saved state for this search and starts a fresh baseline. |
| `emitUnchanged` | boolean | `false` | Incremental mode: also return (and bill) listings with no detected change. |
| `emitExpired` | boolean | `false` | Incremental mode: also return (and bill) listings no longer found, after a complete, uncapped, non-resumed scan. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode: extra field names that never count as a change (any nesting depth); still returned in the output. |
| `mcpConnectors` | array | - | MCP connectors to also deliver results into (Notion, Linear, Airtable, Apify). Leave empty to skip. |
| `notionParentPageUrl` | string | - | Notion connector only: URL or id of the page under which item pages are created. Ignored by other connectors. |
| `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 record.

```json
{
  "id": "example-0000-1111-2222-000000000001",
  "listing_id": "example-0000-1111-2222-000000000001",
  "source": "dotproperty",
  "url": "https://www.dotproperty.com.ph/ads/example-condo-for-sale-in-example-city_example-0000-1111-2222-000000000001",
  "title": "2 Bedroom Condo for Sale in Example City",
  "price": 6500000,
  "currency": "PHP",
  "price_per_sqm": 130000,
  "bedrooms": 2,
  "bathrooms": 2,
  "usable_area_sqm": 50,
  "floor": 12,
  "latitude": 14.5547,
  "longitude": 121.0244,
  "location_source": "detail_page",
  "breadcrumbs": ["Philippines", "Metro Manila", "Example City"],
  "facilities": ["Swimming pool", "Gym", "24-hour security", "Function room"],
  "images": [
    "https://img.example.com/listing/1.jpg",
    "https://img.example.com/listing/2.jpg"
  ],
  "image_count": 2,
  "og_image": "https://img.example.com/listing/1.jpg",
  "description": "Bright 2 bedroom unit with balcony and city view, close to Example City's main business district.",
  "listing_id_text": "EX-000123",
  "agent_name": "Example Realty Group",
  "agent_phone": "+63 900 000 0000",
  "agent_url": "https://www.dotproperty.com.ph/agency/example-realty-group",
  "agent_listing_count": 42,
  "agent_verified": true
}
```

### Plan Requirement

Connection settings default to Apify Proxy with no specific group selected, and the run automatically retries with a different connection when one is refused. dotproperty.com.ph was served normally from datacenter connections in our checks. lamudi.com.ph refuses some datacenter exits with a plain 403 (a short CloudFront "Request blocked" page) while others succeed, so the run rotates to a fresh connection on that refusal; no challenge or captcha is involved. A Philippines country pin only takes effect once you pick a proxy group under **Proxy configuration**. For a run that keeps getting blocked, switch the connection group to residential for more headroom.

### FAQ

#### How much does it cost?

You pay a per-listing fee for every row returned in the dataset, plus a separate detail-enrichment fee only for listings whose detail page was actually read successfully. A pasted single-listing URL carries the detail-enrichment fee when its page loads and yields a price and exact coordinates. The **Pricing** tab shows the current rates. Use **Max listings** to cap the cost of any run.

#### Is it legal to scrape DotProperty.com.ph and Lamudi.com.ph?

This actor collects only publicly available property listing data. You are responsible for how you use it: follow each portal's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts such as price, size and location are generally facts, but photos and agent-submitted text may be subject to third-party rights.

#### Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Unchanged listings are then suppressed and not billed unless you turn on **Emit unchanged listings**, and withdrawn listings are only reported once a run completes a full, uncapped scan with **Emit expired listings** on.

#### Why did I get fewer listings than expected, or none at all?

Each search or pasted URL is walked independently: if one location or portal is temporarily unreachable, the run still returns everything it could read from the others rather than failing the whole run. Check the run log for pages it could not read, then run it again, raise **Max pages**, or switch the connection group under **Proxy configuration**.

#### 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:

<table>
<tr><td>🏨 <a href="https://apify.com/abotapi/hipflat-scraper"><b>Hipflat Thailand Scraper</b></a><br>Scrape Hipflat (hipflat.co.th) properties for sale and rent across Thailand. Extract...</td><td>🏠 <a href="https://apify.com/abotapi/rumah123-indonesia-property-scraper"><b>Rumah123 Scraper</b></a><br>Pull structured property listings from Rumah123.com, Indonesia’s largest property portal...</td></tr>
<tr><td>🏠 <a href="https://apify.com/abotapi/rent-com-scraper"><b>Rent.com Scraper</b></a><br>Extract rental listings from rent.com. Get comprehensive data including monthly rent...</td><td>🏠 <a href="https://apify.com/abotapi/fotocasa-es-scraper"><b>Fotocasa.es</b></a><br>Scrape Spain property listings from fotocasa.es. Get price, surface, rooms, baths...</td></tr>
<tr><td>🧩 <a href="https://apify.com/abotapi/homes-com-scraper"><b>Homes.com Scraper</b></a><br>Scrape US property records from Homes.com. Pick a city, state or ZIP and a channel (for...</td><td>🏠 <a href="https://apify.com/abotapi/batdongsan-com-vn-scraper"><b>Batdongsan.com.vn</b></a><br>Scrape Batdongsan.com.vn property listings into clean JSON. Search by listing type...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/dotproperty-com-ph-scraper/issues/open). 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.

# Actor input Schema

## `mode` (type: `string`):

Search mode = build search URLs from the filters below. URL mode = paste one or more dotproperty.com.ph or lamudi.com.ph URLs (search or listing pages); they are auto-classified and pagination advances forward from any ?page=N you provide.

## `sites` (type: `array`):

Which Philippines property portals to search. Both by default — every row carries a source field so you can tell them apart.

## `operation` (type: `string`):

Whether to search rental listings or listings for sale.

## `propertyTypes` (type: `array`):

Which property types to search. 'properties' means all types. (Townhouses and villas exist only on Dot Property; offices map to Lamudi's commercial category; land maps to land on both.)

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

Location names or slugs — e.g. 'Metro Manila', 'Makati', 'Cebu', 'metro-manila/makati'. Case and spaces don't matter; they are slugified automatically. One search is built per (portal x property type x location).

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

Minimum price in Philippine Pesos. Leave empty for no minimum.

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

Maximum price in Philippine Pesos. Leave empty for no maximum.

## `minBedrooms` (type: `integer`):

Minimum number of bedrooms (0=studio).

## `minSqm` (type: `integer`):

Minimum usable floor area in square meters. Applied by both sites.

## `sort` (type: `string`):

Sort order. Dot Property supports all four values. Lamudi honours only Newest first (sorting=newest); for the other values Lamudi keeps its default order.

## `urls` (type: `array`):

One or more dotproperty.com.ph or lamudi.com.ph URLs. Paste search pages (e.g. /properties-for-sale/metro-manila/makati or /rent/metro-manila/makati/house/) or direct listing pages (/ads/{slug}\_{id} or /property/{id}). Also accepted: agency and publisher pages, lamudi agent pages (/real-estate-agent/{id}), and ?page=N / filter / sort query strings. Left unedited, this field scrapes one example URL per supported page shape. Search URLs continue through all available results pages; a listing URL is collected once. In URL mode the search-mode fields above are ignored.

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

Hard cap on the number of listings collected across all searches and URLs. This is the run's volume limit; leave Max pages below unlimited (empty).

## `maxPages` (type: `integer`):

Optional page cap per search URL. Leave empty for no page limit — the run stops at Max listings. Both portals show roughly 25-30 listings per page.

## `fetchDetails` (type: `boolean`):

When ON, results are enriched with exact map coordinates (lat/lng), facilities, the full photo gallery, description, and agent contact details. Adds a per-listing detail-enrichment charge. Default ON — the exact map-pin coordinates only exist in the full listing data.

## `proxy` (type: `object`):

Works on every Apify plan. If a run gets blocked, select RESIDENTIAL proxies and a PH country pin for the most locally-consistent results.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue that ONE interrupted crawl - listings it already collected are skipped, not re-scraped. Unrelated to Incremental mode below, which tracks a recurring search across scheduled runs.

## `incrementalMode` (type: `boolean`):

When ON, this actor remembers the last run of this SAME search (via its own saved state, keyed on your filters or on State key below) and classifies every listing as NEW / UPDATED / REAPPEARED / EXPIRED. Unrelated to Resume from run/dataset ID above, which continues one specific interrupted run. Default OFF - normal runs return every matching listing every time.

## `stateKey` (type: `string`):

Optional. Set this to a name of your choice to manually control which runs share incremental state (e.g. to deliberately merge two different searches into one monitoring campaign). Leave blank to auto-derive the key from your search filters - two different filter setups then never share a baseline.

## `emitUnchanged` (type: `boolean`):

When ON, listings with no detected change are still returned (tagged changeType=UNCHANGED) instead of being suppressed. Off by default so a recurring run returns only what actually changed. Turning this ON returns - and bills, at the standard per-result rate - every listing scanned, not just the changed ones.

## `emitExpired` (type: `boolean`):

When ON, listings tracked by a previous incremental run that no longer appear are returned once, tagged changeType=EXPIRED. Only fires after a run that scans its search to a genuine natural end (no Max listings cap hit, no Resume) - a partial run leaves previous state untouched instead of guessing. Turning this ON returns - and bills, at the standard per-result rate - these extra rows.

## `monitoringMode` (type: `boolean`):

When ON, turns on Incremental mode and returns only listings not seen on previous runs of the same search (NEW or REAPPEARED). Updated listings are tracked silently. If Emit expired listings is also ON, listings that are no longer found are still returned (tagged EXPIRED) and billed at the standard per-result rate.

## `resetMonitoringState` (type: `boolean`):

When ON together with Incremental or Monitoring mode, this run discards the saved state for the search and starts a fresh baseline. Turn OFF again afterwards.

## `ignoreFieldsForChanges` (type: `array`):

Output field names that should NOT make a listing count as UPDATED, even when they changed. These fields are always ignored already: posted_ago, agent_listing_count, scraped_at, posted_at, price_raw, specs_raw, description_html, location_text, agent_info_text and contact_email. The order of images, facilities, nearby places and breadcrumbs is also ignored. Add more names here, for example price_per_sqm. A name matches at any nesting depth. Ignored fields are still returned in the output.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "sites": [
    "dotproperty",
    "lamudi"
  ],
  "operation": "sale",
  "propertyTypes": [
    "properties"
  ],
  "locations": [
    "Metro Manila"
  ],
  "sort": "newest",
  "urls": [
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati",
    "https://www.dotproperty.com.ph/properties-for-rent/metro-manila/makati",
    "https://www.dotproperty.com.ph/houses-for-sale/cebu",
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila",
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati?page=3&min_price=5000000&sort=max_price",
    "https://www.dotproperty.com.ph/ads/1-bedroom-condo-for-sale-in-the-linear-san-antonio-metro-manila_5971c811f880-1371-3792-81d0-a8181089",
    "https://www.dotproperty.com.ph/agency/lolito-l-varona/14219/properties-for-sale",
    "https://www.dotproperty.com.ph/publisher/ace-realty_26a9fb842b94-7e51-4f75-5bc3-aa7048e4/properties-for-sale",
    "https://dotproperty.com.ph/properties-for-sale/metro-manila/makati",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/",
    "https://www.lamudi.com.ph/buy/metro-manila/makati/condo/",
    "https://www.lamudi.com.ph/rent/metro-manila/",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?page=2",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?minArea=100&sorting=newest",
    "https://www.lamudi.com.ph/property/41032-73-1c939e8724cc-cdfe-19a5dd8-89d9-7a98",
    "https://www.lamudi.com.ph/real-estate-agent/41032-73-42010a940051-bef8-5882a58b-9f43-1234"
  ],
  "maxItems": 20,
  "fetchDetails": true,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [],
    "apifyProxyCountry": "PH"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

Every listing collected by this run, with price, size, location and change type.

## `map` (type: `string`):

Listings with their exact map coordinates.

## `agents` (type: `string`):

The seller or agent behind each listing.

## `detailed` (type: `string`):

Every scraped field, including description, facilities, photos and nearby places.

## `changes` (type: `string`):

Change type, changed fields and first/last seen times for incremental runs.

# 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 = {
    "mode": "search",
    "sites": [
        "dotproperty",
        "lamudi"
    ],
    "operation": "sale",
    "propertyTypes": [
        "properties"
    ],
    "locations": [
        "Metro Manila"
    ],
    "sort": "newest",
    "urls": [
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati",
        "https://www.dotproperty.com.ph/properties-for-rent/metro-manila/makati",
        "https://www.dotproperty.com.ph/houses-for-sale/cebu",
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila",
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati?page=3&min_price=5000000&sort=max_price",
        "https://www.dotproperty.com.ph/ads/1-bedroom-condo-for-sale-in-the-linear-san-antonio-metro-manila_5971c811f880-1371-3792-81d0-a8181089",
        "https://www.dotproperty.com.ph/agency/lolito-l-varona/14219/properties-for-sale",
        "https://www.dotproperty.com.ph/publisher/ace-realty_26a9fb842b94-7e51-4f75-5bc3-aa7048e4/properties-for-sale",
        "https://dotproperty.com.ph/properties-for-sale/metro-manila/makati",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/",
        "https://www.lamudi.com.ph/buy/metro-manila/makati/condo/",
        "https://www.lamudi.com.ph/rent/metro-manila/",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?page=2",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?minArea=100&sorting=newest",
        "https://www.lamudi.com.ph/property/41032-73-1c939e8724cc-cdfe-19a5dd8-89d9-7a98",
        "https://www.lamudi.com.ph/real-estate-agent/41032-73-42010a940051-bef8-5882a58b-9f43-1234"
    ],
    "maxItems": 20,
    "fetchDetails": true,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [],
        "apifyProxyCountry": "PH"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "monitoringMode": false,
    "resetMonitoringState": false,
    "ignoreFieldsForChanges": [],
    "maxNotifyListings": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/dotproperty-com-ph-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 = {
    "mode": "search",
    "sites": [
        "dotproperty",
        "lamudi",
    ],
    "operation": "sale",
    "propertyTypes": ["properties"],
    "locations": ["Metro Manila"],
    "sort": "newest",
    "urls": [
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati",
        "https://www.dotproperty.com.ph/properties-for-rent/metro-manila/makati",
        "https://www.dotproperty.com.ph/houses-for-sale/cebu",
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila",
        "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati?page=3&min_price=5000000&sort=max_price",
        "https://www.dotproperty.com.ph/ads/1-bedroom-condo-for-sale-in-the-linear-san-antonio-metro-manila_5971c811f880-1371-3792-81d0-a8181089",
        "https://www.dotproperty.com.ph/agency/lolito-l-varona/14219/properties-for-sale",
        "https://www.dotproperty.com.ph/publisher/ace-realty_26a9fb842b94-7e51-4f75-5bc3-aa7048e4/properties-for-sale",
        "https://dotproperty.com.ph/properties-for-sale/metro-manila/makati",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/",
        "https://www.lamudi.com.ph/buy/metro-manila/makati/condo/",
        "https://www.lamudi.com.ph/rent/metro-manila/",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?page=2",
        "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?minArea=100&sorting=newest",
        "https://www.lamudi.com.ph/property/41032-73-1c939e8724cc-cdfe-19a5dd8-89d9-7a98",
        "https://www.lamudi.com.ph/real-estate-agent/41032-73-42010a940051-bef8-5882a58b-9f43-1234",
    ],
    "maxItems": 20,
    "fetchDetails": True,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
        "apifyProxyCountry": "PH",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "monitoringMode": False,
    "resetMonitoringState": False,
    "ignoreFieldsForChanges": [],
    "maxNotifyListings": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/dotproperty-com-ph-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 '{
  "mode": "search",
  "sites": [
    "dotproperty",
    "lamudi"
  ],
  "operation": "sale",
  "propertyTypes": [
    "properties"
  ],
  "locations": [
    "Metro Manila"
  ],
  "sort": "newest",
  "urls": [
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati",
    "https://www.dotproperty.com.ph/properties-for-rent/metro-manila/makati",
    "https://www.dotproperty.com.ph/houses-for-sale/cebu",
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila",
    "https://www.dotproperty.com.ph/properties-for-sale/metro-manila/makati?page=3&min_price=5000000&sort=max_price",
    "https://www.dotproperty.com.ph/ads/1-bedroom-condo-for-sale-in-the-linear-san-antonio-metro-manila_5971c811f880-1371-3792-81d0-a8181089",
    "https://www.dotproperty.com.ph/agency/lolito-l-varona/14219/properties-for-sale",
    "https://www.dotproperty.com.ph/publisher/ace-realty_26a9fb842b94-7e51-4f75-5bc3-aa7048e4/properties-for-sale",
    "https://dotproperty.com.ph/properties-for-sale/metro-manila/makati",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/",
    "https://www.lamudi.com.ph/buy/metro-manila/makati/condo/",
    "https://www.lamudi.com.ph/rent/metro-manila/",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?page=2",
    "https://www.lamudi.com.ph/rent/metro-manila/makati/house/?minArea=100&sorting=newest",
    "https://www.lamudi.com.ph/property/41032-73-1c939e8724cc-cdfe-19a5dd8-89d9-7a98",
    "https://www.lamudi.com.ph/real-estate-agent/41032-73-42010a940051-bef8-5882a58b-9f43-1234"
  ],
  "maxItems": 20,
  "fetchDetails": true,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [],
    "apifyProxyCountry": "PH"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}' |
apify call abotapi/dotproperty-com-ph-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/dotproperty-com-ph-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/wn5twwvRinqeZrJNM/builds/yOIXuAfEmO5WJw58c/openapi.json
