Why is my automation creating duplicate records?
The two faults behind duplicate contacts, how to tell them apart in your run history, and why a find record step isn't enough.

Say you run a nine-person commercial cleaning firm in Sheffield. A building manager fills in the quote form at 4:12pm. By 4:13pm there are two of her in your CRM (the customer relationship management system your team works out of), both marked new, both owned by a different person. One calls her at five. The other calls at half past, with the same script.
Nobody made a mistake. The automation did what it was built to do. It just did it twice.
An automation creating duplicate records has one of two faults: the same event reached it more than once, or it failed to recognise someone it had already seen. The first is a delivery problem, because webhooks are built to retry. The second is a matching problem, and the usual fix for it, a "find record" step in front of "create record", works until two runs overlap.
Left alone it costs money rather than tidiness. A 2025 Validity survey of 602 CRM users and stakeholders found 37 percent had lost revenue as a direct result of poor data quality.
Why is my automation creating duplicate records?
Because either the event arrived twice, or your lookup searched for someone who was already there and came back empty. Both faults produce the same mess in the CRM. They need completely different fixes, so telling them apart is the whole first step.
Open the run history in whatever built the automation. Zapier calls it Zap history, Make calls it the execution history, n8n calls it executions. Then compare the timestamps on the two records.
Two runs seconds apart means a double delivery
The form, the payment processor or the CRM itself sent the same event more than once, and your automation treated each copy as a new customer. The payloads will be near-identical. Sometimes byte-identical.
One run that found nothing means a match failure
The event arrived once, your lookup searched for the person, and the search came back empty even though she was in there. Usually the key you matched on didn't line up: she enquired from facilities@ the first time and her own address the second, or someone pasted a space into the phone number.
Fix the wrong one of those two and you'll spend a week proving nothing.
Why does my webhook keep sending the same data over and over?
Because webhook delivery is at-least-once, not exactly-once. Every platform in the chain would rather send your lead twice than lose it, so a delivery that isn't acknowledged quickly gets sent again.
The numbers are published and worth knowing. HubSpot's webhooks guide states that notifications are retried up to 10 times, spread over the next 24 hours. Its error handling docs count a batch your endpoint takes longer than five seconds to answer as a timeout worth retrying. Make automatically retries incomplete executions caused by rate limit, connection and module timeout errors, using exponential backoff, capped at three retries running in parallel per scenario.
Now stack those behaviours up.
Say a 20-truck landscaping company in Tampa runs three Make scenarios that all write into one Google Sheet. Google's Sheets API, the door other software uses to read and write inside your spreadsheet, has published usage limits: 300 read and 300 write requests per minute per project, and 60 of each per user. Go past the quota and it returns a 429, the HTTP status for too many requests, which Google says to handle with exponential backoff.
Make sees a rate limit error, waits, retries. The row lands twice.
Retrying isn't the bug. It's why you still have Tuesday's lead after your form host had a bad ten seconds at 2am. What's broken is that the second delivery was allowed to create a second record.
Does a find record step before create record stop duplicates?
Mostly. Then one day it doesn't, which is worse than it never having worked, because by then you trust it.
Here's the failure. Two copies of the same event arrive 300 milliseconds apart. Run A searches the CRM for the contact and finds nothing. Run B searches 100ms later and also finds nothing, because Run A hasn't written anything yet.
Both runs conclude she's new. Both create her. The check was honest and the answer was wrong.
That's a race, and it only shows up under the conditions that matter: a busy afternoon, a retry storm, two scenarios firing at once. Which is why it passes every test you run on a quiet Tuesday and fails in week six.
Sequential processing helps. Make exposes it as the "Process data in order" setting, usually paired with a Data Store lookup right after the trigger. It narrows the window instead of closing it, and it slows the scenario down, which is a real cost at a few hundred events an hour.
The distinction worth keeping: a lookup asks a question, a constraint makes a promise.
How do I prevent a contact entering my automation twice?
Give every event a key, write that key down before you do anything else, and refuse to carry on if the key is already there. The pattern is called idempotency, meaning an operation you can run twice and get the same result as running it once.
In practice, for a no-code or low-code build:
- Derive the key from the event, not the person. The form submission ID, the invoice ID, the booking reference. Something the sending system generated and will send again unchanged on a retry.
- Write the key before any side effects. A row in a Make Data Store, an Airtable base, a Zapier Table. If that write fails because the key already exists, stop the run there.
- Enforce uniqueness at the write, not at a lookup. The store itself should reject the second insert. A duplicate key error is the signal you want, not an error to route around.
- Use upsert endpoints where the destination has one. Update if it exists, insert if it doesn't, decided inside the destination where the race can't happen. A
409 Contact already existsfrom HubSpot, 409 being the conflict response, is the outcome you want. - Keep the key log longer than the retry window. If HubSpot can retry for 24 hours, a log you clear nightly is theatre. Seven days costs nothing.

Picking a dedupe key that holds
Email is the default choice and the weakest one. Three things break it:
- Shared mailboxes, where four people enquire from one address.
- The same person using a work address one week and a personal one the next.
- A trailing space picked up from a copy and paste.
The event's own identifier is better, with one caveat worth reading twice. HubSpot's webhook field reference states that the eventId on a notification is not guaranteed to be unique, so a key built on it alone can quietly drop legitimate updates. Composite keys last longer: normalised email, plus object type, plus source form, plus the event identifier.
Matching on phone numbers? Normalise to E.164 first, the international format, so +441142961000 rather than 0114 296 1000. Two records for one person often differ by nothing more than a leading zero. Our post on the first process worth automating makes the same argument about intake generally: the shape of your data decides what you can build on top of it.
What's changing in 2027 that will break your dedupe logic
HubSpot is moving to date-based API versioning, and the dates are already published. Its v4 APIs become unsupported on 30 March 2027, with 2026-03 the current recommended version. The Pipelines API v1 sunsets on 4 December 2026. The legacy v1 OAuth endpoints, part of the standard your tools use to stay connected without holding your password, are fully deprecated on 16 February 2027.
Here's why that lands on this topic in particular. A version migration is the moment identifiers change shape, and dedupe logic built on a hard-coded ID format fails silently when they do. No error. It simply stops matching, and starts creating.
So do the boring thing this quarter. List every endpoint your automations touch, note which version each one calls, and book the migration before Q1 2027 rather than during it. If you can't produce that list today, that's the finding. The failure mode is the one we wrote about in spotting an automation that's stopped working: a system that looks fine and isn't.
When a dedupe key isn't worth building
Two cases, and we'd rather say so than sell you a build.
The first is volume. At roughly 20 leads a month through one form, a saved CRM view sorted by email and ten minutes on a Friday beats anything we'd charge you for. A dedupe store is a thing you then own and maintain. At that volume it costs more attention than it saves, and the honest answer is to come back when two people might call the same lead on the same afternoon.
The second is harder, and it's the one people skip. A strict unique key on email will merge two real customers who share a mailbox:
- A letting agent and a tenant at one property.
- A husband and wife using one address.
- Four site managers at a fit-out contractor in Dubai Investments Park, all enquiring from one
projects@account.
Merging two genuine customers into one record is worse than holding two records for one customer, because the second is visible and the first isn't. Where customers really do share contact details, a strict constraint is the wrong tool and flagging for human review is the right one.
None of this helps when the duplicates are human, either. If three people on your team type leads in by hand, or your intake has four front doors (a form, a WhatsApp number, a phone line, an inbox) each creating records on its own, a key inside one automation fixes one door. That's a routing problem before it's a code problem. Same judgement call as working out when to stop vibe coding and build the thing properly.
Start with your run history, not your CRM
Open your automation's run history, filter to the last 30 days, and count the runs whose payload matches an earlier run. Not the duplicate records in the CRM. The duplicate runs in the history. That number tells you whether you have a delivery problem or a matching problem, and you can't pick the fix before you know which.
If the count is ugly, workflow automation is what we build, dedupe keys and all. Send us the run history and the name of your CRM through our contact page, and we'll tell you which of the two faults you have before anyone talks about a project.
Common questions
Still wondering
Will my CRM's built-in duplicate management fix this?
It cleans up after the fact, which is useful, but it doesn't stop the duplicate being created or the second call being made. Most duplicate managers run on a schedule and merge on fuzzy matches, so a lead can sit twice in your pipeline for hours. Treat it as a safety net underneath a dedupe key, not as a replacement for one.
Should I just clean up duplicates manually each month?
At low volume, yes. If you take roughly 20 leads a month through a single form, a saved view sorted by email and ten minutes on a Friday is cheaper than any build. The maths changes once two people might call the same lead, or once a duplicate reaches an invoice, a contract or a payment. Then the cost stops being tidiness.
Do I need a developer to add a dedupe key to a Zap?
Not usually. Zapier Tables, a Make Data Store or an Airtable base can all hold keys, and you can enforce uniqueness in them without writing code. You need a developer when the destination offers no upsert endpoint, when you have to normalise messy identifiers before matching, or when several automations must share one key store safely.
Can two automations share the same dedupe store?
They should, if they write to the same destination. Two scenarios with separate stores can each decide a lead is new and create it twice, which puts you back where you started. Use one store, key it by event source and event ID together, and have every automation that creates records check the same table before it writes anything.


