← All writing
Real-timeJune 30, 2026·8 min read

Your 3D model should talk to your CRM

An interactive maquette that shows a fixed unit list is a brochure. Wire it to your CRM and it becomes the sales floor: units reflect real status in real time, a tap becomes a qualified lead, and nobody sells the same apartment twice. How I build that in the browser, with code.

Most interactive property models have a quiet lie in them. The tower spins, the floors peel apart, you tap a unit and see its plan, and the whole thing feels alive. Then you notice the unit marked available was sold last Tuesday, because the model is reading a list somebody exported to JSON three weeks ago. It looks like software and behaves like a brochure.

Meanwhile the truth about your inventory lives somewhere else entirely: a CRM, a sales system, a spreadsheet a coordinator updates by hand. The model and the truth never speak. The single highest-leverage upgrade you can make to an interactive maquette is to close that gap, so the 3D is not a picture of your inventory but a live window into it.

A model that shows a fixed unit list is a brochure with an orbit control. Connect it to the system that actually knows what is sold, and it becomes the sales floor.

Every unit already has a status

You do not have to invent any new data to do this. Every unit in the building already carries a status in your CRM or inventory system: available, on hold, reserved, sold. That status is the most valuable thing you can put on a 3D model, because it turns a pretty object into a decision surface. Colour the units by status and a buyer sees, at a glance, what is actually gettable, where the good stock is, how fast a floor is filling. Scarcity you can see moves people in a way a price list never has.

The mechanics are simple once the model is built the right way. Each unit is a component that reads its own status and paints itself. It does not know or care where that status came from. Swap the source from a static file to a live feed and nothing about the geometry or the interaction changes. That is the whole trick, and it is why doing this on the web is cheap: the model was always just a view of state.

Interactive maquette showing districts and per-unit selection with a unit list
Units and districts as selectable objects, each tied to a record. Put its CRM status on it and the tower becomes a live board of what is actually available.

Live, and both directions

The version that earns its keep is live. When a sales agent marks a unit reserved in the CRM, every open model updates within a second: the website, the gallery touchscreen, the link a broker forwarded this morning. No nightly sync, no stale PDF, and critically no two agents pitching the same apartment because one of them was looking at yesterday's data.

It runs the other way too, and this is the part developers underrate. A buyer taps a unit in the 3D, and the app writes a lead straight into the CRM with that exact unit attached: block, floor, unit number, even the view they were looking at. Sales stops receiving anonymous contact-form enquiries and starts receiving qualified intent. The model is no longer just showing inventory, it is generating pipeline.

The CRM drives the model; the model feeds the CRM
// server — one webhook from the CRM, fanned out to all
app.post('/webhook/crm', (req) => {
  const { unitId, status } = req.body   // 'reserved' | 'sold'...
  io.emit('unit:update', { unitId, status })
})

// client — the scene reacts in real time
socket.on('unit:update', ({ unitId, status }) =>
  units.set(unitId, status))            // one store update

// each unit paints itself from status, and a tap
// writes a qualified lead back into the CRM
<Unit id={id}
  color={STATUS_COLOR[status]}
  onClick={() => createLead({ unitId: id, view })} />

The CRM is the source of truth, the model is a view

The failure mode to avoid is letting the model own the state. It should not. Your CRM or inventory system is the single source of truth, and the 3D is a live view of it, the same way a dashboard is. A unit's status changes in one place and everything reflects it. The moment you keep a second copy of availability inside the 3D app, you have signed up to keep two systems in sync forever, which is exactly the mess you were trying to escape.

Practically that means the browser never talks to the CRM directly. A small server sits in the middle: it holds the credentials, exposes only the read-only data the public model is allowed to see, receives the CRM's webhooks, and validates any write like a new lead before forwarding it. The client stays dumb and safe. This is ordinary web architecture, which is the point. It is boring, well understood, and cheap, not a bespoke networking layer you invent and then maintain alone.

Beyond the CRM: booking, payments, inventory APIs

A CRM is usually the first integration, not the last, because the wiring is the same for all of them. That same webhook-in, socket-out pattern reaches a booking system that places a temporary hold when a buyer expresses interest, a payment step that takes a reservation deposit and flips the unit to reserved on success, or a GraphQL or REST inventory service that is the real system of record. From the model's side these are interchangeable: something changes a unit's status, the change arrives over a socket, the mesh recolours.

Because it is all standard web, authentication is standard too: a token on the server, scoped access, the usual guardrails your web team already knows. There is no per-platform plugin to source, no native SDK to wrap, no separate build to test. The interactive model joins your stack as just another client of your APIs, which is the least glamorous and most valuable thing I can say about it.

Interactive maquette surroundings map with amenity, transport, and services data layers
Amenities, transport, medical, and services as toggleable data layers on the model, the same wiring as live inventory.

This is the line between a maquette and a twin

If you have read my other pieces you have seen me draw the line between a digital maquette and a digital twin. This is exactly where it sits. The maquette is the model reading a static snapshot: perfect for a launch, shareable as a link, no live plumbing. The twin is the model reading live systems, and a CRM-connected sales model is the first and most common kind of twin most developers actually need, long before building-management sensors enter the picture.

The good news is you do not choose once and forever. Because the model is the same scene either way, you can ship the maquette for launch day and switch the data layer on later, when the CRM integration is ready, without rebuilding the 3D. The geometry, the lighting, the interaction all stay. You are only changing where the status comes from.

What you actually get

Put plainly: no double-sold units, because everyone reads one truth. Qualified leads with the unit attached, because a tap writes to the CRM. Visible scarcity that moves buyers, because status sits on the model where they are already looking. And a marketing asset that stops going stale the day after launch, because it is wired to the system that changes anyway.

None of this needs a headset, an install, or a controlled machine. It is a link that happens to be plugged into your sales operation. That combination, reach plus live data, is the whole reason my interactive work lives in the browser now, and it is the first upgrade I would push for on any model that is currently just a pretty, static thing.

Moustafa Moussa

Moustafa Moussa

3D technical art director. I make the unbuilt feel real.

Have a space that needs believing in?