focosys.io
← Writing
Essay · Customer Data, Attribution & Lifecycle

CDP identity resolution breaks after week 12, not before

Most CDP rollouts fail because nobody owned identity resolution before the contract was signed. Here's where the 90 days actually go wrong.

CDP identity resolution breaks after week 12, not before
Key takeaways
  • Most CDP failures happen before day 1: the vendor demo skipped identity resolution, so the team discovers 3-4 competing definitions of 'customer' only after data starts flowing.
  • A CDP with no owned use case by day 30 becomes, say, a few thousand dollars a month in expense the team defends in budget reviews instead of a system that ships audiences.
  • Reverse ETL syncs fail silently more than they fail loudly. If you're not checking sync logs weekly, a broken Klaviyo sync can run undetected for a full billing cycle.
  • Identity resolution rules degrade over time as new sources get added. The fix that worked at 2 sources creates false merges at 6, and nobody revisits the ruleset until support tickets pile up.

The CDP demo went great. Sales showed unified customer profiles, real-time audience sync to Meta and Google, a dashboard that made the CMO nod. Contract signed in March. By June, three people on the marketing team are quietly Slacking each other asking if anyone actually knows what's in the tool anymore.

This is the pattern I see more than any other in this space. Not a bad platform choice. Not bad intentions. A rollout that had no owner, no defined use case, and no plan for what happens when two data sources disagree about who a customer is.

I've walked into six of these post-mortems in the last two years. Segment, RudderStack, mParticle, one home-grown warehouse-native setup. Different vendors, same failure shape. The tool works. The implementation doesn't.

The demo hides the hardest problem

Every CDP demo shows you a clean unified profile. One row, one customer, all their events and traits merged. What the demo doesn't show is the identity resolution logic that made that merge happen, because in the demo, the data was clean and the rules were pre-built for a happy path.

Your data isn't clean. You've got a Shopify customer ID, a GA4 client ID, an email captured at checkout, a phone number from SMS opt-in, and a hashed email sitting in your ad platform's conversions API. None of these are guaranteed to point at the same person with certainty. Someone has to write the rules that decide when two records merge and when they stay separate.

That "someone" is rarely named in the project kickoff. The vendor's implementation team will build a default identity spine, usually keyed on email with fallback to a first-party cookie ID. That default works fine for a DTC brand with one login flow. It falls apart the moment you add a loyalty program with phone-based auth, a wholesale portal with company-level accounts, or guest checkout that never captures an email until the confirmation page.

Identity rules are the actual product, not the UI

The dashboard, the audience builder, the reverse ETL connectors, all of that is the same across most CDPs at this point. The differentiator that determines whether your rollout works is the identity resolution logic, and that's the part nobody budgets time to design before kickoff.

What to do: before the platform is even selected, write down every identifier your business collects (email, phone, device ID, loyalty ID, account ID) and map which systems hold which ones. If you can't produce that map in a spreadsheet in an afternoon, you're not ready to configure identity resolution. You're going to inherit whatever default the vendor ships. The same mapping discipline applies to attribution work; see how GA4 attribution can quietly go wrong when nobody owns the source-of-truth definition.

Week 1-30: nobody owns a use case, so nobody notices it's broken

Week 1-30: nobody owns a use case, so nobody notices it's broken

Many CDP contracts get signed by someone who wants "a single customer view." That's not a use case. That's a mission statement. Nobody can build a QA checklist against a mission statement.

The rollouts that survive past 90 days have a first use case picked before data starts flowing. Something concrete: "sync high-value cart abandoners to a Meta custom audience within 15 minutes of the event." That's testable. You can watch the audience populate in Meta Ads Manager and check the count against your own event log.

The rollouts that fail spend the first month connecting sources because "more data is better" and never define what success looks like for any single audience or sync. By day 30, the team has a dozen or so sources connected, an identity graph nobody's validated, and zero audiences shipped to an ad platform. At that point the CDP is a line item, not a tool. It shows up in the next budget review as a cost center someone has to justify, and justifying "we have a unified customer view" to a CFO who wants pipeline numbers is a losing argument.

Pick one audience, ship it, then expand

Before connecting a second source, get one audience from source to ad platform end to end. Warehouse to CDP to Google Ads Customer Match, or CDP to Klaviyo. Validate the count matches expectations. Only then add the next source. Sequencing beats parallelizing here.

What to do: name one activation use case with a number attached (audience size, sync frequency, time-to-activation) and get it live before adding a fourth or fifth data source. A working narrow pipeline beats a broad one that nobody's checked.

Reverse ETL fails quietly, and quiet failures compound

Reverse ETL syncs (warehouse to Klaviyo, warehouse to Meta CAPI, warehouse to Salesforce) don't usually fail with an alert. They fail with a stale sync that keeps reporting "success" while the underlying query silently returns fewer rows than it should.

I've seen this happen because a warehouse table got a schema change (a column renamed from customer_email to email_address during a dbt refactor) and the sync tool's field mapping kept referencing the old column name. The sync didn't error. It just synced null values for that field going forward. Nobody caught it because the audience size in the destination platform still looked roughly right, just slightly smaller each week as more records aged out of whatever fallback logic the platform used.

That's weeks of a marketing team optimizing campaigns against an audience that's silently degrading, with no error in any dashboard telling them to look. This is the same silent-failure shape that shows up in Facebook CAPI deduplication problems, where a broken pipeline keeps reporting numbers that look plausible but aren't.

-- what gets checked by default (audience count, looks fine)
select count(*) from activated_audience_v1;

-- what actually catches the break
select
  count(*) as total_rows,
  count(email_address) as non_null_email,
  count(*) - count(email_address) as null_email_count
from activated_audience_v1
where synced_at >= current_date - interval '7 days';

What to do: schedule a weekly check on null rates and row counts for every reverse ETL sync, not just a pass/fail status check. Most reverse ETL tools (Census, Hightouch, RudderStack) expose sync logs with row-level success/failure counts. Look at them. A sync that says "completed" and a sync that's actually moving correct data are two different claims. The debugging discipline is the same one covered in how to debug server-side GTM across the full event chain.

The identity rules that worked at launch break at scale

The merge logic that correctly identified customers across 2 sources at launch starts producing false merges once you add source 5 or 6. This is the failure mode nobody plans for because it doesn't show up on day 1. It shows up three months in, as a slow accumulation of support tickets: "why did this customer's order history show items they never bought," "why is this person getting emails meant for someone else."

A common version: identity resolution is keyed on email plus a fuzzy name match to catch typos and nicknames. That works fine when your only sources are the website and email platform. Add a call center system that logs customer records under the agent's typed name instead of the customer's, and now "Mike Johnson" and "Michael Johnson" from two different households start merging into one profile because the fuzzy match threshold was tuned for a smaller, cleaner dataset.

Identity resolution rules rarely get revisited on a schedule. They get set once during implementation and treated as infrastructure, not as a living ruleset that needs review every time a new source gets added.

What to do: whenever you add a new source to the CDP, re-run identity resolution against a sample of known customer pairs (people you're certain are the same person, and people you're certain are different) and check the merge/split results before pushing the new source to production. Most platforms let you run this in a staging or preview mode. Use it every time, not just at initial setup.

What the first 90 days should actually look like

Days 1-15: map your identifiers across every source system before connecting anything. Write down what "same customer" means in plain language, and get someone from data, someone from marketing, and someone from customer support to agree on it. They usually don't agree on the first try, and that disagreement surfacing early is the point.

Days 15-45: connect two sources, build identity resolution against those two, and validate against a sample of records you can check by hand. Ship one audience to one ad platform. Confirm the count and confirm a handful of individual records look correct.

Days 45-75: add reverse ETL syncs one at a time, with row-count and null-rate monitoring on each before moving to the next. Add a third data source only after the first pipeline is stable for at least two weeks.

Days 75-90: document the identity resolution ruleset in a place someone new to the team can read it. Most of the "why is this customer profile wrong" tickets I've debugged happened because the person who set up the merge logic left the company and nobody else understood the config.

None of this is exciting work. It's also close to the entire difference between a CDP that's still running audiences in month six and one that's a support ticket in the next platform migration.

The platform was never the hard part. Deciding what counts as the same customer, and checking that decision every time the data changes, is the actual job.

focosys — Measurement systems writingMore writing →