Clay enriches the data. HubSpot stores the record of truth. The moment you connect the two with a write-back, you accept responsibility for every record Clay touches. Get the pattern wrong and you wake up to hundreds of duplicate companies, overwrites on fields your reps corrected by hand, and a CRM your ops team no longer trusts.
The fix is a decision, not a feature. You need to agree on a write-back contract before the first sync runs.
Use Clay's Lookup object action to find the HubSpot record by email or domain first. If a match exists, update it by Object ID. If no match exists, create a new record. Turn on "Ignore blank values" so empty enrichment fields never overwrite populated properties. Agree on which fields Clay owns and which HubSpot owns before the first run.
Why the duplicates happen
The root cause is simpler than most teams expect. Clay's Create object action does exactly what the name says: it creates a new record in HubSpot every time it runs, regardless of whether a matching record already exists. As Clay's mass-update guide puts it, "a Create action run across records that already exist copies every record instead of changing it."
HubSpot's API compounds the problem. The HubSpot developer documentation describes domain as the "primary unique identifier to avoid duplicate companies," but the company create endpoint does not enforce uniqueness on domain. Two API calls with the same domain produce two company records. Contacts have a batch upsert endpoint that matches on email, but companies have no equivalent.
So the duplication comes from two directions. Clay sends a Create call for a record that already exists. HubSpot accepts it without checking for a match. Neither system stops you.
The teams that avoid this problem all follow the same sequence: look up the record first, update if it exists, create only if it does not. Clay's sync guide confirms the pattern: "update keyed on record ID lands on the exact existing object and never spawns a copy."
Lookup-before-create, step by step
Clay University documents this as a four-step workflow for CRM enrichment: enrich, look up, selectively create, then update. Here is how each step works in practice.
Step 1: Enrich in Clay. Run your enrichment columns (company data, technographics, headcount, whatever your table needs) before touching HubSpot. Every field you plan to write back should already be populated or confirmed empty.
Step 2: Look up the HubSpot record. Add a Lookup object action. For companies, match on domain. For contacts, match on email. The Lookup returns the HubSpot Object ID if a match exists and returns empty if it does not. Clay's integration overview notes that domain filters on Lookup can strip subdomains, so blog.example.com still matches example.com in HubSpot.
Step 3: Create only when the Lookup returns empty. Add a Create object action with a condition: run only when the Lookup Object ID column is blank. This means Create fires exclusively for net-new records. The CRM enrichment lesson describes this as conditional logic "to only create new records if nothing was found during your Lookup phase."
Step 4: Update when the Lookup returns a match. Add an Update object action with the opposite condition: run only when the Lookup Object ID column has a value. Map the Object ID into the Update action's identifier field. Clay's enrich guide confirms that the Update action keyed on HubSpot record ID "lands on the exact existing object and never spawns a copy."
Step 5: Turn on Ignore blank values. On the Update action, confirm that Ignore blank values is toggled on (it is on by default). When enabled, blank values coming from Clay are left alone in HubSpot. When disabled, existing HubSpot values get overwritten with blanks, which is almost never what you want.
The sequence matters. Lookup before Create prevents duplicates. Update by Object ID prevents mismatches. Ignore blank values prevents data loss.
Field ownership table
Before you map a single column, your ops team and your enrichment team need to agree on which system owns each field. Without this agreement, Clay overwrites a rep's hand-corrected company name with a vendor guess, or a HubSpot workflow resets a field Clay just populated.
The principle from Clay's enrich guide applies here: "a vendor guess that replaces a rep's lifecycle notes or a corrected title destroys trust." The table below is a starting template. Adjust it to your stack.
| Field | Owner system | Clay overwrite rule |
|---|---|---|
| Company name | HubSpot | Never overwrite |
| Domain | HubSpot | Never overwrite |
| Lifecycle stage | HubSpot | Never overwrite |
| Lead status | HubSpot | Never overwrite |
| Deal stage | HubSpot | Never overwrite |
| HubSpot owner | HubSpot | Never overwrite |
| Employee count | Clay | Overwrite if blank |
| Industry | Clay | Overwrite if blank |
| LinkedIn URL | Clay | Overwrite if blank |
| Technologies used | Clay | Overwrite always |
| Funding round | Clay | Overwrite always |
| Year founded | Clay | Overwrite if blank |
| Phone number | Clay | Overwrite if blank |
| Job title | Clay | Overwrite if blank |
| City / State / Country | Clay | Overwrite if blank |
| Description | Clay | Overwrite if blank |
| Notes / Custom text fields | Rep (HubSpot) | Never overwrite |
"Overwrite if blank" means Clay writes the value only when the existing HubSpot property is empty. This is the behaviour you get when Ignore blank values is on and the Clay column has data. "Overwrite always" means Clay replaces whatever is there, which makes sense only for fields that decay quickly (technographics, headcount) and where no human ever edits the value.
For a deeper framework on who owns what across your entire CRM, our data governance guide covers ownership hygiene beyond the Clay-HubSpot boundary.
Test before the full run
Never run a write-back across your full HubSpot database on the first attempt. Clay's mass-update guide recommends testing on 10 to 25 records before scaling.
Pick a representative sample. Choose records that cover each scenario: companies that already exist in HubSpot, contacts that already exist, and a few net-new records that should be created. Include at least one record where the Lookup should match on domain and one where it should match on email.
Run the table. Execute the full Clay table (Lookup, conditional Create, conditional Update) on just the sample rows. Check HubSpot after each action, not just at the end.
Verify five things:
- Existing records were updated, not duplicated. Search HubSpot for the company domain and confirm only one record exists.
- Net-new records were created with the correct properties.
- Fields marked "never overwrite" in your ownership table were left untouched.
- Fields marked "overwrite if blank" were written only where the HubSpot property was empty.
- Ignore blank values prevented Clay from blanking out populated properties.
If any of those checks fail, fix the mapping or condition before scaling. Cleaning up 15 duplicates takes minutes. Cleaning up 1,500 takes a full CRM audit.
Associations and parent-child companies
Writing back records is only half the job. Those records need to be connected to each other in HubSpot through associations.
Clay's HubSpot integration includes a Create association action. After you create or update a contact, you can associate it with the correct company using the HubSpot Object IDs for both records. The Lookup step gives you the company's Object ID, and the Create or Update step gives you the contact's Object ID (returned in the action output).
Parent-child company hierarchies add a layer of complexity. When Clay enriches a subsidiary, the write-back needs to land on the child company record, not the parent. If the domain lookup returns the parent because both share a domain, the update overwrites the wrong record. Our guide to Clay account hierarchies and HubSpot parent-child companies walks through the mapping logic for these structures.
The common mistake is ignoring associations entirely and writing back contacts and companies as disconnected records. That leaves your reps clicking into contacts with no company attached, which defeats the purpose of enrichment.
Suppression first: GDPR opt-outs before enriching
Before any write-back runs, the table should filter out records that have opted out of data processing. This is not optional in the EU and EEA, and it is good practice everywhere.
The check is straightforward. Pull opt-out status from HubSpot during the Lookup step (include the hs_legal_basis or your custom opt-out property in the Lookup fields). Add a condition to the Update and Create actions: skip any row where the opt-out property indicates the contact has withdrawn consent.
If you are using Clay alongside Apollo or other enrichment tools, the opt-out sync gets more complex because each tool maintains its own suppression list. Our GDPR opt-out sync guide covers how to keep those lists aligned across Clay, Apollo, and HubSpot so a suppression in one system carries through to the others.
The write-back contract should include a line about suppression. If nobody has agreed on when and how opt-outs are checked, they will not be checked.
When to move the write-back into n8n
Clay's built-in HubSpot actions handle the core pattern well: lookup, create, update, associate. For a single Clay table writing back to a single HubSpot portal, the native actions are enough.
The write-back outgrows Clay when any of these conditions appear:
Multiple source systems. If Clay enriches records that also flow in from a form tool, an ad platform, or a product database, the write-back needs to reconcile inputs from several systems before deciding what to write. Clay runs one table at a time; n8n can orchestrate across sources in a single workflow. The same applies if you write back to both HubSpot and Attio from the same enrichment run.
Conditional routing. When the write-back logic includes branching (for example, route to one HubSpot portal for EMEA and another for North America, or assign different owners based on enrichment score), the conditional logic in Clay becomes hard to maintain. n8n's visual workflow builder makes branching explicit.
Scheduling and retry logic. Clay tables run when you trigger them or on a schedule, but retrying failed rows requires manual re-runs. n8n workflows can catch errors, retry individual records, and log failures to a dead-letter queue.
Audit trails. If your compliance or ops team needs a log of every write-back (what was written, when, and what the value was before the overwrite), n8n can write that log as part of the workflow. Clay's action history shows results per run, but building a persistent audit trail from it takes extra work.
For teams already using Clay and HubSpot in their go-to-market stack, we typically start with Clay-native write-back and move the pattern into n8n only when one of these triggers appears. The enrichment and lead routing guide covers how these tools connect within a broader SaaS GTM workflow, and our Clay enrichment waterfall guide explains how to sequence multiple enrichment providers before the write-back step.
The write-back contract checklist
Before the first sync runs, sit your ops team and your enrichment team in the same room (or the same doc) and agree on every item below. Print this list, work through it, and store the answers somewhere your whole revenue team can find them.
- Lookup key for companies. Domain, HubSpot Object ID, or both. Domain lookup with subdomain stripping is the default for most teams.
- Lookup key for contacts. Email is the standard. Decide whether personal emails (gmail.com, outlook.com) are valid lookup keys or should be excluded.
- Field ownership. Complete the ownership table above for every field Clay will touch. Sign off on it with the team that owns HubSpot.
- Overwrite rules. For each field, decide: never overwrite, overwrite if blank, or overwrite always.
- Ignore blank values. Confirm the toggle is on for every Update action. Document this as a rule, not a default you hope stays set.
- Suppression list. Which opt-out properties are checked before write-back, and where are they stored.
- Sample size. How many records run in the test batch. We recommend 10 to 25 per Clay's guidance.
- Verification checklist. Who checks HubSpot after the sample run, and what they are checking.
- Association rules. Which associations are created (contact-to-company, company-to-parent) and what triggers them.
- Escalation threshold. At what point does the write-back move from Clay-native actions into n8n or another orchestration tool.
- Error handling. What happens when a Lookup returns multiple matches, an Update fails, or a Create returns an error.
- Review cadence. How often the team revisits the ownership table and overwrite rules. Quarterly is a reasonable starting point.
If you are migrating to HubSpot and setting up Clay write-back at the same time, run the migration to completion before enabling any enrichment write-back. Writing back to a CRM that is still being populated creates a moving target.
FAQ
How do I stop Clay creating duplicate companies in HubSpot?
Use the Lookup object action to search HubSpot by domain before creating anything. If the Lookup returns a HubSpot Object ID, use the Update object action to write to the existing record. Use Create object only when the Lookup returns empty. This pattern is documented in Clay's CRM enrichment lesson and prevents the Create action from spawning copies of records that already exist.
Should I use Create object or Update object in Clay for HubSpot?
Both, with conditions. Use Lookup first to determine whether the record exists. Route to Update (by Object ID) when it does, and to Create when it does not. Running Create across existing records duplicates every one of them. Running Update without an Object ID fails. The Lookup step is what makes the routing possible.
How do I sync Clay enrichment back to HubSpot safely?
Follow the lookup-before-create pattern: Lookup by domain or email, Update by Object ID for existing records, Create for net-new only. Turn on Ignore blank values so empty Clay columns do not overwrite populated HubSpot fields (Clay University). Agree on a field ownership table before the first run, test on 10 to 25 records, and verify the results in HubSpot before scaling.
Which HubSpot fields should Clay be allowed to overwrite?
Fields that decay quickly and are never hand-edited by reps (employee count, technologies used, funding round) are safe for Clay to own. Fields that reps correct or that drive automation (company name, lifecycle stage, deal stage, HubSpot owner) should never be overwritten by Clay. Use the "overwrite if blank" rule for fields where Clay fills gaps but should not replace human input. Document these rules in a field ownership table and review it quarterly.
Does HubSpot automatically deduplicate companies created via the API?
No. The HubSpot developer documentation describes domain as the primary unique identifier for companies but does not enforce uniqueness on the create endpoint. Two API calls with the same domain produce two company records. Contacts have a batch upsert endpoint that matches on email, but companies have no equivalent. The only reliable way to prevent company duplicates via the API is to check for an existing record before creating a new one.
Can Clay update and create HubSpot records in the same table?
Yes. Add both a Create object action and an Update object action to the same Clay table, each with a condition tied to the Lookup result. The Create action runs when the Lookup Object ID is blank (net-new record). The Update action runs when the Lookup Object ID has a value (existing record). Clay's enrichment guide documents this as the standard write-back pattern.
Need help setting up Clay write-back? Talk to our Clay team about getting the integration right the first time.