What Can You Learn from an Off-Market Zillow Property?
A field-by-field checklist for researching a known home that is not listed: what the estimates, sale history, facts and leftover listing details can tell you, and what they cannot.
Start with a home you already know about
Most homes are not for sale on any given day, and Zillow still keeps a page for many of them. If you already have an address or a Zillow link for such a home, a lookup returns what that page shows: Zillow's estimates, past sales and listings, tax years, physical facts and sometimes details left over from the last listing.
That makes an off-market lookup useful for research on a property you have a reason to study, such as a neighbor's home in a comparison you are assembling yourself, a property a client asked about, or a home in your own portfolio. It does not find off-market homes for you. The API looks up properties you supply; it has no search across homes that are not listed, and it returns no owner names, owner contact details or signals that an owner wants to sell.
Recognize an off-market response
An unlisted home usually comes back with homeStatus OTHER, sometimes OFF_MARKET, and statusText Off market. Check this before reading any price field, because it changes what the other fields mean.
price is normally null for these homes. When the source page fills its price slot with the Zestimate for an unlisted home, the API returns null instead, so you never see an estimate disguised as an asking price. A null price here is the correct answer, not a gap to fill.
Status can also change between your lookup and the moment someone reads your notes. A home that was off market last month may be listed today, and a home that looked listed may have been withdrawn. Keep the collection time with the review sheet, and look the home up again before any decision that depends on whether it is for sale.
The field-by-field checklist
Work through the fields in this order. Each row says what the field can tell you about an off-market home and the limit you should write next to it.
| Field | What it tells you | Limit |
|---|---|---|
| homeStatus, statusText | The home is not listed on the source | Not a statement about the owner's plans |
| zestimate, rentZestimate | Zillow's current estimates, when shown | Estimates, not offers or appraisals. Can be null |
| calculated.last_sale_price and last_sale_date | The most recent recorded sale | Null price when the sale was not disclosed |
| lastSoldPrice, dateSold | The source's last sale fields | Prefer the dated Sold event when they differ |
| priceHistory | Past listings, removals, rentals and sales | Only events the source shows; gaps are normal |
| taxHistory, taxAnnualAmount | Tax paid and assessed value by year | Assessed value is not market value |
| beds, baths, livingArea, lotSize, yearBuilt, homeType | Physical facts as shown | May predate renovations or additions |
| parcelId, schools | Parcel number and nearby schools | Use the parcel number with the county record |
| description, photos, agentName, brokerName | Content from a past listing, if any | Stale by definition; not current contacts |
| daysOnZillow | A day count from the source | Not days on market; calculated.days_on_market is null |
Leftover listing details are history, not news
In one recorded test response for an off-market home, the description, photos and listing agent came from past listings, and the newest event in priceHistory was a Listing removed entry dated more than a year before the lookup. Nothing in those fields was wrong, but none of it described the home's current state.
Read the last Listing removed or Sold event in priceHistory and treat everything listing-shaped as belonging to that moment. An agent named on an old listing represented a past seller or landlord. They are not the owner, and the response gives you no basis to contact them about the home today. Photos from an old listing remain the photographer's or broker's, and the data-rights page explains why we return photo links rather than copies.
Estimates and change since the last sale
For an unlisted home, the calculated change_since_last_sale_pct compares the most recent sale with the Zestimate, and change_since_last_sale_basis says zestimate. That is a comparison of a past sale with Zillow's current estimate. It is useful for context and should be labeled exactly that way, not as appreciation the owner could realize.
If the Zestimate is null, the change is null too. The null Zestimate guide explains why estimates go missing and how to show that without inventing a number.
Generate the review sheet
The script reads one saved response and prints each checklist item with its caveat attached, so the limits travel with the values when you paste the sheet into a report. It warns if the home turns out not to be off market, finds the latest Listing removed event, and prints unavailable for missing values instead of zero.
Save the response first. The lookup costs the same as any other: one credit for a successful live lookup, free for a repeat inside the cache window and free when it fails.
"""off_market_review.py: a field-by-field review sheet for one known, off-market home."""
import json, sys
NOT_LISTED = {"OTHER", "OFF_MARKET"}
def latest(events, label):
hits = [e for e in events or [] if (e.get("event") or "").lower() == label]
return max(hits, key=lambda e: e.get("date") or "", default=None)
def review(body):
d, meta = body["data"], body["meta"]
calc = d.get("calculated") or {}
events = d.get("priceHistory") or []
out = []
def add(item, value, caveat):
out.append((item, "unavailable" if value is None else value, caveat))
if d.get("homeStatus") in NOT_LISTED:
add("Status", d.get("statusText") or d.get("homeStatus"),
"Not listed on the source page. Says nothing about whether the owner would sell.")
else:
add("Status", d.get("statusText") or d.get("homeStatus"),
"WARNING: this home is not off market; use a listing review instead.")
add("Current asking price", d.get("price"), "Normally unavailable for an unlisted home.")
add("Zestimate", d.get("zestimate"), "Zillow's estimate, not an offer or appraisal.")
add("Rent Zestimate", d.get("rentZestimate"), "Zillow's monthly rent estimate.")
add("Last sale", calc.get("last_sale_price"),
f"Most recent Sold event, dated {calc.get('last_sale_date') or 'unknown'}; null if undisclosed.")
removed = latest(events, "listing removed")
add("Last listing removed", removed and removed.get("date"),
"The most recent listing ended here. Its text and photos may still appear.")
fact = lambda k: "?" if d.get(k) is None else d.get(k)
add("Facts", f"{fact('beds')} bd / {fact('baths')} ba / {fact('livingArea')} sqft / built {fact('yearBuilt')}",
"As shown by the source; may predate renovations.")
add("Tax history years", len(d.get("taxHistory") or []), "Assessment, not market value.")
add("Listing agent on record", d.get("agentName"),
"From a past listing if present. Not the owner, and not a current contact for this home.")
add("Days on Zillow", d.get("daysOnZillow"),
"For an unlisted home this is not days on market; calculated.days_on_market is null.")
add("Collected", meta.get("fetched_at"), "Re-check the source page before acting.")
return out
if __name__ == "__main__":
body = json.load(open(sys.argv[1], encoding="utf-8"))
print(body["data"].get("address"), "|", body["data"].get("detailUrl"))
for item, value, caveat in review(body):
print(f"- {item}: {value}\n {caveat}")
# Save one response, then review it
curl --get "https://api.propertiesapi.com/v1/zillow/property" \
--header "x-api-key: $PROPERTIESAPI_KEY" \
--data-urlencode "address=$PROPERTY_ADDRESS" \
--max-time 130 -o home.json
python off_market_review.py home.jsonWhat not to infer
Off-market data invites guesses, so it helps to write the forbidden inferences down. A rising Zestimate does not mean the owner will sell. A long gap since the last sale does not mean a home is ready to list. A removed listing does not mean it failed to sell for a reason you can name. An old agent record is not a lead.
What you can say is narrower and more useful: what the home is, what it last sold for if that was disclosed, how its taxes and Zillow's estimates look today, and when you collected those facts.
- Do not present the home as available or likely to sell.
- Do not treat past listing contacts as owner contacts.
- Do not fill a null price with the Zestimate.
- Keep the collection time and the source link with every saved review.
Sources and documentation
Product details checked against the linked documentation on October 22, 2026. Code and sample inputs are illustrative unless stated otherwise.
Written by PropertiesAPI, an independent property data service. We are not affiliated with Zillow. Source data may be incomplete or change over time.