Reconciling Klaviyo Subscription Status: 63% Had Cancelled
A subscription brand we work with had a profile property in Klaviyo that marked every customer as an active or cancelled subscriber. When we checked it against the client's own records, 63% of the people Klaviyo had marked active had actually cancelled. Some had cancelled two years earlier.
Nobody had done anything wrong inside Klaviyo. The data coming in was incomplete: the integration told Klaviyo when someone started a subscription and never told it when they stopped. Here's how we found it, how we reconciled about 28,000 profiles against the client's source of truth using Claude Code, and the weekly job that keeps it from drifting again.
Why a Stale Subscription Property Matters
A subscription brand leans on that one property more than almost anything else in the account. It decides who counts as a subscriber in your segments, who gets subscriber-only messaging, and who should be getting a winback because they left. When the property is wrong, all of that is wrong in the same direction.
In this case the error only ran one way. Klaviyo knew when people started and never learned when they cancelled, so anyone who ever subscribed stayed "active" forever. Every segment built on that property overcounted subscribers, and the people who had cancelled were the ones least likely to hear from the brand as former subscribers.
How the Data Drifted
The client keeps their customers in a separate data warehouse, which is the real source of truth for who is subscribed. A third-party integration syncs that data into Klaviyo. It isn't a simple two-way sync, and the gap was on cancellations.
The part worth knowing: the cancellation event was reaching Klaviyo. Before changing anything, we had Claude check whether the people who looked cancelled had ever received that event, and almost all of them had. The event arrived and the profile property never changed. So the account had the right history and the wrong current state.
That's the trap with integrations. Seeing an event come through tells you the pipe is connected. It doesn't tell you the profile was updated. If you only spot-check the activity feed, this kind of drift can run for years.
The Reconciliation Logic
The client sent a CSV export from their warehouse: about 50,000 rows, which came down to about 26,000 actual customers. The obvious move is to make Klaviyo match the file. That's not quite the right question, and getting the question right mattered more than anything the tooling did.
The file is a list of people who are subscribed. What we needed to find were the people Klaviyo thought were subscribed who weren't on the file. It's a negative match: anyone marked active in Klaviyo but missing from the source of truth has cancelled at some point, and the integration never passed that along.
Matching on email alone would have gotten this wrong. Customers change email addresses, and the warehouse and Klaviyo don't always hold the same one. A profile that fails an email match isn't necessarily cancelled; it might just be the same person under a different address. So the matching ran in passes:
- Email first. The primary match between the file and the account.
- First name, last name and ZIP code for the profiles email didn't match.
- Last name and ZIP code as a final pass, to catch first-name variations like a nickname on one side and the full name on the other.
- Anyone who matched none of the three was treated as cancelled and had the property updated.
Profiles that were missing the property entirely got it set as part of the same pass, which is why the final count of updated profiles (about 28,000) came out higher than the customer count. People on the file who didn't exist in Klaviyo were left alone. Creating profiles wasn't the job; correcting the ones Klaviyo already had was.
Verify Before You Write 28,000 Profiles
Updating a property on tens of thousands of profiles is the kind of change that's very easy to make and very annoying to undo. If the matching logic is off, you've just marked real subscribers as cancelled, and they fall out of every subscriber segment in the account.
So the order of operations was deliberate:
- Map the data first. Before touching Klaviyo, Claude read the CSV and worked out how its fields lined up with the profiles in the account.
- Check the story against the events. A 63% cancellation rate is a big claim about a client's business. Confirming that those profiles had received the cancellation event is what made it believable instead of a sign the file was broken.
- Run a small batch. We updated a small group first and checked the results before doing the full sweep.
This is the same principle from our bulk suppression of a do-not-contact list, at about 17 times the scale. The speed is nice. The reason to do it this way is that the careful version, the one a person would skip because it takes all afternoon, now costs almost nothing.
Keeping It Fixed: A Flow Plus a Weekly Reconciliation
A one-time cleanup only fixes the past. The integration still behaves the same way, so without something else in place the drift starts again the next day. There are now two layers:
- A custom flow in Klaviyo that triggers on the cancellation event and updates the profile property, so the property changes when the event arrives instead of depending on the integration.
- A weekly reconciliation that runs the same matching logic against a fresh export from the warehouse and corrects anything that disagrees.
The flow handles the normal case in real time. The weekly job is the backstop for everything the flow can't see: events the integration never sends, profiles that change email, and whatever the next quirk turns out to be. It's been running every week since the first reconciliation.
How to Tell if Your Account Has This Problem
If a subscription platform, a subscription app or a separate database feeds subscription status into Klaviyo, two checks will tell you fast:
- Compare the counts. Build a segment of profiles Klaviyo considers active subscribers and compare it to the active count in the system that actually bills them. They won't match exactly, but if Klaviyo's number is well above the billing system's, something isn't syncing cancellations.
- Look for contradictions. Build a segment of profiles that have a cancellation event but still show an active status. If that segment isn't empty, your events and your properties disagree, and the property is the one your segments trust.
If either check turns something up, you have a reconciliation job on your hands. It's the kind of task Claude Code connected to Klaviyo handles well; our Klaviyo CLI is the tool it runs through, and Jarvis covers the wider setup we use across client accounts.
If your Klaviyo data has drifted from the systems that run your business and you want it reconciled and kept that way, reach out. This is the kind of work we handle as part of running a client's email program.