marvin-mitterlehner.com 48.16°N 14.03°E · --:--:--
← back
Project · 2026–now

Real Estate Analyzer

A private market-intelligence tool for the apartment market. It captures listings every night, rebuilds the history the market itself forgets, and learns which places are actually worth my attention.

The premise

A real estate listings marketplace only ever shows today. A flat that has been online for four months looks identical to one posted this morning. A price that quietly dropped twice shows up as a single number. Almost everything interesting about a listing lives in time, and the marketplace throws that away every night.

So the tool's first job is simply to remember. Everything else (comparisons, rankings, recommendations) is derived from a history that nobody else is keeping.

Capturing the market

One gentle pass every night collects the apartments for sale and for rent across the regions I care about. The data already sits as structured JSON inside each page, the same payload the site renders itself from. Public pages only, one slow run, strictly private use.

The history is not reconstructable: the marketplace shows only the current state, so a missed night is gone for good. That makes the daily text snapshots the source of truth and the database a derived, rebuildable copy, never the only one.

Day to day

In daily use it is a map. Every listing sits where it actually is, filterable by price, size, rooms and features, with its own timeline alongside: when it appeared, what it cost, what changed since. Locations the source only knows roughly are drawn as a radius rather than a false pin, and a feature a listing simply does not mention is recorded as not specified, never as absent.

What a price actually means

Collecting numbers is easy. Knowing what they mean is the hard part. Base rent, operating costs, total burden, VAT, deposit, commission: labelled inconsistently from one agent to the next, and sometimes contradictory within a single listing. Before anything can be compared, the tool derives one honest comparable figure per listing, records which rule produced it and how confident that rule is, and keeps not specified strictly separate from zero.

Reading time, not snapshots

From the accumulating snapshots the tool derives the things a single view cannot: when a listing first appeared, every price change, and status changes, including a reserved flag that comes about as close to a completed deal as public data allows.

The statistics are treated carefully. A listing still online is a right-censored observation, not a finished duration, so it is not quietly averaged in as though it had ended. And a listing that disappears is never assumed to be sold or rented, only "no longer observed". The difference matters, and pretending otherwise would turn a scraper hiccup into a fake market signal.

Three scores, kept apart

Market liquidity. How quickly comparable listings disappear from the observed market, always shown with the sample size behind it, so a confident number and a hopeful guess do not look the same.

Opportunity. How attractive a listing is relative to comparable ones: how far below the comparable median, how fresh, whether the price has been cut. Deterministic and explainable, never an opaque number, and always with the caveat that these are asking prices, not signed contracts.

Personal match. A model that learns from my own like, maybe and dislike ratings, per person rather than pooled. It can pick up trade-offs a filter never could, such as normally wanting more space but accepting a smaller flat in a favourite area when the price per square metre is right. It starts as a transparent heuristic and only becomes a trained model once there are enough ratings to justify one.

The three combine into a single "For You" feed, but the individual numbers stay visible, so a recommendation can always be traced back to a reason.

Design decisions worth naming

History as plain text. Immutable daily snapshots are the archive; the database is regenerated from them, so a lost server loses nothing.

Explainable over opaque. Three separate, legible scores instead of one mysterious "AI number" that silently blends taste, price and market into something no one can question.

Ratings from day one. Market history accumulates on its own, but personal preference labels only exist once I create them. Every week without them is training data lost for good.

Why it stays interesting

New listings arrive every day, so the archive is never finished, and the longer it runs the sharper both the market history and the personal model get. A small private system with a high multiplier, quietly turning "hundreds of new listings" into "the handful actually worth looking at".

// built with love, by hand, in Wels ·
no framework, no build step