TL;DR — What Changed
- Commercial teams see live coverage across all 71 mapped NHS trusts in one place, not stale spreadsheet exports.
- Every change made on the map writes back to HubSpot immediately, so the CRM is never out of sync with reality.
- SDRs work a ranked queue with the originating channel attached to every lead, not an undifferentiated list.
3D Estate Visibility and Live HubSpot Sync
Two builds for one commercial team: a 3D cockpit that turns the NHS secondary-care estate into something you can see and act on, and an SDR dashboard that turns raw call and email data into a ranked queue. Both write straight back into HubSpot.

Overview
The client is an NHS-adjacent healthcare staffing platform, connecting temporary and locum clinical staff with NHS trusts across the UK. Its commercial and SDR teams sell into secondary care, which in practice means selling into a market with 71 distinct trusts, each with its own hospital sites, its own procurement quirks, and its own place in a pipeline that has to be tracked deal by deal. We built two things for this team: the Secondary Care Cockpit, a 3D geographic view of the estate with live HubSpot deal data drawn directly onto it, and the SDR Activation Dashboard, a ranked lead queue built from HubSpot and Looker data. They ship separately and solve different problems, but they share one design principle: HubSpot stays the system of record, and everything we build reads from it and writes back to it rather than existing as a parallel copy that drifts.
The Problem
Before either build existed, the view the commercial and SDR teams had of secondary care lived in HubSpot rows and separate lead lists. That’s not a criticism of HubSpot: a CRM is built to hold records, not to show you a hundred-plus hospital sites arranged the way they actually sit on a map, or to tell a rep at a glance which trust has a live deal moving and which one has gone quiet. The team needed to work the estate directly. Which trusts had live deals. Where those deals sat in the pipeline. Where to spend outbound effort next, given a fixed number of SDR hours and 71 trusts competing for them. None of that existed as something a team member could act on and then hand off to a colleague without re-checking the underlying data by hand first. Every handoff was a re-verification exercise, which is a slow and error-prone way to run a pipeline that depends on timing.
On the SDR side, the problem was different in shape but the same in kind: too much raw signal, no structure. HubSpot recorded meetings, calls, emails and sequence activity. Looker held reporting-layer data on outcomes. Neither system was built to answer the actual question an SDR asks at nine in the morning, which is: who do I call first today, and why that person over the other four hundred in my territory.
Our Solution
We split the work into two builds rather than forcing one system to do both jobs, because a geographic pipeline visualisation and a daily calling queue have different update cadences, different users, and different failure modes. Forcing them into one codebase would have meant every change to one risked breaking the other.
Secondary Care Cockpit
The Cockpit is a 3D map of the NHS secondary-care estate, built in Next.js and deployed on Vercel, rendering with Three.js. It covers all 71 trusts, and the hospital sites sit where they actually are geographically rather than as rows in a spreadsheet, with ward placements checked against evidence rather than approximated. On top of the map sits a live HubSpot deal layer: a drag-to-move pipeline board where moving a deal on the map updates the underlying HubSpot record immediately, with no export step and no re-entry. We also built a natural-language assistant into the Cockpit that takes plain-English instructions and turns them into the correct HubSpot deal update, because not every commercial team member wants to learn a bespoke UI to change a deal stage.
Two things needed to sit underneath that before it could go live for real users. First, trust service profiles gated by CQC status, since not every trust-level fact is safe to surface to every viewer, and the data model had to encode that distinction rather than leave it to convention. Second, a permission layer, because different commercial teams needed genuinely separate visibility rather than a shared login with an honesty policy attached to it. We built a standalone, KV-backed user management system specifically for the Cockpit: passwords hashed with scrypt, account lockout after repeated failed attempts, session-version invalidation so a password reset or a role change actually revokes existing sessions rather than leaving them valid until they expire naturally, and role enforcement checked on every request rather than only at login. We also built a closed-lost disposition system, so a deal that stops moving gets a clear, structured reason attached to it instead of just going quiet on the map, which matters because “quiet” and “lost” are different states and the team needed to be able to tell them apart at a glance.
SDR Activation Dashboard
The Dashboard runs on n8n, pulling HubSpot and Looker data on a schedule and writing the processed result into a sharded Upstash Redis store. The core output is a five-tier lead prioritisation model: every lead in a rep’s territory gets ranked, so the daily queue is never just “everyone in my patch,” it’s “these people first, and here is roughly why.” Territory scoping keeps that ranking relevant to the rep looking at it rather than showing them a global list they’d have to filter themselves. Each activation carries channel attribution, built on a hierarchy of meeting, call, email and sequence touches, so a rep can see not just that a lead is high priority but what kind of engagement got them there. We added outcome weighting on top of the base ranking, and a lapsed-post rescue signal that resurfaces a lead whose engagement has gone quiet after a period of activity, on the basis that a lead that recently went cold is a different kind of opportunity than one that was never warm. Every action a rep takes against the queue writes a task back into HubSpot, so the CRM stays the record of what actually happened rather than a downstream copy of it.
How We Deployed It
The single hardest technical problem on the SDR side was memory, not logic. The first version of the ingestion workflow pulled HubSpot and Looker data and processed it in one pass inside n8n. That worked at small volume and then stopped working as the data grew, crashing with out-of-memory errors partway through a run. The fix wasn’t a bigger server; it was a different shape of workflow. We split the pipeline into a Collector stage, which pulls and stores raw data in smaller batches without trying to hold the full dataset in memory at once, and a separate Merger stage, which combines and scores the batches afterward. That split-architecture decision was adopted specifically to stop the OOM crashes, and it’s the reason the Dashboard runs reliably on a schedule now rather than needing to be babysat through every run.
On the Cockpit side, the harder problem was correctness rather than performance: getting ward placements right enough that a commercial team member could trust the map instead of treating it as a nice-looking overlay on top of the real data in HubSpot. That meant checking site placements against evidence rather than plotting from best-guess coordinates, and building the CQC-gating into the data model from the start rather than retrofitting it once profiles were already live. The permission layer was the other piece that took real engineering time on its own terms, separate from the map itself, because role-based access with session invalidation is the kind of feature that looks simple until someone changes a password and expects every other active session for that account to stop working immediately, not on next login.
The Outcome
The headline figure is the one that’s evidence-locked and stays that way: 71 NHS trusts mapped and live. Beyond that number, the change is qualitative, and we’re stating it as qualitative rather than dressing it up as something more precise than it is. The commercial team sees estate coverage across all 71 trusts in one place instead of working from spreadsheet exports that were out of date the moment they were pulled. Changes made on the map are the CRM’s own data, not a copy that drifts out of sync with HubSpot over time, because every move writes back immediately. The SDR team works a ranked queue instead of an undifferentiated list, with the originating channel attached to every lead, so a rep can see not just who to call but why that call is likely to matter. Both systems have been running in production, not as a demo or a pilot that quietly stopped being used.
Why build a 3D map instead of a simpler dashboard?
So the estate is genuinely visible, not just tabulated, across 71 NHS trusts, with a role-based access layer designed in from the start rather than retrofitted once profiles were already live.
Does moving a deal on the map actually update HubSpot?
Yes. Every move writes back to HubSpot immediately. The map isn’t a separate copy of the data that can drift out of sync with the CRM.
How does the SDR side prioritise leads?
A five-tier ranked queue with the originating channel attached to every lead, so a rep can see not just who to call but why that call is likely to matter.
Want a Build Like This?
Book a free audit and we’ll walk through what’s possible with your data as it stands today.
Related: RevOps Consultancy and AI Deployment. More on the team behind this build: About Equanax.