New to Attio?Get 10% off when you sign up through Craftt.Try Attio free →
All articles

We shipped an agent that stops Attio imports from creating duplicates

·6 min read

Import a list into Attio and here is what nobody tells you. Attio's importer matches on a column you pick, and it is brutal about format. ACME LTD and Acme Ltd. are two different companies to it. Jon@x.com and jon@x.com are two different people. A trailing space is a new record. When it cannot find a match, it does not skip the row. It creates a fresh copy.

Do that a few times with market-data feeds and manual lists, and your clean workspace climbs back to tens of thousands of half-empty duplicate records. The reports stop being trustworthy. The team stops trusting the CRM.

We built an Attio deduper agent that stands in front of every import. It cleans the CSV, removes the duplicates inside it, and checks every remaining row against your live workspace, so only genuinely new, clean rows ever reach an import. It reads Attio to check, and it writes files. It never writes to your live workspace.

This post is what it produces, how it matches without dropping real prospects, how it runs, and how to put it on your workspace.

Why the importer makes duplicates

The assumption most people have is that Attio's importer de-duplicates for them. It does not, not the way they think.

It matches on one column, exactly, and format has to be perfect. Real data is never perfect. A feed from one source spells the company one way, another spells it differently, the email has a capital letter, the name is in all caps. Every one of those mismatches becomes a brand-new record that sits next to the one you already had.

The fix is to clean and check the file before it goes in, not to fight the mess afterward. That is the agent.

What it produces

Hand it a raw file, and it writes three things next to it:

OutputWhat it is
The cleaned CSVThe headline deliverable. Every genuinely new row, normalized, internal duplicates merged, columns renamed to match Attio's import headers. This is the file you import.
The needs-review CSVThe medium-confidence rows: a probable but not certain match against an existing record. A human decides. Each row carries the matched record's ID and a note explaining why, so the call is one click.
The summaryThe log. Rows in, duplicates merged, already-in-Attio dropped, new, and needs-review, plus the exact column mapping it used. Nothing is silent.

The cleaned file is what you asked for. The other two exist so that "nothing was lost" is provable, which matters when the data is going into a regulated business.

How it matches without dropping real prospects

Cleaning a list is easy to do badly. Match too loosely and you drop a real new prospect as a "duplicate." Match too tightly and the duplicates get through. The agent works in a careful order.

  1. It maps and confirms the columns. Full Name, Work Email, Firm, Country get mapped to the real Attio attributes, and it shows you the mapping before it goes further. A wrong mapping corrupts the whole run, so thirty seconds of confirmation is cheap.
  2. It normalizes every value. Emails lowercased and trimmed, company domains derived from emails, shouting names title-cased without breaking McKinsey or O'Brien, legal suffixes and country names standardized. This is what makes matching work: Jon@X.COM and jon@x.com have to collapse to the same key before anything is compared.
  3. It removes duplicates inside the file, merging each group into one row and keeping the most complete value in every field.
  4. It matches the survivors against the live workspace, exact first: an email hit for a person, a domain hit for a company. Where there is no key, it falls back to a careful search on the surname or the company's distinctive token, then judges the candidates on name, company, and location.

There is one hard rule underneath all of it. A search hit is a candidate, not a verdict. Attio search is full text, so a query can return something that merely shares a word. Before the agent ever calls a row an existing record, it confirms the actual key matches: the email is literally in that record, or the domain is literally in that record. If it cannot verify the key, the row goes to review, never to the bin. That is the line between de-duplicating and silently deleting a real lead.

Read-only, always

The agent reads from Attio to check for existing records, and it writes files. It does not create, update, or delete anything in your workspace. Loading the cleaned file into Attio is a separate, deliberate step run on its own command, so the clean-and-check stage can never accidentally write. It never overwrites a filled value with a blank, and it never drops a row as a duplicate on a weak signal.

How it runs

The deduper ships as a Claude Code skill you run on demand, whenever you have a list to import.

  • The skill is a single markdown file we install on your Claude Code. No Python runner. No Anthropic API key. No server.
  • The reader is the Attio MCP server, already connected to your Claude Code. It matches by targeted search on the unique keys, in batches, so it never pulls a whole object into context even on a feed of tens of thousands of rows.
  • The trigger is you, in Claude Code: "dedupe this CSV before I import it into Attio," with the file path. Review the three outputs, then import the cleaned file.

Your Claude Code subscription is the entire runtime. We do not host the agent and we do not see your data.

What it costs

Build. A one-time setup: the column map tuned to your workspace's attributes and your usual feed formats, and the matching thresholds set to how strict you want to be.

Run. It runs on demand on your own Claude Code, so there is no separate runtime to pay for. An optional monthly retainer if you want us handling the imports for you.

Claude Code consumption. It runs on your existing Claude Code subscription. No separate Anthropic API key, no usage-based bill from us.

Pricing is on the pricing page.

Want to set up AI agents in your Attio?

Book a call.

Start here if your workspace is filling with duplicates

Every duplicate in your CRM is a small tax. A rep works a record that is already being worked. A report double-counts. A merge has to happen by hand later. It compounds every time someone imports a list without checking it first.

The fix is not more discipline at import time. It is a step that cleans and checks the file for you, every time, and refuses to guess. If you run Attio and you import lists from more than one source, the deduper is the one to ship first.

Need help with your Attio setup?

We migrate teams, build data models, wire automations, and train Claude agents inside your workspace. Discovery call is free.

Book a free discovery call