Where they started
Castellan's problem was measurable in a single number: 9.2 seconds to largest contentful paint on a listing page over 4G. Property photography is the point of a property site and it was also the payload — eight to fourteen full-resolution JPEGs per listing, served at original size and scaled down in the browser.
Search made it worse. Every filter change — price, beds, type — triggered a full page reload, so refining a search meant waiting nine seconds again. Their analytics showed 2.1 pages per session, which for a property site means people were looking at one listing and leaving.
Then the URL problem. Their previous developer had configured delisted properties to return 404. Around 300 sold listings had accumulated links and search authority over four years, and all of it was being discarded on the day of sale.
Their agents had quietly adapted by sending buyers links to the portal instead of their own site. Every one of those visits was a lead they paid a fee on.
What we built
The image pipeline was the first fix and the biggest. AVIF with WebP fallback, generated at five widths, the hero preloaded and everything below the fold lazy-loaded, with blurred placeholders so the layout never shifts as photos arrive. Same photography, roughly an eighth of the bytes.
Search became client-side over a pre-built index. Filters apply instantly, map and list views share state, and the URL updates so a filtered search can be bookmarked or sent to a client — which is what the agents were using the portal for.
The feed was the unglamorous half of the project. Their RESO Web API source sends duplicate records and occasionally omits required fields, so ingestion runs every fifteen minutes with validation and a reconciliation report. Bad records raise an alert instead of quietly publishing a listing with no price.
For sold stock we wrote an actual policy rather than picking a default. Sold listings stay live with clear status and links to similar available properties; the handful that were genuinely worthless get a 301 to their area page. Nothing that had earned links gets thrown away.