InAir's Latest Insights on Airtable

Why Your Integrations Create Duplicates: Matching Records by Name vs. by ID

Written by Julia Eboli | Nov 6, 2026, 6:52:55 PM

 

Two systems can run a sync between them flawlessly for months and still slowly poison your database with duplicates. Not because the connection breaks, but because of a quieter disagreement underneath: the two systems can't reliably agree on which record they're both talking about.

That sounds like it should be the easy part. A customer is a customer. But the way badly-designed integrations decide “is this the same record I already have?” is far more fragile than anyone assumes, and when it fails, it doesn't throw an error. It creates a second copy and moves on. This is the identity problem, and it sits one level below the field-ownership question: before you can argue about who owns a field, both systems have to agree they're even looking at the same record.

 

How a Missed Match Becomes a Duplicate

 

Here's the mechanism. An integration receives an incoming record, say a contact from your CRM, and before creating it in Airtable, it searches for a matching existing record. If it finds one, it updates. If it doesn't, it creates.

The failure lives entirely in that search step. A fragile integration matches on something human-readable: a name, an email. And human-readable values are unstable by nature. As one guide on preventing duplicate records puts it plainly, names change, people mistype, and different apps format strings differently. “Acme Corp” and “Acme Corp ” with a trailing space are, to an exact-match search, two entirely different things. So the search for the existing record fails, the integration concludes no match exists, and it dutifully creates a brand new record for a customer you already had.

Now you have two Acme Corps. The next update picks one of them, maybe not the same one a human was looking at yesterday. Your record count creeps upward, your reporting splits across phantom copies, and nothing anywhere logged an error, because from the integration's point of view, nothing went wrong. It was told to find or create, it couldn't find, so it created. Exactly as configured.

 

It's a Configuration Choice, Not an Accident

 

This part is worth being precise about, because it's easy to blame the tool and miss the real cause. Duplicates don't appear because integrations are inherently broken. They appear because of one specific setting.

By default, an integration is usually configured to find and update: locate a matching record, and if none exists, skip it. The duplicate problem shows up specifically when a builder switches the behavior to find or create, a simple checkbox in tools like Zapier and Make. It usually gets enabled out of convenience, on the reasonable-sounding assumption that if a CRM contact has no match in Airtable, it must be new and should be added. That single checkbox is what converts a harmless missed match into a silently created duplicate. Without it, a failed match just does nothing. With it, a failed match manufactures a copy.

So the duplicate problem is really two mistakes stacked: matching on an unstable value, and telling the system to create whenever that unstable match fails.

 

The Fix: Match on an Immutable ID, Create with a Separate Workflow

 

The durable solution is to stop matching on anything a human can retype. Every entity that moves between systems should carry an immutable ID: a value assigned once, never edited, and never reused. Match against that, and the whole failure mode disappears, because the thing you're matching on can no longer drift.

The established best practice, straight from guidance on stopping Zapier duplicates, is an ID-first search with name as a fallback: search by the stable ID first, and only fall back to name-based matching when you genuinely have to. Name matching is the backup plan. ID matching is the long-term fix. The two should live in separate steps, not one overloaded search trying to do both at once.

There's a second half to the fix that matters just as much, and it's the one people skip. Matching on an ID is only half of it. You also want to split updating and creating into separate, deliberate flows rather than leaning on a single “find or create” action to guess which one is appropriate. One flow finds an existing record by ID and updates it. A different flow handles genuinely new records, and, critically, ...writes the newly assigned ID back into both systems so the next sync can match on it. When the two are separate, “create” only ever runs when you actually intended a creation, not as the silent default that fires every time a match fails.

If you want to harden it further for a production environment, two additions earn their keep. A failed match should go to a quarantine (a holding area for a human to inspect) instead of silently dropping, so an unexpected non-match becomes something you see rather than something that just happens. And an audit log of every create, update, and rejected match gives you a trail to follow when a number looks wrong, instead of guessing. Both are standard defensive-integration practice, and both exist to make the invisible failure visible.

 

Why This Compounds Quietly

 

The reason duplicate drift is so corrosive is the same reason the field-collision problem was: it produces no error and no signal. A duplicate isn't a broken record. It's a perfectly valid record that simply shouldn't exist. Nothing flags it because nothing is technically wrong with it. It just quietly fractures your source of truth into two, then three, then more, each update landing on whichever copy the last match happened to pick.

And it interacts badly with everything upstream and down. Once you have two copies of a customer, the ownership map from the field-level discussion is now being applied to two different records that both claim to be the same customer, and the systems writing to them have no idea they've diverged. Identity resolution isn't a nice-to-have layered on top of a good integration. It's the floor the whole thing stands on.

 

Give Every Record One Name That Can't Drift

 

The cleanest integrations share a single discipline: every entity that crosses a system boundary has one immutable ID, every match runs against that ID first, and creating a new record is always a deliberate act, never an accidental fallback. The ID doesn't have to be some cryptic machine string, either. What matters is that it's stable and unique, not that it's unreadable. An invoice number like INV-0026 is a perfect example: unique across every system, impossible to mistype into a collision, and still readable enough that a human can identify the exact record when they're processing it. Do that, and duplicates stop being a recurring cleanup chore and become something the architecture simply doesn't produce.

Building that identity layer across a live multi-system environment, assigning stable IDs, rewiring matches to run against them, and separating create from update so nothing manufactures copies in the dark, is exactly the kind of work InAir does. We turn integrations that quietly multiply your records into ones that hold a single, trustworthy version of every entity. Schedule a Discovery Call with InAir to stop your syncs from duplicating the truth.