# Realtor Scraper (`negligible_endive/realtor-scraper`) Actor

Collect US Realtor.com listings from search links or locations, continue with saved batches, and monitor observed price and status changes. Includes nationwide search, optional history and datacenter-first proxy fallback.

- **URL**: https://apify.com/negligible_endive/realtor-scraper.md
- **Developed by:** [Gemmah](https://apify.com/negligible_endive) (community)
- **Categories:** Real estate
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 4.50 out of 5 stars

## Pricing

from $0.79 / 1,000 property records

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

## Realtor Scraper

Collect Realtor.com property listings from search-page links, selected US locations or a nationwide search, and track price and status changes across repeat runs. Search homes for sale, rental listings and sold properties with configurable filters, optional source history and Apify Proxy support.

Use the results for property research, comparable listing analysis, price monitoring and recurring market reports. Coverage is limited to the United States.

This Actor is independently developed and is not affiliated with or endorsed by Realtor.com.

### Key features

- Paste listing search-page links and follow their pagination automatically.
- Search all 50 states and Washington, DC, or choose cities, counties, ZIP codes or states.
- Type cities, counties or ZIP codes into a lightweight location field; use the state dropdown to narrow your search.
- Remove duplicate property IDs within each run.
- Continue across multiple batches using saved progress, skipping previously delivered properties.
- Filter by price, property type, bedrooms, bathrooms, size, location, dates and amenities.
- Collect listing details, photo galleries and public agent or broker information when available.
- Recover missing descriptions with up to three detail lookups and verify the listing ID before merging text.
- Request source-provided price and sale history.
- Track observed price reductions, price increases, status changes and relistings using a persistent snapshot.
- Export all matched properties or only observed changes.
- Choose a record count and spending limit; source request limits are managed automatically.
- Follow numbered listing-page logs and open ready-made next-run input from the Output tab.

### Getting started

1. Paste a Realtor.com search link into **Listing page links (optional)**, or leave it empty to search by location.
2. Set **How many properties?** The default is 100.
3. For location searches, choose a listing category and optionally type cities or select states. Leave locations empty to search nationwide.
4. Run the Actor, then open the dataset to view or export results as JSON or CSV.

Property filters, listing content, continuation and advanced settings are grouped into optional sections. All four **Information to include** options are off by default: detailed information, photo galleries, public agent/broker details and source price/sale history. Enable only the options you need. Apify Proxy appears in the last input section, above the platform's run controls.

The city field accepts typed locations without loading a large city dropdown. Enter one location per entry, such as `Houston, TX`, `Harris County, TX` or `77002`. Include the state code for cities and counties to avoid ambiguous place names. The state dropdown remains available; no city autocomplete is included.

If you select a state filter, explicitly named locations must match one of the selected states. For example, `Houston, TX` with California selected stops with a clear error before source requests, proxy initialization or record billing. This check also covers county, state and search-link locations. With several states selected, a location may match any one of them. ZIP codes and city names without a state cannot be checked locally; the state filter still applies to returned records.

For batch continuation, set **Batch continuation** to **Continue**. You can leave the saved store empty on the first run: the Actor names that run's progress store automatically. Open **Output → Resume instructions** to find its ID and a ready-to-copy input for the next batch. Later batches must reuse that ID. For price monitoring with continuation off, you can also reuse the store shown in the output.

#### Nationwide example

```json
{
  "maxRecords": 100
}
```

This searches states in order until it reaches the record or request limit. A small nationwide batch can contain properties from the first state only; it is not a geographically balanced sample. To restrict the search to states, set `states`, for example `["CA", "TX"]`, without entering cities.

#### Listing-link example

```json
{
  "startUrls": [
    "https://www.realtor.com/realestateandhomes-search/Houston_TX/price-100000-750000/beds-3-na"
  ],
  "maxRecords": 100
}
```

Links must be Realtor.com search pages under `/realestateandhomes-search/` or `/apartments/`. Supported URL filters include property type, price, bedrooms, bathrooms, floor area, recently sold, foreclosure, new construction, last-seven-day listings (`show-newest-listings`) and supported sort codes. Their filters, listing category and sorting are carried into subsequent pages. Tracking parameters are ignored; unsupported filters or conflicting Actor filters produce a clear error before collection.

`show-newest-listings` restricts results to listings added in the last seven days; `sby-6` separately sorts newest first. Batch continuation preserves the date window from the first run. Restart the saved search to refresh that window, or turn continuation off for recurring monitoring of the current seven days.

Supply listing links or locations, rather than both. Each link determines its own sale, rental or sold category. Individual property detail links are output fields and are not accepted as search inputs. An input link containing `pg-N` identifies the search; a fresh run starts at its first page. Use batch continuation to resume saved progress.

#### Example input

Collect up to 100 single-family homes in Texas with at least three bedrooms and two bathrooms, priced between $100,000 and $750,000:

```json
{
  "country": "US",
  "markets": ["Houston, TX"],
  "listingTypes": ["for_sale"],
  "maxRecords": 100,
  "minPrice": 100000,
  "maxPrice": 750000,
  "minBedrooms": 3,
  "minBathrooms": 2,
  "propertyTypes": ["single_family"],
  "states": ["TX"],
  "sortBy": "newest",
  "includeHistory": false,
  "proxyConfiguration": {"useApifyProxy": false}
}
```

Increase `maxRecords` for larger samples. Request allowance, pacing, history concurrency and proxy traffic protection are managed automatically. The actual count depends on matching inventory, source access, internal safety limits and your spending limit. Searches can include nearby cities; use `cities` to require exact city matches.

### Pricing

When paid pricing is enabled, charges are based on delivered information:

| Information | Price per 1,000 | Event price |
| --- | ---: | ---: |
| Actual matched property records | $0.99 | $0.00099 |
| Detailed information, when selected and available | +$0.25 | $0.00025 |
| Successfully retrieved source history, when selected | +$1.00 | $0.001 |
| Photo URLs and public agent/broker details | Included | No additional event |

Base records with both paid options successfully delivered cost **$2.24 per 1,000**. All optional information groups are off by default, so the default content costs **$0.99 per 1,000** before applicable Store discounts. Enable details or source history to select their paid add-ons. All options and their prices are explained in the input form.

#### Apify Store discounts

Your Apify discount tier determines the price. Discounts apply to all three paid events; photo URLs and public agent/broker details remain included.

| Discount tier | Discount | Base records per 1,000 | Delivered details per 1,000 | Successful history per 1,000 | All three per 1,000 |
| --- | ---: | ---: | ---: | ---: | ---: |
| Free / Bronze | 0% | $0.99 | $0.25 | $1.00 | $2.24 |
| Silver | 10% | $0.891 | $0.225 | $0.90 | $2.016 |
| Gold / Platinum / Diamond | 20% | $0.792 | $0.20 | $0.80 | $1.792 |

The Actor uses your actual event prices when enforcing spending limits. `SUMMARY.billingEventPricesUsd` and `SUMMARY.storeDiscountPercent` show the rates applied to your run. All-three totals assume every property delivers qualifying detailed information and non-empty source history. Missing add-ons are not charged.

Each unique matched property triggers one `property-checked` event. `property-details` is charged once only if details are selected and at least one description, amenity, HOA fee or open-house entry is delivered. A partially populated details group can still qualify; inspect the description coverage fields for missing text. `source-history` is charged once only if history is selected, the request succeeds and at least one source history event is returned. Failed or empty histories and entirely empty details groups incur no add-on. The complete historical record is not guaranteed; `maxHistoryEntries` bounds delivered events.

Duplicate IDs, filter rejects and missing or invalid records are not billed. Retry requests, photo URLs, public agent details, Actor startup and automatic dataset-item writes have no additional Actor event fee.

Checking a property again on a later monitoring run is a new billable observation, even if its price is unchanged. `changesOnly` filters the default dataset; it does not reduce the number of matched properties or successfully delivered optional information billed. All processed observations remain available in run storage.

Continuation skips properties already delivered in the same resume session, including their add-on events. Explicit Restart begins a new session and can return and bill those properties again.

Spending limits reserve the combined maximum cost of selected content before source requests begin, then verify actual delivered event costs before saving a batch. This conservative initial cap can stop a run below its requested count even when some optional data later proves unavailable. No charge exceeds the user's spending limit. If a delivery or multi-event charge is interrupted, automatic continuation stops for review to avoid duplicate billing.

### Input reference

Numeric bounds are inclusive. Prices and HOA fees use USD; property and lot sizes use square feet.

| Inputs | Purpose |
| --- | --- |
| `startUrls` | Up to 100 Realtor.com listing search-page links. URLs determine their listing category, supported filters and sorting. |
| `markets`, `listingTypes`, `country` | Optional US city, county, ZIP or state searches, up to 100 locations. Empty locations search selected states or all 50 states and DC. Listing types: `for_sale`, `for_rent`, `sold`. Country: `US`. |
| `minPrice` / `maxPrice` | Asking-price range. |
| `minBedrooms` / `maxBedrooms`, `minBathrooms` / `maxBathrooms` | Bedroom and bathroom ranges. |
| `minSquareFeet` / `maxSquareFeet`, `minLotSquareFeet` / `maxLotSquareFeet` | Floor and lot area ranges. |
| `minYearBuilt` / `maxYearBuilt`, `minGarageSpaces` / `maxGarageSpaces`, `minHoaFee` / `maxHoaFee` | Construction year, garage capacity and HOA fee ranges. |
| `propertyTypes` | Property categories, such as `single_family`, `condos`, `townhomes`, `multi_family` or `land`. See the input form for supported values. |
| `cities`, `states`, `postalCodes` | Exact location matches. With no links or locations, `states` also selects which states to search. Cities ignore case; states use uppercase two-letter codes; ZIP codes are strings. |
| `keywords`, `amenities`, `excludeKeywords` | Text matching across descriptions, addresses, tags and amenities. All required terms must match; any excluded term rejects the record. |
| `pending`, `contingent`, `newConstruction`, `hasPhotos`, `foreclosure` | Select `any`, `yes` or `no` in the input form. Foreclosure classification comes from source search. |
| `listedAfter` / `listedBefore`, `updatedAfter` / `updatedBefore`, `soldAfter` / `soldBefore` | Inclusive ISO date or datetime bounds. A date without a time means midnight UTC. |
| `boundingBox` | Geographic bounds with `south`, `north`, `west` and `east`. Bounds crossing the date line are unsupported. |
| `sortBy` | `price_asc` (default), `price_desc`, `newest` or `oldest`. |
| `includeDetails`, `includePhotos`, `includeAgentDetails` | Include optional listing content. All default to false; enable the groups you need. |
| `includeHistory` | Request source-provided price and sale history. Defaults to false. |
| `maxPhotos`, `maxHistoryEntries` | Retain up to 25 photos and 100 history entries per property by default; maximums are 200 and 1,000. |
| `maxRecords` | Maximum properties to fetch. Defaults to 100, up to 100,000 per run. Internal request and traffic allowances adjust automatically. |
| `changesOnly`, `snapshotStoreId`, `snapshotKey` | Change-only exports and persistent monitoring. |
| `resumeMode`, `resumeKey` | `off` (default) starts searches again; `continue` starts or continues a saved batch session; `restart` explicitly replaces its progress. |
| `proxyConfiguration` | Optional Apify Proxy. Disabled by default; enabled runs always start with datacenter routing. |

Price, bedrooms, bathrooms, sizes, construction year, property type and foreclosure are passed to source search. Other criteria are applied to returned records; numeric and property-type filters are also checked locally. Missing values do not satisfy requested numeric or boolean filters. Restrictive filters can require more requests.

Filters can also be supplied inside a `filters` object. Use booleans there for yes/no criteria. Conflicting flat and nested filter values are rejected.

#### Source history and automatic limits

Set `includeHistory` to true to request source history. This normally adds one source request per matched property. When details are enabled and a description is empty, the Actor makes up to three recovery lookups after the listing-page response, with backoff. The first can share a request with source history; later description retries do not fetch history again. Text is accepted only when both property ID and listing ID match the original listing. Prices, listing IDs and other listing fields are never replaced by the recovery response. A different listing returned on a later run can represent a relisting or source update, rather than a scraping error.

Request allowance accounts for the selected content and bounded recovery. For example, 500 properties with details enabled receive an allowance of 1,850 requests; with details disabled and history enabled the allowance is 650. These are ceilings, not requests that will always be made. There is no request-limit field to configure. Explicit access denial, cooldowns or exhausted safety limits can stop recovery before three attempts. No retry can guarantee that the source will provide missing text.

Listing pages take priority: the Actor reserves estimated requests for later pages before using the remaining allowance on optional information. The internal ceiling is 2,000 source requests per run. Use batches of 500 properties or fewer with Continue when requesting details and history together. Restrictive filters, retries and source access can still reduce coverage.

If a history request fails or reaches its budget, the listing remains in the dataset with a `historyError`. A run that meets its minimum listing count and has no listing-search errors completes with warnings when history is incomplete. Check `SUMMARY.historyErrors`, `historyBudgetSkipped`, `historyComplete` and `warnings` for coverage. Reaching the automatic request allowance completes with a clear partial-coverage warning when at least one listing was collected; it is not classified as a source error. Actual listing-search errors or no matched listings still fail the run, retaining any partial results.

Descriptions that remain unavailable have `descriptionError` and `descriptionRecoveryAttempts`; recovered text has `descriptionRecoveredAt`. `sourceFetchedAt` still identifies the original listing-page fetch. `SUMMARY` includes recovered/missing description counts, recovery request counts and separate error-cause counts for descriptions and history. Logs report retries and batch coverage, and name causes such as HTTP 403 instead of reporting only a generic missing-history total. Missing descriptions remain empty; they are never invented. Photo URLs, coordinates, amenities and agent fields also depend on what the source supplies.

### Output structure

Each dataset row represents one matched property observation. Fields depend on the selected information groups and source availability; disabled or missing optional information remains empty.

| Data group | Main fields |
| --- | --- |
| Identity and links | `propertyId`, `listingId`, `source`, `country`, `url` (property detail link), `sourceSearchUrls` (originating search links) |
| Location | `address`, `city`, `state`, `postalCode`, `coordinates` |
| Price and status | `price`, `currency`, `status`, `isPending`, `isContingent`, `pricePerSquareFoot` |
| Property details | `bedrooms`, `bathrooms`, `squareFeet`, `lotSquareFeet`, `propertyType`, `yearBuilt`, `garageSpaces`, `stories` |
| Listing content | `title`, `description`, `tags`, `amenities`, `hoaFee`, `openHouses`, `photoUrl`, `photos`, `agents` |
| Description recovery | `descriptionRequested`, `descriptionRecoveryAttempts`, `descriptionRecoveredAt`, `descriptionError` |
| Dates and past sales | `listedAt`, `sourceUpdatedAt`, `sourceFetchedAt`, `lastSoldAt`, `lastSoldPrice` |
| Monitoring | `changeTypes`, `previousPrice`, `priceChange`, `priceChangePercent`, `firstSeenAt`, `observedAt`, `priceHistory` |
| Source history | `sourcePriceHistory`, `historyRequested`, `historyError` |

#### Example property record

The complete example below uses fictional property, agent and broker information. It shows an observation of a price reduction with all content options enabled. Actual fields depend on the source: missing scalar values are `null`, and unavailable lists are empty arrays. Optional descriptions, photos, agents and source history can be disabled in the input.

```json
{
  "propertyId": "1234567890",
  "listingId": "3000000001",
  "source": "realtor.com",
  "country": "US",
  "url": "https://www.realtor.com/realestateandhomes-detail/123-Example-St_Houston_TX_77002_M12345-67890",
  "address": "123 Example St",
  "city": "Houston",
  "state": "TX",
  "postalCode": "77002",
  "coordinates": {"lat": 29.76, "lon": -95.37},
  "price": 270000,
  "currency": "USD",
  "status": "for_sale",
  "isPending": false,
  "isContingent": false,
  "bedrooms": 3,
  "bathrooms": 2,
  "squareFeet": 1800,
  "lotSquareFeet": 6000,
  "propertyType": "single_family",
  "yearBuilt": 2005,
  "title": "Example home",
  "description": "Fictional three-bedroom home with a garage and fenced yard.",
  "descriptionRequested": true,
  "descriptionRecoveryAttempts": 0,
  "descriptionRecoveredAt": null,
  "descriptionError": null,
  "garageSpaces": 2,
  "stories": 1,
  "isNewConstruction": false,
  "mlsStatus": "Active",
  "lastSoldPrice": 250000,
  "lastSoldAt": "2020-06-15",
  "hoaFee": 50,
  "tags": ["single_story", "garage_2_or_more"],
  "amenities": [{"category": "Interior Features", "text": ["Example amenity"]}],
  "openHouses": [
    {
      "start_date": "2026-10-04T13:00:00",
      "end_date": "2026-10-04T15:00:00",
      "description": "Example open house",
      "time_zone": "America/Chicago"
    }
  ],
  "photos": ["https://example.com/property-photo.jpg"],
  "agents": [
    {
      "name": "Example Agent",
      "type": "seller",
      "email": "agent@example.com",
      "phones": [{"number": "+1-202-555-0142", "type": "Office"}],
      "broker": "Example Brokerage",
      "office": {"name": "Example Office", "href": "https://example.com/office"}
    }
  ],
  "sourcePriceHistory": [
    {"date": "2026-10-02", "event_name": "Price Changed", "price": 270000},
    {"date": "2026-10-01", "event_name": "Listed", "price": 300000}
  ],
  "historyRequested": true,
  "historyError": null,
  "pricePerSquareFoot": 150,
  "listedAt": "2026-10-01T12:00:00+00:00",
  "sourceUpdatedAt": "2026-10-02T11:00:00+00:00",
  "sourceFetchedAt": "2026-10-02T12:00:00+00:00",
  "photoUrl": "https://example.com/property-photo.jpg",
  "matchedMarkets": ["Houston, TX"],
  "sourceSearchUrls": ["https://www.realtor.com/realestateandhomes-search/Houston_TX"],
  "changeTypes": ["price_reduced"],
  "previousPrice": 300000,
  "priceChange": -30000,
  "priceChangePercent": -10,
  "firstSeenAt": "2026-10-01T12:00:00+00:00",
  "observedAt": "2026-10-02T12:00:00+00:00",
  "priceHistory": [
    {"price": 300000, "currency": "USD", "status": "for_sale", "observedAt": "2026-10-01T12:00:00+00:00"},
    {"price": 270000, "currency": "USD", "status": "for_sale", "observedAt": "2026-10-02T12:00:00+00:00"}
  ]
}
```

`url` links to the property detail page; `sourceSearchUrls` lists the originating search pages. `agents[].broker` is the broker name, and `agents[].office` contains the source-provided office name and link. Broker information is part of the optional `includeAgentDetails` group, which has no additional event fee. Only source-provided contacts are returned; missing contact information is not inferred.

`sourcePriceHistory` contains historical events supplied by Realtor.com. `priceHistory` contains observations recorded by this Actor across runs that share the same snapshot store. They are separate timelines. Photo fields contain links, not downloaded image files.

#### Run reports and continuation

The run's key-value store also contains:

- `SUMMARY`: coverage, request counts, listing pages attempted/fetched/reused, errors, checked records, charged records, exported rows and the actual saved-store ID.
- `RESUME_INFO`: store ID and link, continuation availability, completion, delivered count and any unresolved delivery warning.
- `NEXT_RUN_INPUT`: ready-made input for the next run, including the saved-store ID and session key.
- `RESUME.html`: readable resume instructions, also linked in **Output ? Resume instructions**.
- `OBSERVATIONS-000001`, `OBSERVATIONS-000002`, etc.: all processed observations, including unchanged records omitted from a change-only dataset. Their keys are listed in `SUMMARY.observationRecordKeys`.

These reports and observations belong to the current run's default key-value store. The monitoring snapshot and continuation checkpoint belong to the store identified by `snapshotStoreId`; on the first run these can be the same store. Later runs link back to the saved store. Snapshot and resume keys must differ and cannot use reserved names (`INPUT`, `OUTPUT`, `SUMMARY`, `RESUME_INFO`, `NEXT_RUN_INPUT`), `OBSERVATIONS-*`, or generated `*-ids-<64-character hash>` page keys.

### Continue with the next batch

Use `resumeMode: "continue"` when you want another batch of properties rather than another observation of the first batch. Leave `snapshotStoreId` empty for your first batch, or select an existing store. The Actor saves the actual store ID in its logs, `SUMMARY` and **Output → Resume instructions**. Copy **Next run input** into your next run to keep the same search, store and resume key.

For example, to collect 5,000 properties per run:

```json
{
  "markets": ["Houston, TX"],
  "maxRecords": 5000,
  "resumeMode": "continue",
  "resumeKey": "houston-sale-batches"
}
```

After the first run, open **Output ? Next run input** and copy its JSON into the next run's Input tab. It contains the actual `snapshotStoreId` and `resumeKey`. Keep **Batch continuation** set to **Continue** to request up to 5,000 additional properties. Previously delivered property IDs are skipped even if search pages overlap. The record limit can change between batches; internal request limits are recalculated automatically. More matching inventory must exist to fill the next batch.

Progress includes unfinished pages and price ranges, so a run can continue partway through a page without fetching it again. Buffered properties retain their original `sourceFetchedAt`; `observedAt` is when the observation is processed. Changing listings or source pagination can still cause unseen properties to be missed; continuation does not freeze the source inventory.

The logs show `Fetching Listing page 1`, `Fetched Listing page 1`, and subsequent page numbers, with the searched location and price partition when applicable. Source pages contain up to 200 listings, so these page numbers can differ from the website's visible page numbers. `SUMMARY.listingPagesFetched` counts successful page responses in this run; `listingPagesAttempted` includes failed attempts at the collection level. A saved-page buffer is logged separately and counted in `listingPagesReused`; it is not a new page fetch. Network retries remain part of `httpRequests`.

The automatically named first-batch store preserves progress until you delete it. If you use an existing unnamed store, name it in Apify Storage to keep it beyond your plan's retention period. A run with continuation **Off** saves a price snapshot but no pagination cursor; its output explains that switching to Continue starts a new session.

Check `SUMMARY.resumeComplete` and `SUMMARY.totalDelivered`. Once the session is complete, later continuation runs return no records and incur no record charges. To start another scan, explicitly use `restart` once, then return to `continue`. For recurring price checks, use `off`.

Changing search links, locations, filters, sorting or collected-field settings requires a separate `resumeKey` or an explicit restart. Do not run simultaneous writers against the same resume or snapshot keys. Resume state retains delivered IDs and grows with the session. Above 5,000 delivered IDs, the Actor stores history in checked, immutable pages so subsequent checkpoints reuse completed ID pages. Missing or corrupt pages stop automatic continuation; an explicit restart can replace that progress.

Progress is committed after delivered records are confirmed. Interrupted source requests resume from the last checkpoint; confirmed delivery receipts recover after a later checkpoint write fails. If interruption leaves a billing outcome unknown, automatic continuation stops for review instead of risking another charge. A restart can intentionally repeat records and charges. These safeguards do not provide an atomic transaction across Apify billing and storage.

### Recurring price monitoring

1. Run once with continuation off, then copy the store ID or **Next run input** from Output. Select that same store for later runs using `snapshotStoreId`. Name the store in Apify Storage to retain it beyond your plan's normal retention.
2. Keep `resumeMode` set to `off` and reuse the same `snapshotKey` and collection settings.
3. Run again manually or through an Apify schedule.
4. Set `changesOnly` to true if you want the default dataset to contain only observed changes.

Without a persistent store, separate cloud runs start separate baselines. Use separate snapshot keys for independent trackers and avoid overlapping runs that write to the same store and key.

| Change type | Meaning |
| --- | --- |
| `baseline` | First observation in a new tracker. |
| `newly_observed` | Property first observed after the tracker was initialized. |
| `price_reduced`, `price_increased` | Numeric price change within the same sale or rental category. |
| `status_changed` | Explicit status, pending or contingent change. |
| `listing_changed`, `listing_category_changed` | Changed listing ID or sale/rental category. |
| `details_changed`, `unchanged` | Other tracked details changed or remained the same. |

`priceHistory` begins when this tracker first observes the property. `sourcePriceHistory` is separate historical information provided by Realtor.com. A first observation does not establish when a property was listed, and disappearance from search does not establish a sale or delisting. Changing collection options can produce a one-time details change.

Observed history is bounded by `maxHistoryEntries`. The snapshot retains newly observed properties, so long-running trackers should account for storage growth.

### Proxy

To use Apify Proxy:

```json
{
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

Every enabled run starts with the account's default datacenter pool. Residential is initialized only after a datacenter HTTP 403 access denial or exhausted connection retries. Selecting residential in the input form or API cannot force residential-first routing: user-selected proxy groups and proxy country are ignored. Both pools require account access. Custom proxy URLs are unsupported; property searches remain US-only.

Apify's Free plan supports proxy use inside the Apify platform. Using Apify Proxy from a local computer requires external proxy access, which is a paid-plan feature. A valid API token does not grant that feature. Run the Actor in Apify to test proxies on the Free plan. See [Apify's connection documentation](https://docs.apify.com/proxy).

HTTP 401 authentication errors, source rate limits and cooldowns, empty searches, server errors and invalid responses do not activate residential fallback. Residential failures stop collection rather than switching pools repeatedly. Datacenter and residential requests share the same request budget and pacing.

Residential fallback has a shared application traffic cap: the smaller of the internal 100 MB ceiling and **2 MB + 0.02 MB per budget-allowed property**. A 100-record run receives at most 4 MB, a 1,000-record run 22 MB, and a 10,000-record run 100 MB. Request bodies, streamed response bytes and an 8 KB allowance per attempt count toward the cap, including retries and optional source history. The run stops with partial output when the allowance is exhausted; saved continuation progress can be used in a later run.

`SUMMARY` reports the proxy mode, fallback reason, residential bytes accounted, effective allowance and whether the cap was reached. This is an application allowance, not an exact invoice limit: Apify's metered bytes can differ because of buffering, concurrent requests and protocol overhead. Photo fields contain URLs; image files are not downloaded or stored.

### Coverage and troubleshooting

Locations and links run in input order; nationwide searches use state order. Record caps produce samples rather than complete market inventories. Default ascending-price sorting favors lower-priced properties. Sorting applies within individual searches; larger searches divided into counties or price ranges may not be globally ordered by date.

The collector treats 10,000 results as the per-query ceiling. Large state searches can be divided into Census county searches; large county or city searches use price ranges and deduplication where possible. Continuation retains these pending searches across runs. Geographic searches can overlap, and restrictive filters or dense price ranges can still prevent the requested count from being reached. Narrow your location, apply source-supported filters or use smaller continued batches. The Actor does not guarantee every listing on Realtor.com or a fixed nationwide inventory count.

If a run fails, review `SUMMARY` and any collected output. Actual listing-search errors or no matched listings fail the run. Reaching an internal request allowance produces a partial-coverage warning when listings were collected. Optional source-history failures produce warnings and per-row `historyError` values; successfully collected listing records can still be billed. Later failures can leave useful partial results. An empty change-only dataset can also be a successful run with no observed changes—check the observation records and summary.

With continuation off, interrupted runs may retain earlier delivered records without completing the snapshot update; another run creates new observations and can repeat earlier records. Continuation mode uses the saved progress and delivery safeguards described above. Source availability and the unofficial source interface may change.

# Actor input Schema

## `startUrls` (type: `array`):

Paste Realtor.com search/results links, one per line. The Actor collects their next pages automatically, up to your property limit. Leave empty to search by location below or across the US. Property detail links are returned in the output; they are not accepted here.

## `maxRecords` (type: `integer`):

Maximum unique properties to collect in this run. Default 100. Request allowance, pacing and traffic caps are managed automatically. Leave location fields empty for a nationwide search. Base rates: $0.99 per 1,000 properties; delivered details +$0.25; successful non-empty history +$1. Silver receives 10% off; Gold and higher tiers receive 20% off. Your spending limit can lower this count.

## `listingTypes` (type: `array`):

Choose sale, rental or sold listings when searching by location. Pasted links determine their own listing category.

## `markets` (type: `array`):

Type one location per entry, including the state for cities and counties: Houston, TX or Harris County, TX. ZIP codes such as 77001 also work. Leave empty for a nationwide search or use States below. Choose listing links OR locations. An explicit location/state mismatch is rejected before scraping.

## `states` (type: `array`):

Leave empty for all states. Select one or more to narrow a nationwide search; also filters properties returned by your links or cities. A city, county or link that explicitly names a different state is rejected before scraping. For example, Houston, TX requires Texas or no state filter.

## `sortBy` (type: `string`):

Source sort within searches. Capped price-partitioned searches are samples, not complete market inventories.

## `minPrice` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxPrice` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minBedrooms` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxBedrooms` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minBathrooms` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxBathrooms` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minSquareFeet` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxSquareFeet` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minLotSquareFeet` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxLotSquareFeet` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minYearBuilt` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxYearBuilt` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minGarageSpaces` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxGarageSpaces` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `minHoaFee` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `maxHoaFee` (type: `number`):

Optional inclusive bound. Price and HOA use USD; floor/lot size use square feet. Missing values do not match requested bounds.

## `amenities` (type: `array`):

Optional filter. Text is case-insensitive. All amenities/keywords must match; any excluded keyword rejects the listing. States use two-letter codes; ZIP codes remain strings.

## `cities` (type: `array`):

Optional filter. Text is case-insensitive. All amenities/keywords must match; any excluded keyword rejects the listing. States use two-letter codes; ZIP codes remain strings.

## `excludeKeywords` (type: `array`):

Optional filter. Text is case-insensitive. All amenities/keywords must match; any excluded keyword rejects the listing. States use two-letter codes; ZIP codes remain strings.

## `keywords` (type: `array`):

Optional filter. Text is case-insensitive. All amenities/keywords must match; any excluded keyword rejects the listing. States use two-letter codes; ZIP codes remain strings.

## `postalCodes` (type: `array`):

Optional filter. Text is case-insensitive. All amenities/keywords must match; any excluded keyword rejects the listing. States use two-letter codes; ZIP codes remain strings.

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

Optional property types: apartment, condo, condos, farm, land, mobile, multi_family, other, single_family, townhomes, townhouse.

## `contingent` (type: `string`):

Any leaves this criterion unrestricted. Unknown source flags do not match yes or no.

## `hasPhotos` (type: `string`):

Any leaves this criterion unrestricted. Unknown source flags do not match yes or no.

## `newConstruction` (type: `string`):

Any leaves this criterion unrestricted. Unknown source flags do not match yes or no.

## `pending` (type: `string`):

Any leaves this criterion unrestricted. Unknown source flags do not match yes or no.

## `listedAfter` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `listedBefore` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `soldAfter` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `soldBefore` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `updatedAfter` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `updatedBefore` (type: `string`):

Optional inclusive ISO date/datetime, e.g. 2026-10-01T00:00:00Z. A date without time is midnight UTC.

## `boundingBox` (type: `object`):

Optional JSON with south, north, west, east coordinates. Missing coordinates do not match.

## `foreclosure` (type: `string`):

Passed to the source search as a foreclosure criterion. The source determines classification; no foreclosure flag is inferred in output.

## `includeDetails` (type: `boolean`):

When paid pricing is active, adds $0.00025 per property only if at least one description, amenity, HOA fee or open-house entry is delivered. Partially populated groups can qualify. Missing descriptions get up to three recovery lookups, subject to source access and safety limits. Only matching property and listing IDs are accepted; recovery shares the first lookup with history when possible. Retries are not extra charge events. Silver receives 10% off this rate; Gold and higher tiers receive 20% off.

## `includePhotos` (type: `boolean`):

Included in the base record price. Returns links only; image files are not downloaded.

## `includeAgentDetails` (type: `boolean`):

Included in the base record price when selected and available from the source.

## `includeHistory` (type: `boolean`):

When paid pricing is active, adds $0.001 per property only after successfully returning non-empty source history. Failed or empty histories have no add-on. Usually adds one request per property; the request allowance adjusts automatically. Source access and safety limits can reduce coverage. Silver receives 10% off this rate; Gold and higher tiers receive 20% off.

## `maxPhotos` (type: `integer`):

Bounds retained photos or history events per property. Older observed history may be trimmed; firstSeenAt is retained.

## `maxHistoryEntries` (type: `integer`):

Bounds retained photos or history events per property. Older observed history may be trimmed; firstSeenAt is retained.

## `resumeMode` (type: `string`):

Off starts each search again for monitoring. Continue starts or resumes a saved session, skipping delivered IDs. For your first batch, leave the saved store empty: a progress store is saved automatically. Copy its ID or next-run input from Output → Resume instructions for the next batch. Restart replaces the session with a new scan; records can be billed again. Switch back to Continue after restarting.

## `snapshotStoreId` (type: `string`):

First run: leave empty. With Continue enabled, the Actor saves progress in a named store automatically and shows its ID in the logs and Output → Resume instructions. Later runs: select that same store or paste the ready-made next-run input. Reuse it for price history too.

## `changesOnly` (type: `boolean`):

Only exports observed changes to the dataset. Billing still counts each unique matched property checked, including unchanged records; all observations remain in run storage.

## `resumeKey` (type: `string`):

Saved progress in your selected persistent store. Reuse for the next batch; use a separate key for each search. Must differ from snapshotKey. Reserved names such as INPUT, SUMMARY, RESUME_INFO, NEXT_RUN_INPUT and OBSERVATIONS-\* are not allowed. Do not run simultaneous writers.

## `snapshotKey` (type: `string`):

Monitoring snapshot in your saved store. Use a separate key for each tracker, different from resumeKey. Reserved output/input names and OBSERVATIONS-\* or resume ID page keys are not allowed.

## `country` (type: `string`):

US listings only.

## `proxyConfiguration` (type: `object`):

Enable Apify Proxy if direct access fails. Enabled runs always try datacenter first. Residential is used only after datacenter access denial or failed connection retries, with a traffic cap. Your group/country selections cannot override this policy. Requires proxy access; custom proxy URLs are unsupported.

## Actor input object example

```json
{
  "maxRecords": 100,
  "listingTypes": [
    "for_sale"
  ],
  "sortBy": "price_asc",
  "contingent": "any",
  "hasPhotos": "any",
  "newConstruction": "any",
  "pending": "any",
  "foreclosure": "any",
  "includeDetails": false,
  "includePhotos": false,
  "includeAgentDetails": false,
  "includeHistory": false,
  "maxPhotos": 25,
  "maxHistoryEntries": 100,
  "resumeMode": "off",
  "changesOnly": false,
  "resumeKey": "us-property-resume",
  "snapshotKey": "us-property-prices",
  "country": "US",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `properties` (type: `string`):

No description

## `resumeInstructions` (type: `string`):

No description

## `nextRunInput` (type: `string`):

No description

## `savedProgress` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("negligible_endive/realtor-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 = { "proxyConfiguration": { "useApifyProxy": False } }

# Run the Actor and wait for it to finish
run = client.actor("negligible_endive/realtor-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 '{
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call negligible_endive/realtor-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,negligible_endive/realtor-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/AcjvsRh0od8OEVdao/builds/dtk8bqAsj6VEWeQgv/openapi.json
