The unified contact timeline
Most organisations do not have a contact data problem. They have a contact data location problem: they know everything about a person and they know it in five places, none of which agree. This is what a unified timeline is, why history fragments in the first place, and what it takes to actually build one.
What a unified contact timeline is
A unified contact timeline is one chronological record per person that contains every interaction with them, whichever tool produced it. A door knock, a text reply, a chatbot conversation, an email open, a donation, a note somebody typed after a phone call: one person, one list, in the order the things happened.
The defining property is subtle and it is the whole point. The tool is an attribute of the event, not the location of it. In a fragmented setup, "she replied to the text" lives in the texting platform because the texting platform is where texts live. On a unified timeline it lives on her record, tagged as having come from the texting platform. The difference sounds like filing. It is the difference between being able to ask "what is the history with this person" and only ever being able to ask "what did this tool do".
That is also why a unified timeline is not the same thing as a set of integrations. Two tools syncing to each other gives you the same information in two places, each still organised around itself. A timeline reorganises around the person.
Why contact history fragments
Nobody chooses fragmentation. It is what happens by default, because each tool stores the interactions it produced, keyed by whatever identifier it happened to collect.
- A texting platform knows a phone number. It may never have been told a name.
- An email platform knows an email address, and treats two addresses as two people.
- A canvassing app knows an address and a name, and often no contact details at all.
- A website chatbot knows whatever the visitor typed, which might be a first name and a mobile number.
- A spreadsheet knows whatever the person who made it decided to put in the columns.
None of those identifiers is the same shape, so nothing joins them automatically. The same person exists several times, under several keys, and every tool's version of them is correct and incomplete. The cost shows up at exactly the wrong moment: somebody who already said "stop texting me" gets texted, because the person doing the texting was working from the list that did not know.
Fragmentation is not primarily a reporting problem, though it wrecks reporting too. It is a judgement problem. Every decision about a person, whether to call, whether to ask again, whether to escalate, is made against whatever history is visible, and in a fragmented setup the visible history is a fraction of the real one.
Deep dive: why the timeline is the spine of a product suite, and what changes when several tools write to one record.
What belongs on a contact record
A contact record has to carry two different kinds of thing, and confusing them is a common design mistake.
Attributes are what is currently true: name, phone, email, address, stage, tags, custom fields. They are overwritten when they change. Nobody wants the history of somebody's phone number; they want the phone number.
Events are what happened: a knock, a reply, an open, a stage change. They are never overwritten and never deleted, because an event that can be removed is not evidence of anything. If a record's history can be quietly edited, it stops being usable for the decisions it exists to inform, and in regulated messaging it stops being usable as proof of consent.
That distinction produces a rule worth stating plainly: soft-delete people, never delete their history. A contact removed from active use should stop appearing in lists and sends while the record of what happened stays intact. Hard-deleting a person destroys the evidence that they asked you to stop, which is precisely the record you would need later.
Matching: how two records become one person
Everything above depends on being able to say "this event and that event are about the same human". That is the matching problem, and the order you check identifiers in is a real decision with real consequences.
Phone first, then email. A phone number is closer to
one-per-person than an email address is. Shared inboxes, role addresses
like info@, family accounts and forwarding all break the
assumption that one address means one person. Match on the weaker
identifier first and you merge people who should have stayed separate.
The asymmetry matters because the two mistakes are not equally bad. Failing to merge leaves two records for one person: annoying, visible, fixable later by merging. Wrongly merging fuses two people's history into one record, and separating them afterwards means deciding which of two intertwined histories each event belonged to. One error is reversible. The other mostly is not.
Which is also why matching should be conservative and normalisation should be strict. Phone numbers stored in a single canonical format compare reliably; the same number written five ways does not, and a matcher that guesses at ambiguous input is guessing about somebody's identity.
Normalisation has to happen on the way in, not on the way out. If records are stored as typed and normalised at comparison time, then every future comparison has to know every historical formatting convention, and the one that gets missed produces a duplicate nobody can explain. Storing one canonical form means the rule is applied once, at the boundary, where it can be got right.
What to do when there is no identifier at all
Canvassing produces this constantly: a name, an address, a result, and no phone or email whatsoever. There are three honest options and one dishonest one.
You can create a new record and accept that it may later turn out to be a duplicate, which is recoverable. You can hold the interaction against the address rather than a person, which is accurate but limits what you can do with it. You can queue it for review, which works at small volume and stops working at large volume. What you cannot do, though systems do it, is match on name and rough locality and call it a person: that is the unrecoverable error, made automatically, at scale.
Merging, when it does happen
Duplicates are not a failure state, they are a normal consequence of conservative matching, so merging has to be a designed operation rather than an afterthought. A merge that keeps only the surviving record's events has destroyed the reason for merging. The events from both sides have to end up on one timeline, in order, with their original sources intact, and the record that went away should leave a pointer behind so that anything still referencing it resolves rather than dangling.
Ingest: getting events in without losing or doubling them
A timeline fed by several products needs a way for those products to hand over events, and that pathway has two failure modes that pull against each other.
Losing events
If the sending product waits on the timeline to confirm, then whenever the timeline is slow or down, the sending product is slow or down too. Nobody accepts that trade for analytics, so the send has to be fire-and-forget from the sender's point of view: the text goes out, the knock is recorded, and the report to the timeline happens without blocking any of it.
Doubling events
Fire-and-forget means retries, and retries mean the same event arrives more than once. The fix is idempotency: the sending product supplies its own identifier for the record, and the timeline checks whether it already holds that identifier before writing. A duplicate is dropped rather than appended.
There is a trap inside that check which is easy to get wrong and hard to notice. Those identifiers are minted by the sending product, so two different customers' events can carry the same one. If the duplicate check is not scoped per account, one account's event silently suppresses another's, and the symptom is not an error, it is history that quietly does not appear.
A useful test of any system claiming a unified timeline: ask what happens when the same event is delivered twice, and what happens when two customers generate the same upstream identifier. If nobody has an answer, the timeline is accumulating errors that nothing will ever surface.
What the events actually are
"Every interaction" is easy to say and vague enough to hide behind, so it is worth being concrete about the vocabulary. CoreCNX recognises 91 distinct event types across 15 source groups: door knocks and canvass results, SMS sent and received and opted out, chatbot sessions and captured leads, email delivered, opened, clicked, bounced and unsubscribed, appointments booked and confirmed and no-showed, donations, stage changes, tags, enrichment, imports, notes.
The number matters less than what having a defined vocabulary buys you. Each type carries its own summary template, so a timeline reads as sentences rather than as rows of JSON, and each one carries the source that produced it, so the timeline can be filtered down to a single channel when you want that and read as one story when you do not.
It also means a new source can be added without inventing a new schema. A product that can describe what happened in that vocabulary can write to the timeline, which is what makes the timeline a layer rather than another silo.
There is a design decision hidden in that vocabulary worth making deliberately: how granular an event should be. Too coarse and the timeline says "email activity" and answers nothing. Too fine and it fills with machine noise nobody reads, and the human events that matter get buried in it. The workable line is roughly anything a person would mention if they were describing what happened. "She opened it twice and clicked the donate link" is worth two entries. Every intermediate delivery state the mail server passed through is not.
The other decision is what an event carries besides its type. Two things earn their place: the source, so the timeline can be read per channel, and a small payload of the specifics, so the summary can say which link was clicked or what the door result was rather than just that a door was knocked. Beyond that, extra fields tend to be added for one report and then never removed.
Data quality: a timeline is only as good as its identifiers
Matching depends on identifiers, so contact data quality is not a separate housekeeping task, it is load-bearing. A record with no phone number cannot be matched on phone, so the next interaction with that person starts a second record and the timeline splits in two.
That is the real argument for enrichment, and it is a different argument from the usual one. Appending a missing mobile number is not about having more data to sell into. It is about the record being joinable, so that tomorrow's text reply lands on the same person as today's door knock.
The same is true of the compliance-shaped work. Scrubbing against do-not-call lists and verifying an address before you send are usually filed under risk, but they are also timeline hygiene: an unverified address that hard-bounces teaches you nothing about the person, and a number you should not have called produces an interaction you would rather not have on the record.
It is worth knowing the shape of the costs, because they are not uniform and the cheap checks are the ones most often skipped. Verifying an email address before sending and scrubbing a number against a do-not-call list are the least expensive operations of the set, by roughly an order of magnitude against appending a missing mobile number. The economics point the same way as the judgement does: the checks that stop you contacting somebody you should not are the ones you can afford to run on everything.
None of which is a reason to enrich indiscriminately. Appending data to records nobody will ever contact is spending money to make a list larger rather than more usable. The useful question before any enrichment run is not "what is missing" but "what would I do differently if I had it", and a field that fails that test is not worth buying.
Building one: a practical order
Before you connect anything
- Decide the canonical identifier and normalise to it. Phone in one format, everywhere, on the way in. Not on the way out.
- Decide the match order and write it down. Phone, then email, then create. The order is a policy, not an implementation detail, and it should survive whoever wrote it leaving.
- Separate attributes from events before there is any data to migrate. Retrofitting that distinction means deciding, per field, what its history was supposed to be.
- Agree what a duplicate is and how one is merged, so that the first inevitable duplicate is a routine fix and not a discussion.
As you connect each source
- Make the sender non-blocking. No product should get slower because the timeline did.
- Give every event a stable upstream identifier and check it before writing, scoped to the account it belongs to.
- Map the source's actions to the event vocabulary rather than inventing per-source shapes.
- Backfill deliberately or not at all. A partial backfill produces a timeline with a hole in the middle that looks like a quiet period, which is worse than a timeline that starts on a known date.
Once it is running
- Watch ingest, not just totals. A source that stops writing looks exactly like a source that had a quiet week, unless something is measuring per-source volume.
- Fill missing identifiers on purpose, so records stay joinable rather than splitting on the next interaction.
- Never delete history. Retire people, keep what happened.
Common questions
Is this just a CRM?
A CRM is usually organised around a pipeline: the question it answers best is "where has this deal got to". A timeline is organised around a person and answers "what has happened with them". Most CRMs contain a timeline of sorts, limited to the interactions that CRM produced, which is fine until interactions start happening elsewhere. If everything your organisation does happens inside one tool, that tool's own history is enough.
Do we need several products for this to be worth it?
No, though it is more obviously worth it with several. Even a single team produces email sends, notes, tasks, imports and stage changes, which are already several sources with different shapes. The timeline is what keeps them in one order instead of in five tabs.
What about people who exist in two systems with different names?
They will match if they share a phone number or an email address, and they will not if they share neither. That is the honest answer. Name matching is tempting and it is how records get wrongly merged: two people with a common name and no shared identifier are two people, and a system that guesses otherwise is making an unrecoverable decision on thin evidence.
How far back should the timeline go?
As far back as you have data you trust the provenance of. Importing an old list with invented timestamps produces a confident-looking history that is fiction, and every later decision is made against it. A timeline that starts on the day you started is more useful than one that starts earlier and is partly made up.
See it with real events on it
CoreCNX is the contact intelligence layer for the CNX Suite: door knocks from Beacon, texts from CampaignCNX+, chatbot conversations from Alma and email all writing to one record per person. It also works on its own.