Israel Property Market Signals — Yad2 & Madlan Analytics avatar

Israel Property Market Signals — Yad2 & Madlan Analytics

Under maintenance

Pricing

Pay per usage

Go to Apify Store
Israel Property Market Signals — Yad2 & Madlan Analytics

Israel Property Market Signals — Yad2 & Madlan Analytics

Under maintenance

Turn Israeli property listings into market intelligence: days on market, price-drop history, motivated-seller scores and per-neighbourhood absorption. Works with any listings scraper.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Amit Arie

Amit Arie

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Turn a pile of Israeli property listings into market intelligence. Point this Actor at the dataset from any Yad2, Madlan or Homeless.co.il scraper and get back what no single scrape can tell you: how long each flat has been on the market, how often and how deeply its price has been cut, which sellers look ready to negotiate, and how fast inventory is clearing in each neighbourhood.

Sold prices in Israel are already free from the Tax Authority. Asking prices are on Yad2. Nobody publishes what happens in between — and that gap is where negotiating leverage lives.

What you get that a listings scraper cannot give you

A scraper photographs the market. This Actor watches it.

QuestionIn a scrape?Here?
What is this flat asking?YesYes
How long has it been sitting?NoYes — from run 1
Has the seller cut the price, how often, how far?NoYes
Was it pulled and re-listed to reset its age?NoYes
Which sellers are ready to negotiate?NoYes
Is this priced above or below its own neighbourhood?NoYes — from run 1
How fast is this neighbourhood clearing?NoYes
What is the median ₪/m² here, and the agent/private split?NoYes — from run 1

The rows marked "from run 1" work on your very first run. The rest appear as runs accumulate, because no listing carries its own price history — cuts can only be seen by watching.

How to use it

1. Get listings. Run any Israeli property scraper from Apify Store and let it finish.

2. Run this Actor. Choose that run's dataset from the Listings dataset picker, set a Tracker ID for the market you are following (tlv-sale, haifa-rent — one per market, always the same value), and run. The Actor is granted read access to just that one dataset and nothing else in your account.

3. Schedule it daily. Console → Schedules, same Tracker ID every time. This is the important step: the Actor's whole value is accumulated observation.

4. Read the first run straight away. Days on market and the neighbourhood comparisons are meaningful immediately; price-cut history builds from run 2. See below.

You can also paste listings straight into the listings field as JSON, which is the quickest way to try it.

What the first run gives you

The first run is useful immediately. Two whole families of signal need no history at all:

  • Real days on market, wherever your source stamps listings with a publication date — which Yad2 and Madlan both do. A flat listed 284 days ago reports 284 days on its very first run, not 0.
  • Every neighbourhood comparison: median ₪/m², how each listing prices against its own area, which listings are sitting far longer than their neighbours, the agent/private split, and the inventory mix. These come from comparing listings to each other inside one snapshot.

So run 1 already ranks sellers by motivation and flags listings priced below their area median:

score days source vs area stale
43 284 published -7.3% false
41 208 published -5.0% false
35 131 published +4.1% false
25 74 published 0.0% false

What genuinely needs time is price-change history — no listing carries its own past prices, so cuts can only be seen by watching. Those begin at run 2 and compound from there.

AfterWhat is added
Run 1Days on market, area comparisons, staleness, motivated-seller ranking
Run 2+Price cuts, depth and frequency of cuts, delistings
~30 daysAbsorption rates and median-days figures stabilise

Already have archived scrapes? Use Backfill: date this snapshot was taken and replay them oldest first. The Actor folds each in as of its own date, so months of price history can be reconstructed in minutes rather than waited for.

If your source has no publication dates, daysOnMarket starts from today and is labelled daysOnMarketSource: "observed" so you always know which you are looking at. Everything else still works.

Output

Four record types in one dataset, tagged by recordType, each with its own saved view.

listing — one row per active listing:

{
"recordType": "listing",
"listingId": "yad2:8842011",
"motivatedSellerScore": 64,
"daysOnMarket": 284,
"daysOnMarketSource": "published",
"daysObserved": 55,
"listedAt": "2025-11-30T00:00:00.000Z",
"observedFrom": "2026-07-16T09:00:00.000Z",
"pricePerSqmVsAreaMedianPct": -7.3,
"areaMedianPricePerSqm": 17590,
"belowAreaMedianPricePerSqm": true,
"isStaleForArea": false,
"daysOnMarketVsAreaMedian": 105,
"priceDrops": 2,
"totalChangePct": -8.34,
"largestDropPct": -4.14,
"daysSinceLastPriceChange": 0,
"price": 1549000,
"firstObservedPrice": 1690000,
"pricePerSqm": 16305,
"rooms": 4, "sqm": 95, "floor": 2,
"city": "חיפה", "neighborhood": "הדר הכרמל", "street": "הרצליה",
"isAgent": false, "agentInferred": false,
"isNew": false, "isRelisted": false,
"url": "https://www.yad2.co.il/item/7710334"
}

area — one row per neighbourhood: medianPricePerSqm, medianDaysOnMarket, listingsWithPriceDropPct, absorptionRatePct, agentSharePct, newThisRun, delistedThisRun.

delisted — listings that vanished this run, with their last asking price and how long they survived.

run_summary — counts for the run, so a scheduled job is easy to monitor.

The motivated-seller score

A 0-100 blend of time on market, how far the price has fallen, and how many separate cuts there have been. A listing at 90 days with three cuts totalling 9% scores far above one at 90 days that has never moved — patience is not the same as desperation.

The weights (staleness 45, price-drop depth 40, number of cuts 15) are exposed in the input so you can retune them for your own market, and Dry run lets you experiment without disturbing your history.

Pricing

Pay per event, so your bill is predictable and you only pay for rows you actually receive:

  • listing-signal — per listing row returned
  • area-report — per neighbourhood row returned

Two things keep the cost down. Filtering with Minimum motivated-seller score bills you only for the rows above your threshold, not everything analysed. And this Actor never calls another Actor on your behalf, so nothing is charged twice and there is no hidden upstream bill — you pay for the scraper you chose, separately and visibly, and for this analysis.

Runs are light: the work is arithmetic over records you already have, not browsing.

Works with any listing source

Field names are mapped, not assumed, and the mapping is verified against a real Yad2 scraper payload rather than assumed: listingId / id / adNumber, price / priceIls, areaSqm / squareMeters / sqm, neighbourhood / neighborhood, publishedAt / createdAt. Where a source gives both a Hebrew and an English city name, the Hebrew one is used, so area keys stay in one language.

Hebrew values carrying currency symbols and מ״ר are parsed, dates in dd/mm/yyyy are read day-first as Israeli sources write them, and the CSV export carries a BOM so Hebrew opens correctly in Excel.

Minimum per record: an identifier and a price. Everything else improves the output when present and is handled gracefully when absent — including a stated hasAgent or adType, which is trusted over guessing from description text.

Attributes passed through when your source provides them: hasSecureRoom (ממ"ד), hasElevator, hasBalcony, hasParking, isRoommates, isExclusive, propertyType. An attribute the source doesn't state is absent from the row rather than reported as false, so "no lift" and "unknown" never look the same.

Honest limits

Read these before relying on the numbers. They are properties of the problem, not defects, and knowing them makes the output more useful.

  • daysOnMarket prefers the listing's own publication date and falls back to how long this Actor has watched. daysOnMarketSource tells you which, and daysObserved always carries the watched figure. Where a source gives no date, the age starts from your first run and becomes accurate as runs accumulate.
  • Price-change history only exists from run 2 onward. No listing carries its past prices, so cuts have to be observed. Backfill archived snapshots if you have them.
  • Some listings are years old and are not really for sale. Real portal data contains ads nobody ever removed — publication dates five and seven years back. Anything over two years is flagged ageLooksImplausible, and age stops earning credit in the score past that point, so a dead record can never outrank a seller who has genuinely been trying for a year. Filter on that flag before showing anyone a shortlist.
  • Delisted is not the same as sold. A seller who pulls a listing and one who sells look identical from outside. Treat absorption as a strong proxy, not a fact.
  • Small neighbourhoods are noise. Anything below your sample threshold is flagged lowConfidence. Don't publish those medians without the flag.
  • The score's weights are reasoned defaults, not a fitted model. They are exposed precisely so you can do better for your own market.
  • isAgent is sometimes inferred from text when the source doesn't state it. agentInferred tells you which is which.
  • No personal data. Seller names and phone numbers are deliberately not carried through, even when the source provides them. This Actor reports market statistics; it is not a contact database.

FAQ

Does this scrape Yad2 or Madlan? No. It analyses listings you already have, from whichever scraper you prefer. That keeps your bill transparent and means the Actor works with any source, including your own CRM export.

Is the first run useful, or do I have to wait? Useful straight away. Where your source stamps a publication date — Yad2 and Madlan both do — days on market is real on run 1, and every neighbourhood comparison works from a single snapshot. Only price-cut history needs repeat runs, because no listing carries its past prices. If you have archived scrapes, backfill them and you get that immediately too.

Can I track several markets? Yes — use a separate Tracker ID for each. Keep them separate; merging Tel Aviv sales with Haifa rentals corrupts every median with no way back.

What if my scraper fails one day? Leave Runs absent before a listing counts as gone at 2. A single failed scrape then costs one day of latency instead of being read as a wave of sales.

Can I change the scoring? Yes, via Motivated-seller weights. Combine it with Dry run to test against real history without writing to it.

Does it work for rentals? Yes. Use a separate Tracker ID from your sale tracker.

Support

Found a bug or need a field that isn't there? Open an issue on the Actor's Issues tab — issues are read and answered. Feature requests that come with a concrete use case tend to get built.

The source is open: normalisation, the signal engine and the Hebrew handling are dependency-free and covered by a test suite you can run yourself with npm test.