A CRM built around how you actually sell.

Pipelines, properties and permissions mapped to your real sales process, not the default setup.

Six services. One revenue system.

E-commerce services/Page Pros/Chapter two

The business thought it had 27,649 customers. It had 11,018.

Four systems each held their own version of every customer. We audited the fragmentation, resolved identity across all of it, then rebuilt the payment, reactivation, and onboarding paths that had grown up around the gap.

StackHubSpot·WooCommerce + Subscriptions·Square·Zapier·Composite identity scoring·Custom WordPress plugin

This is the second chapter. The first is the stack itself, built from nothing, then proved when a core component had to be swapped. Read the build →

The symptom

By the time Page Pros was onboarding 300 to 350 new customers a month, nobody could say how many customers the business had.

Same business, four answers
8,540
WooCommerce accounts
8,666
Square customers
10,443
HubSpot contacts
?
Master spreadsheet

Every figure downstream had inherited the disagreement. Customer counts, repeat-purchase rates, lifetime value, all quietly wrong in directions nobody could measure.

The cause wasn’t carelessness. The store enforced one account per email address, so a returning customer or a re-purchase couldn’t reuse the address already on file. The workaround was to invent one: a digit bolted onto the front or back of the real address. One customer ended up existing as seven variants of the same email.

It worked, in the only sense that mattered at the time. The sale cleared, the customer got their product, the business grew. It also meant the person in the store, the person at the till, and the person in the CRM were, as far as any system could tell, different people.

A workaround repeated a few hundred times a month stops being a workaround. It becomes the data.

Two more mechanisms compounded it. 466 customers had been charged directly in Square, through failed-payment rescues and direct deals that never touched the checkout, so the store had never heard of them. And a failed payment often meant cancelling the store account and rebuilding billing in Square, which left a dead account and a closed deal where an active customer actually lived. Both of those show up again further down this page, because both had their own fix.

What we rebuilt — identity first

Matching on email was never an option, because email was the field the workaround had corrupted.

We audited the pool before touching anything, then built composite identity scoring across WooCommerce, Square, HubSpot, and the spreadsheet. The model weighs phone, name, company, address, and email together, scores how likely it is that two records describe the same person, merges high-confidence matches automatically, and queues the rest for a human.

Two decisions carry the model. Phone outranks email, because a real person rarely holds two different ten-digit numbers across three systems, while this dataset held over a thousand invented addresses. And the signature of the workaround itself, a stripped-base email match, scores high enough to flag a pair but never high enough to merge it alone. It always needs one corroborating signal before a record moves.

A wrong merge is worse than a duplicate, so uncertainty goes to a person rather than to a rule. One legitimate pattern looked identical to the fakes: an owner opening a second location or a second company. That case gets a confirmation step rather than a merge, which is the whole argument for scoring over matching. The fraud and the growth are indistinguishable until something weighs the evidence.

Out the other side
11,018
Real customers, from 27,649 records
16,631
Duplicates or fragments — 60% of the pool
99.6%
Of 8,125 clusters spanned two or more systems

That last figure settles what kind of problem this was. It was never a mess inside one tool. It was the gaps between four.

The business had been reading itself as two and a half times its own size. Every decision taken off those numbers had been taken against a customer base that did not exist.

The scoring model, the confidence tiers, and the full audit findings have their own page. Read the dedup study →

The card that couldn't be changed

In a subscription business, a declined card is routine. The path back from one was not.

There was no way to update a card on an active subscription. That wasn’t an oversight in the setup; it was a limit in the platforms themselves. The only route was to cancel the subscription in WooCommerce, rebuild the customer in Square as a new recurring series, and update the deal in HubSpot by hand. Three platforms, four steps, ten to fifteen minutes, three or four times a day.

This is the second fragmentation mechanism from the audit, seen from the operational side. Every rebuild created a duplicate customer, so a routine card expiry was manufacturing new customers in the reporting.

Some of the growth the business could see was attrition wearing a costume.

We built the Square Payment Method Manager, a WordPress admin plugin that puts card management inside the WooCommerce subscription screen. Add a card through Square’s tokenization, set which one charges at renewal, charge a specific card immediately to recover a failed payment, remove an expired one. No cancellation, no rebuild, no second trip to Square.

Every action writes to the subscription’s fields at once, so the renewal engine, the payment gateway, and the admin screen never disagree about which card is on file. A preflight check refuses to attach a card to the wrong Square customer — the same identity discipline enforced at the payment layer, so the problem the audit had just measured couldn’t quietly rebuild itself.

Before
3 platforms, 4 steps, 10–15 minutes, three or four times a day
After
One screen — roughly 16 hours a month, about 190 hours a year, back

The more interesting change is quieter. The panel shows which card will be charged at the next renewal, and flags an expired one before the charge is attempted. The admin team stopped reacting to declines and started auditing renewals, acting before the customer knew there was anything to act on.

The customer who came back and became a stranger

A dormant customer who wanted to return couldn’t have a new subscription attached to their existing account. The only way to take their money was to create them again.

With a new email address, which is the same constraint that started the fragmentation in the first place. Lifetime spend reset to zero. The history of what they’d bought, what they’d paid, and how long they’d stayed was severed from the person it belonged to, and the return counted as a brand-new customer.

For seasonal customers, who pause and come back every year by design, that erasure was annual. The system had no concept of returning. Loyalty was structurally invisible to it.

We built reactivation properly. A new subscription attaches to the existing customer record, and the history stays with the human it describes. Then the full lifecycle as a defined pipeline — lead, customer, dormant, active — with reactivations generating their own deals, so a returning customer is a recognisable event rather than an accident of data entry.

Roughly 900 duplicate records a year stopped being created.

The onboarding call nobody attended

Six to seven percent of paying customers never showed up to their first onboarding call, and almost all of them cancelled after month one.

The missed calendar invite was one of the most reliable churn signals in the business, and nothing was reading it. The no-show sat as an empty half-hour in someone’s diary, not as a flag on an account about to leave. An automated follow-up sequence now fires for anyone who misses.

The miss became a sequence instead of a silence.

The call had a second leak inside it. Seven to ten of its thirty minutes went to collecting basic business information, with photos and details chased through email threads before and after. A HubSpot onboarding form the customer fills in writes straight into their profile ahead of the call, so the information is already there when the call starts. The call is still thirty minutes. Across the monthly volume, roughly 46 hours a month of it moved from data collection to actual onboarding.

The workflow that reported success

A billing-date reset in the subscription plugin was silently excluding hundreds of accounts from the monthly send. No error surfaced.

Monthly update emails ran from a shared process with no owner attached to each send, so as the account-manager team grew, the communication got more generic and less attributable. Underneath that sat something worse.

The workflow reported success every month, and hundreds of customers quietly stopped hearing from anyone.

We replaced the trigger, which had been built on a date field the billing system kept resetting, with a dedicated send-date property and a calculated next-send date. Then we routed each send to the account manager who actually owns that account. The touchpoint came back for everyone who had been missing it, and it now scales with the team instead of against it.

What the architecture holds now

Two pipelines, sales and customer service, with reactivations tracked as their own deals.
One account holding any combination of the three products, with per-product deal and payment tracking that stays accurate.
One customer holding several businesses and several locations, because plenty of them do.
Separate US and Canadian databases, with a purpose-built setup for the US market.

None of that was possible while one customer could exist as seven records. All of it is ordinary now.

The outcome

One customer, one record, one history — with an evidence trail behind every merge and the operational paths around it rebuilt so the fragmentation can’t regrow.

Reports that count 11,018 customers instead of 27,649 records.
Card problems resolved on one screen before the customer notices.
Returning customers recognised as returning — around 900 duplicate records a year stopped at source.
Around 16 hours a month of admin time back, and 46 more moved from data collection into work worth doing.

One customer, one record, one history.