# How to stop duplicate contacts in your CRM

> Duplicate contacts split a customer’s history and cause double follow-ups. Why they happen, how upsert and matching rules stop them, and how to clean up.

Source: https://roughfigure.com/blog/stop-duplicate-contacts-in-your-crm (updated 2026-11-11)

To stop duplicate contacts in your CRM, make every tool that adds people **look them up first** (by email, then phone) and update the person it finds. In API terms that’s an **upsert**: update if they exist, insert if they don’t. Then switch on your CRM’s duplicate settings and merge the duplicates you already have.

## Why duplicates happen

- **Customers enquire twice.** Once for a fence, then again for a gate, or the same request from a phone and a laptop.
- **Integrations “create” instead of “upsert”.** Every lead becomes a new contact.
- **Retries.** A connection times out, tries again, and the first attempt had actually worked.
- **Several tools add people.** Your website, Facebook lead forms and your newsletter each add their own copy.
- **Different details.** `sophie@` vs `Sophie@`, or a phone with and without `+44`.

## What upsert looks like in popular CRMs

| CRM            | How to avoid duplicates                                                                                |
| -------------- | ------------------------------------------------------------------------------------------------------ |
| HubSpot        | Batch upsert with `idProperty: email` ([guide](https://roughfigure.com/blog/send-website-leads-to-hubspot))                   |
| HighLevel      | `contacts/upsert`, plus **Allow Duplicate Contact** off ([guide](https://roughfigure.com/blog/send-leads-to-gohighlevel-api)) |
| Pipedrive      | Search persons by exact email, then create ([guide](https://roughfigure.com/blog/add-leads-to-pipedrive-leads-inbox))         |
| ActiveCampaign | `contact/sync` ([guide](https://roughfigure.com/blog/add-contacts-to-activecampaign-from-your-website))                       |
| Freshsales     | `contacts/upsert` with `unique_identifier` ([guide](https://roughfigure.com/blog/send-leads-to-freshsales))                   |
| Mailchimp      | Add, and treat “Member Exists” as done ([guide](https://roughfigure.com/blog/add-website-leads-to-mailchimp))                 |

## Tidy the data before it arrives

- **Lowercase emails** and trim spaces.
- **Store phones in international format** (`+447700900123`), so `07700 900123` and `+44 7700 900123` match.
- **Make retries safe.** Use upsert, or search again before creating, and give each delivery an ID the receiver can ignore if it’s seen it.

## Cleaning up the duplicates you already have

1. Use your CRM’s duplicate tool (HubSpot’s **Manage duplicates**, Pipedrive’s **Merge duplicates**, and similar elsewhere).
2. Merge so the oldest record survives, keeping its history and notes.
3. Fix the source: find which tool made the duplicates and switch it to upsert.

## Doing it in RoughFigure

In RoughFigure we’ve built every CRM connection to avoid duplicates. HubSpot, ActiveCampaign, Freshsales and HighLevel are upserted by email, Pipedrive looks the person up before adding them, and our newsletter connections never resubscribe someone who left. Retries reuse the same delivery, so a timeout can’t make a second copy. Connect yours with a click under **Integrations**. [See every integration](https://roughfigure.com/integrations).

## Questions

### Should I match on email or phone?

Email first: it’s the most reliable. Phone is a good second check, as long as numbers are stored the same way.

### Do duplicates cost money?

Often. Many CRMs and email tools price by contact count, and duplicates also mean two people chasing one customer.

### Can I stop customers from enquiring twice?

No, and you don’t want to. Just make sure the second enquiry updates the same person, with a note of what’s new.
