Motivated Seller Score — Listing Motivation Rank
Pricing
from $3.50 / 1,000 motivated listings
Motivated Seller Score — Listing Motivation Rank
Motivated seller score for property listings you already have. Same rows, plus a 0-100 score from keywords and days on market. Listing motivation rank from 200 rows. Paste JSON or a dataset ID. No portal scrape and no phones.
Pricing
from $3.50 / 1,000 motivated listings
Rating
0.0
(0)
Developer
Noah Adler
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
17 days ago
Last modified
Categories
Share
Motivated seller score for property listings you already have. Paste JSON, or pass an Apify datasetId. Each output row is the same listing plus a motivated seller score from 0 to 100. From 200 rows, the run also adds a listing motivation rank.
This Actor does not scrape Zillow, Idealista, Fotocasa, SeLoger, or any other portal. It does not return phones, emails, or owner names. With redactContactsInText left on (the default), phones and emails inside the description are replaced with [redacted].
What you get
| Field | When |
|---|---|
motivationScore | Always. Integer 0–100. |
motivationFactors | Always. Short reasons. |
keywordHits | Always. Empty when nothing matched. |
daysOnMarket | From publishedAt, firstPublicationDate, daysOnPortal, or another listed date. null if there is no date. |
scoreVersion | Always "0.2". |
rarityApplied | false under 200 rows. true from 200 rows up. |
motivationPercentile, relativeTier | null under 200 rows. From 200 rows, a rank inside this run. |
specialCase | true when a zero-point case phrase matched (subasta, asta, nuda propiedad, …). |
detectedLanguage | Hint only (es, fr, en, de, it). Every dictionary still runs. |
priceDropped, priceCutPct | Only when this row brings previousPrice, priceHistory, or priceDropped: true. |
previousPriceObserved, priceCutPctObserved, relisted, firstSeenAt, daysObserved | Only when previousDatasetId was set. |
relativeTier is "top" at or above the 95th percentile of this run, "high" from the 80th up to that line, and "normal" below the 80th. It is not an absolute motivated-seller threshold.
How the score is calculated
Deterministic. No LLM.
- Base weight 25:
urge,herencia,estate sale,as-is,must sell,foreclosure,venta urgente,liquidación,Nachlass,Zwangsversteigerung, and the other distress phrases in the dictionary. - Base weight 12:
por traslado,por divorcio. - Base weight 8:
a reformar,para reformar,à saisir. - Base weight 5:
oportunidad,negociable,coup de coeur,price reduced. A weak hit alone is marketing language, not distress. - Weight 0,
specialCaseonly:subasta,procedente de banco,procedente de entidad,nuda propiedad,asta. - A negation within three tokens (
no,sin,nicht,non,pas de,no hay) cancels that phrase. - Days on market ≥ 60: +15. ≥ 120: +25 more (both apply). Cap 100.
- Price cut on this row: +20, only from
previousPrice,oldPrice,priceBefore,originalPrice,priceHistory, orpriceDropped: true. - Relist versus
previousDatasetId: +15.
From 200 rows up, rarity reweights motivationScore even when you pass no new inputs. Each phrase weight is multiplied by clamp(log(1/df) / log(100), 0.1, 1.5), where df is the share of rows in this run that contain the phrase. A phrase everyone uses (high df) falls near the floor, about 0 to 1 point instead of 5. Under 200 rows, rarity is off and oportunidad stays at 5.
On a normal Madrid sample, strong distress phrases are rare. Below 200 rows the score mostly moves with days on market and weak words such as oportunidad. This is not a probate detector.
No description (some Leboncoin list feeds): keyword hits stay empty unless the title itself contains a phrase. Days on market still score.
Works with datasets from
Pass datasetId from a dataset you already stored. Examples, none of which include phone numbers:
fotocasa-spain-property-scraperseloger-scraperleboncoin-immobilier(often title and date only, no description)- a Zillow or Idealista export you already downloaded and saved as an Apify dataset
You can also paste listings JSON. Contact fields are dropped either way.
Weekly schedule
Run once a week. Point datasetId at this week's dataset and previousDatasetId at last week's dataset:
{"datasetId": "DATASET_ID_THIS_WEEK","previousDatasetId": "DATASET_ID_LAST_WEEK","maxItems": 5000}
A fingerprint that matches exactly one older row with a different listingId is relisted. The same listingId with a newer publishedAt is relisted as well. Day points then use max(daysObserved, daysOnMarket).
SUMMARY.notInThisFile counts previous rows that are absent from this input. It does not mean those listings sold. The count changes if filters, area, or maxItems change.
If previousDatasetId cannot be read, the run returns an error row. It does not pretend the diff was empty.
Input
listingsordatasetId(one of them).maxItems: default 100, max 5000.asOfDate: ISO date for days on market. Default is the run time in UTC.redactContactsInText: defaulttrue.customKeywords:[{ "phrase": "vendido por divorcio", "weight": 12 }]. Weight must be an integer from 1 to 25. Anything else stops the run.previousDatasetId: optional.
Pricing
Pay per enriched listing: $0.005. No residential proxy.
Limitations
- Not a skip-trace product and not a portal scraper.
priceDroppedmeans the previous price was already on the row. A drop seen only by comparingpreviousDatasetIdispriceCutPctObserved, and it does not changepriceDropped.relativeTiercompares rows inside the run you just scored.