Live test · Austin, Texas
How I built a change-only Austin rental feed
Austin rental monitoring becomes noisy when every scheduled run sends the same capped search window. This test stores a baseline in the customer's Apify account, compares each listing by stable ID, and emits a row only when a listing is new or its tracked details change. It is meant for property managers, relocation teams, investors, and agencies that need a small filtered feed rather than another daily spreadsheet full of duplicates.
I tested the workflow against live Zumper apartment data on August 20, 2026. The first monitoring run returned three current listings. An identical repeat returned zero. A separate seed-only monitor stored the same three listings without sending an initial alert. All six cloud runs finished without warnings or errors.
No form backend, cookies, tracking pixels, or analytics. The email code identifies this case study only after you send the draft.
The Austin rental monitoring test
The verification search used Austin apartments, at least one bedroom, an available unit at or below $3,000 per month, no photos, and a three-listing cap. The small cap kept the test cheap and made duplicate behavior easy to inspect. It was not intended to represent the full Austin rental market.
{
"mode": "search",
"location": "austin-tx",
"propertyType": "apartments-for-rent",
"maxPrice": 3000,
"minBeds": 1,
"airbnbFriendly": false,
"maxListings": 3,
"includePhotos": false,
"useApifyProxy": true,
"onlyChanges": true,
"monitorId": "proof-austin-20260820-195358",
"firstRunMode": "emitAll",
"resetState": false
}
The downloadable n8n example raises maxListings to 25 and uses firstRunMode: "seedOnly" so setup does not email the existing backlog.
Real rows from the corrected filter route
These rows came from run iV5m9F3ukRZHOcDhw at 19:54 UTC. The original query-string filter was not reliable, so build 1.1.18 moved bedroom and rent filters into Zumper's supported route format. Each returned row passed beds_min ≥ 1 and price_min ≤ 3000.
| Listing ID | Address | Observed rent | Beds / baths | Lead score | Change |
|---|---|---|---|---|---|
| 63223586 | 3515 Manor Rd, Austin, TX 78723 | $702–$2,079 | 1–4 / 1–2 | 59 | new |
| 62077402 | 2921 E 17th St, Austin, TX 78702 | $1,590 | 2 / 2 | 69 | new |
| 62884748 | 2450 Wickersham Ln, Austin, TX 78741 | $1,749–$1,840 | 1–2 / 1–2 | 74 | new |
Observed values can change. Building records may cover several available unit types, which is why some rows contain ranges. Open the sample as JSON.
How duplicate suppression works
1. Stable identity
listing_id is the primary identity. A canonical source URL is retained for delivery and inspection.
2. Tracked snapshot
The fingerprint covers rent range, bedroom and bathroom range, and the canonical listing URL.
3. Caller-owned state
Each monitorId gets a separate record in the named zumper-rental-monitor-state store.
4. Change-only output
An unchanged repeat emits nothing. New or changed rows carry first-seen, detected, and prior-price fields.
The store is created in the account running the Actor. The state is retained for 90 days and capped at 5,000 listing fingerprints per monitor. A reset clears only the selected monitorId, so separate Austin and Dallas feeds do not erase one another.
What the final cloud matrix proved
| Scenario | Run ID | Rows | Result |
|---|---|---|---|
| Ordinary Actor mode | JAZuc99yGE9mIVOV6 | 3 | Backward-compatible output; no monitor metadata |
| Monitoring baseline | iV5m9F3ukRZHOcDhw | 3 | Three new rows stored |
| Identical repeat | HZC2nvz82ZGtxSTga | 0 | No duplicate delivery |
| Scoped reset | LuRhVsPsGHM4cS2BK | 3 | Selected monitor emitted a fresh baseline |
| Seed-only baseline | NPCuk3uvRCCGrOtjy | 0 | Three entries stored without an alert |
| Seed-only repeat | 439cb2hHdoP6aQCaF | 0 | State remained stable |
The short repeat window did not contain a real rent change. Price-change behavior is covered by the local test suite, which checks the prior rent, amount, percentage, and failed-write rollback. I do not present that controlled test as a live market event.
From source to alert
The public n8n workflow calls the Actor each morning, reads its dataset, stops when the dataset is empty, appends changed rows to Google Sheets, and then sends a digest. Credentials belong in n8n credential objects, not inside the workflow JSON. The template contains no Apify token, webhook, mail password, or Google credential.
Limits I keep in the product
No removal claim from a capped search. A listing can disappear because the portal reordered the result window. The feed reports new, price_changed, and details_changed; it does not call an absent row “removed.”
Source access is tested before a quote. A working Austin run does not prove that every portal, country, or filter is available. Residential proxy or unblocker costs are scoped separately.
Price ranges need context. A building can expose several unit types in one row. The feed preserves the observed minimum and maximum rather than pretending each building has one rent.
State depends on the monitor ID. Distinct searches need distinct IDs. Reusing one ID for different filters replaces that feed's comparison baseline.
Self-serve or managed
You can run the Actor and n8n template in your own accounts. A managed package is for a named source set, agreed schema, schedule, delivery target, monitoring, and source repairs.
One proven source
Real-estate pilot
$750 setup + $350/month
- One market and filter set
- Up to 5,000 delivered rows per month
- Daily delivery by default
- Acceptance against a live source sample
Up to three proven sources
Real-estate Growth feed
$1,750 setup + $950/month
- Up to three source and market combinations
- Normalized change schema
- Daily or agreed scheduled delivery
- Source monitoring and bounded maintenance
Apify platform usage, Actor charges, residential proxies, unblockers, and third-party APIs are separate unless a written quote includes a cap. A monthly service starts only after the sample and schema pass the agreed acceptance check.