00 / Case study
The CRM changes.
The site follows.
DigitalHappy designs and builds websites for estate agents across Spain, from island specialists to national agencies. Every one of those agents keeps its listings in a property CRM, and the website is only worth something if it stays up-to-date automatically. Since 2024 I have been the developer who connects the sites to the systems behind them: importers that bring listings in, forms and feeds that send data back out, and the search and browse pages built on top.
-
10
Sites for
DigitalHappy -
10
Systems
connected -
2,600+
Properties
in sync -
05
Languages
on one site
- Client
- DigitalHappy
- Role
- Backend developer
- Stack
- Statamic, Laravel
- Since
- 2024, ongoing
01 / Starting point
Estate agents run their business in a property CRM. That is where listings are created, priced, translated and marked as sold, and nobody at the agency wants to enter any of it twice. The website has to follow the CRM on its own, every night, without an editor copying anything across.
There is no one CRM, and no standard way out of one. Each agency works with its own (Infocasa, Mobilia and Inmoweb among them), and each hands over its listings differently: a full XML export published every night, a proprietary XML service that answers one query at a time, a JSON API behind an access key, photos that have to be fetched separately. Every one of them has its own structure for locations, property types and translations, and documentation is thin where it exists at all.
Data has to travel the other way as well. What visitors send through a form belongs in the agency's own systems rather than an inbox, a card payment only counts once the bank has confirmed it, and some listings also need to go out to property portals abroad, in the format those portals expect.
The buyers come from all over Europe, so the same listing exists in up to five languages, and every agent wanted its own way of browsing by region, town and property type.
02 / Constraints
- The feed decides what exists
- A property sold in the CRM has to leave the website by the next morning, and a new one has to appear. The same holds for every price drop, new photo and rewritten description, in every language the listing has.
- Editors keep their work
- Agencies add their own text, SEO fields and landing pages around imported listings. A nightly import may only touch the fields it owns.
- A failed import changes nothing
- If an import stops halfway, visitors have to see yesterday's listings, not half of today's and an error page for the rest.
- Nothing fails quietly
- Every import keeps its own log of what it fetched, changed and skipped. An error does not wait for someone to notice a missing listing: it goes by email to the people who can act on it.
03 / What I built
-
B/01
Property importers
Five importers that share one shape: fetch and archive the feed, check it is complete, compare it with what the site holds, then create, update and delete in queued jobs. Only listings changed in the last day are rewritten, so an incremental run updates a handful of properties in seconds rather than the whole catalog.
-
B/02
Every language
The same listing in up to five languages, with titles, descriptions and SEO text mapped onto Statamic localizations, and location trees rebuilt from province down to municipality for each language.
-
B/03
Browse pages from data
At four of the agencies, every combination of location and property type becomes its own page with a title, a listing count and links to its neighbors. The pages are generated from the imported data and warmed into the static cache after each import.
-
B/04
Search that knows the map
Pick a region and every town below it is included. Search runs on CRM ids rather than slugs, so it survives re-imports, and a location autocomplete is fed from the same tree.
-
B/05
Old links keep working
Property alerts and portals still point at URLs from the previous sites. At two of the agencies, those old addresses are matched to the listing by its CRM reference and redirected permanently.
-
B/06
Listings in full
Photos, 360-degree photos, videos and virtual tours come over with each listing and are served from the CRM, energy certificates arrive with the rest of the data, and where the agency wanted it, schema.org listing data describes each property to search engines.
-
B/07
Forms into CRMs
Inquiry and application forms go straight into the CRM instead of an inbox, with returning contacts matched by email instead of duplicated. Job applications reach Salesforce with the CV stored in a private bucket, never on the web server.
-
B/08
Feeds and APIs
An OpenImmo feed that can pass the resort development's listings on to German portals, JSON location feeds behind the search autocomplete, the resort's HubSpot blog pulled in over its API, and live listings from a national agency's property API inside its blog, cached and logged when the API fails.
-
B/09
Payments
Redsys card payments, with every attempt logged and recorded as an order. The bank's signed confirmation, not the visitor's return to the site, is what marks an order paid and emails both sides.
04 / Messy data
Feeds do not always arrive the way they should. They time out, get cut off halfway or come back empty, and one CRM sometimes sends a perfectly valid XML file holding an error message instead of listings. Read naively, any of those looks like an agency that has sold everything overnight. The importers check every feed before acting on it, and when something is off they change nothing and report it.
The data inside is just as uneven. Translations go missing without warning, the same field arrives as a single value in one listing and a list in the next, descriptions come as one block held together by stray line breaks, and every CRM writes its dates its own way. All of it is cleaned up and normalized before anything is saved, so the website never shows it.
05 / Ongoing work
The importer, search and browse pages for the agency in Barcelona are built, ahead of the site's launch.
On the Mallorca site, a performance pass on search and browse pages is in review.
06 / In their words
“Alexander has helped us to develop add-ons that integrate with third-party APIs. His understanding of our project needs and the quality of the work delivered were excellent. He demonstrated clear expertise and knowledge of the Statamic and Laravel environment, and our collaboration has been extremely positive.”
Creative Director, DigitalHappy
07 / Credits
The sites were designed and built by DigitalHappy. My part was the backend work described here.
08 / Next step
Your website and your CRM disagree?
Listings that stay online after they sell, prices that differ, translations that never arrive. Name the CRM you are on and what has to travel in each direction. That is enough to scope keeping the two in step.