Someone got in touch twice, and now they are in the database twice at both levels: two contacts with the same number, and two deals, each holding its own half of the history. The manager opens one record and cannot see that the customer was turned down a month ago. The report counts two people where there is one, and conversion looks lower than it is.
Most CRMs have a “merge duplicates” feature of their own. The problem is not that it is bad. It is that it solves the easier half of the job and ignores the fact that contacts and deals duplicate in different ways.
#How a duplicate contact differs from a duplicate deal
A contact is a person. If the same number and the same email are written into two records, that is always an error: one person should be one record. The only question here is how to merge them cleanly.
A deal is an enquiry. The same customer may well have bought three times — those are three genuine deals, and folding them into one is wrong. A duplicate deal is when one enquiry has split into two records: the bot logged the enquiry, and a minute later the form logged the same one again; a manager entered a deal by hand without seeing that the integration had already entered its own.
So the rules differ too. Contacts can be checked across the whole database, all the way back. For deals, a matching phone number means nothing on its own — you need a rule that tells a repeat purchase from a duplicate. Ours is the pair “same pipeline + a short gap in time”; where you draw that line depends on how often your customers really come back.
#Why contacts come first and deals second
A deal hangs off a contact. As long as the person lives in two records, every integration — the bot, the form, the phone system — attaches new deals to “its” one of the two, and the pair keeps drifting further apart. Merge the deals and leave the contacts alone, and a week later new duplicates turn up in the same place.
The order is fixed: first “one person, one record”, then a pass through that person’s deals. Once the contacts are merged, some of the duplicate deals surface on their own — they end up side by side in one record, where you can see them.
#What to move into the master record
Finding duplicates comes down to a match on phone or email, and that part is easy. The hard part comes next: the two records hold different data, and the question is not which one to keep but how to lose nothing from either.
For a contact that means at least: every phone number and email (the second number becomes an additional one rather than disappearing), tags, subscriptions, comments and the assigned manager.
For a deal, here is what sits in the second record and what we move into the master:
| What we move | Why it matters |
|---|---|
| Comments | Half the context of a deal lives in the managers’ notes, not in the fields |
| Attributes | Source, campaign, any custom fields |
| Contacts | One deal may carry a phone number, the other an email |
| Tasks | Scheduled calls and reminders vanish along with the duplicate |
| Calls | The communication history |
| Files | Contracts, invoices, screenshots |
| Deadline and amount | Otherwise the totals in the reports will not add up |
The master is the oldest record, not the newest. For contacts and for deals alike, that keeps the real date of the first enquiry — and the funnel report stays correct with it.
#Why one trigger is not enough
Running the check on the “record created” event looks like the logical choice. But at that exact moment the record often has neither a phone number nor an email — those get filled in by the bot, by a manager or by the next form, minutes or days later.
This happens regularly: a deal arrives with no contact details at all, there is nothing to match on, and the built-in merge does not see it either. Its pair, meanwhile, may have been sitting in the database for a week.
So there are three triggers:
- the “record created” event — catches the obvious cases straight away;
- an hourly check of recent records — catches “the number was added the same day”, and costs little;
- a full scan every few hours — catches “the number was added a week later”.
#How to match on a phone number
There is a mistake hiding here, and it leaves the matching either finding nothing or finding too much.
Start by checking how your CRM searches by phone number. Some systems normalise the number before the search; some search by substring — effectively a LIKE over the digits. In the second case:
+380 67 123 45 67and380671234567are different strings, and the search will not connect them;- and a substring gives you false matches: a search for
client@example.comalso turns upxclient@example.com.
That is why the group key is the last nine digits of the number. The country code, the plus sign and the spaces stop mattering. Every candidate you find has to be checked a second time: pull its contact details and keep it in the group only if the number really does end that way, or the email is exactly the same.
A contact can have several phone numbers, so you have to compare every one against every one, not “primary against primary”: a duplicate appears precisely when the number is first in one record and additional in the other.
Groups matched by phone and groups matched by email have to be merged into one. Otherwise the same person is folded into two different masters, and part of the data lands in the wrong record. The chain record 1 — phone — record 2 — email — record 3 is merged whole: all three into the oldest.
#When a duplicate must not be deleted
Deletion has to be a separate step, not part of one shared list of operations. If moving the comments failed and the DELETE sits at the end of that same list, it will run anyway — and the data is gone.
The order should be:
- run all the transfers;
- check the statuses: if even one operation failed, leave the duplicate alone entirely;
- delete only the duplicates that everything moved out of cleanly.
Contacts need care of their own: if the CRM is wired to a messenger, the record may be holding a conversation. Before you delete a duplicate contact, try one pair and see what happens to the chat history — it should move into the master, not disappear.
You test the safeguard the same way you test the transfers: point one of the steps at an address you know is broken, then check that the duplicates are still intact and that a line about the error showed up in the report.
#Does any of this depend on the CRM
The logic does not depend on the product — only the endpoints and the field names change. One thing to check before you start: whether the API gives access to comments, tasks and files, not only to the fields of the record. If it does not, automatic merging will lose exactly the thing it is being built for.
#Takeaways
- A duplicate contact is always an error; a duplicate deal only when one enquiry split into two records.
- The order is fixed: contacts first, then deals — otherwise the duplicate deals keep coming back.
- The master is the oldest record, so the real date of the first enquiry survives.
- Everything has to move, comments, tasks and files included.
- One trigger is not enough: the phone number is often added after the record is created.
- If the phone search works by substring, you need the last nine digits and a second check on every candidate; on contacts, compare every number against every number.
- Deletion is a separate step, after the transfers have succeeded. A duplicate with a payment on it stays until you are sure the payment can be moved.
#Common questions
#Is the CRM’s built-in duplicate merge enough?
For simple cases, yes — but check what it actually moves first. Every system folds the fields together; not every one carries comments, tasks and files across, and that is where the context is. If the communication history matters to you and the built-in merge does not keep it, you need something separate.
#Can contacts be merged fully automatically?
Mostly yes, as long as you only merge pairs with more than one match — phone and email, say, or phone and the same name. Leave pairs that share only a number for manual review: one number can belong to two different people.
#What if both deals have payments on them?
Check whether your CRM has a method for moving a payment. If it does, move it along with everything else. If not, pairs like that are not merged automatically: they get flagged and sorted out by hand.
#How often should the check run?
Every hour, check the records from the last twenty-four hours; every few hours, run a full scan. The first catches fresh duplicates cheaply; the second catches the ones where the contact details showed up later.