Clay logo, go to homepage

Clay GTM guide

How to Enrich Salesforce Records with Verified Data

Enriching Salesforce is not a one-time import. It is a loop that runs on a schedule, verifies every value before it touches a record, and only writes data it has actually checked.

May 27, 202610 min read

Enriching Salesforce is not a one-time import. It is a loop.

A Salesforce record starts decaying the moment it is saved. People change jobs, companies move, headcounts grow, phone lines get reassigned. Roughly 3 to 5 percent of CRM records go stale every month, so a database left alone for a year is wrong about a third of the time. Most teams treat enrichment as a project: buy a vendor, run one backfill, declare victory. Two quarters later the fields are stale again and reps stop trusting the data enough to act on it.

The teams that win run enrichment on a schedule, verify every value before it touches a record, and only write data they have actually checked. This is how to build that loop in Salesforce.

What you need before you start:

  • A Clay account connected to your Salesforce instance: Ideally with a sandbox alongside production.
  • Admin or RevOps permissions: Enough access to map fields and add a custom field or two.
  • A short list of the fields that matter: The ones that actually change who a rep calls and what they say. Enrich those. Skip the rest, because every field you enrich spends credits.

Step 1: Pull the right Salesforce records into Clay

Start narrow, not with the whole org.

Clay's native Salesforce integration imports objects directly, with no CSV exports that go stale the day you run them. You authenticate once (a Salesforce user signs in via OAuth, or you use client-credentials for a server-to-server connection), then pull Leads, Contacts, Accounts, or Opportunities into a Clay table. If security is a concern, connect through a restricted Salesforce user with field-level limits: it can still write approved enrichment back without exposing your whole CRM. When you need a precise slice, a Salesforce SOQL source lets you query exactly the records you want.

The instinct is to import everything. Resist it. Build a filtered Salesforce view first, accounts in an active deal, contacts missing a verified email, leads from last quarter with a blank company size, and import that view, not the database. Carry over the Salesforce Record ID on every row. It is the key that lets you write enriched values back to the exact right record later, with no ambiguity about which Jordan Lee at which account you mean.

Step 2: Find which fields are empty, and which are quietly wrong

A blank field is an honest problem. A field that looks full but is three years out of date is the expensive one.

The decay is invisible until someone measures it: years of records that nobody has touched since the day they were entered, with lead routing, scoring, and ad audiences all quietly inheriting the drift. So measure it before you enrich anything. Profile the records you imported and separate true gaps from silent decay, because the two need different treatment.

Auto-plays one accurate record decaying over 18 months. Click any month to pause and see what changed.

Salesforce contact

Jordan Lee

5/5

Fields still accurate

0%

Record decay

TitleSenior PMM
accurate
Employees210
accurate
CompanyNorthwind
accurate
Verified emailjordan@northwind.com
accurate
Direct phone+1 415 555 0142
accurate
Month 0Month 0Month 18
Monthly decay rate

A Salesforce record is not static data; it decays on a predictable schedule, and the field that mattered most is usually the one that went wrong without anyone noticing.

The pattern sets your priorities. Time-sensitive fields like title, employer, and phone need frequent refresh. Slow-moving firmographics like founding year, industry, and HQ city can be enriched once and left alone. Enrich on each field's real decay rate, not on one calendar reminder.

Step 3: Waterfall-enrich the gaps with verified data

One provider is a coverage ceiling. A waterfall is how you get past it.

No single vendor has every contact and every firmographic. The provider that nails North American work emails may be blind in EMEA; the one with deep firmographics may carry no direct dials. A waterfall checks the cheapest, highest-hit provider first, and only falls through to the next when the first returns nothing, until a field fills or the chain runs out. You pay for the provider that delivers, not the ones that whiffed.

Auto-runs a cheapest-first work-email waterfall to 91% where one provider stalls at 58%. Click a provider to inspect it.

Field: Verified work email · 1,000 contacts
Cumulative coverage0%
Found (0%) Verified & usable (0%)
1
Findymailruns against 1,000 · fills 580
2
Prospeoruns against 420 · fills 172
3
Hunterruns against 248 · fills 82
4
Dropcontactruns against 166 · fills 46

Stacking providers cheapest-first lifts usable coverage far past any single vendor's ceiling while billing each provider only against the records the one before it missed. Providers and ordering reflect Clay's North America work-email data-test; order your own chain to your segment.

That coverage lift is the difference a waterfall makes against a single incumbent vendor.

88%

share of its data gap Hex filled with Clay's waterfall, versus its previous single enrichment vendor

Read the full story

For the gaps a provider database cannot fill, the company-specific facts that decide your deals, point an AI research agent at the record. Claygent reads the open web and returns a structured value you can write to a field: whether an account runs the platform your product integrates with, whether they just opened an office in a territory you cover, whether they posted a role that signals the project you solve.

Claygent prompt — fill a missing Salesforce field from the open web
Company: {{Account Name}}Domain: {{Website}}Research this company using its website, recent press, and publicjob postings. Return ONLY a JSON object, no prose:{  "employee_count_estimate": <integer or null>,  "primary_industry": "<one of: SaaS, Fintech, Healthcare, Manufacturing, Other>",  "uses_salesforce": <true | false | null>,  "recent_funding": "<round and date, or null>",  "evidence_url": "<the single URL that best supports the above>"}If a value cannot be confirmed from a credible source, return nullfor that key. Do not guess. Do not infer headcount from followercounts or unrelated pages.

The "return null, do not guess" instruction is the load-bearing part. An enrichment that admits it does not know is worth more than one that confidently invents a number you then write into your record of truth.

Step 4: Verify before you write anything back

Coverage is not the same as usable coverage. The gap between them is bad data.

A found email is a string. A verified email is a string an inbox will actually accept. Write the unverified version into Salesforce and the first three bounces teach reps to double-check every field by hand, which defeats the entire point of enriching. The fix is not more data. It is a single gate that decides what is true before anything reaches the record.

Auto-runs four enriched values through the gate. Click any card to see why it wrote, held, or went to review.

Trust mode
On conflict, trust wins in order:rep-verifiedenrichment 90+ confidenceenrichment 70-89form-submitted

Incoming for Jordan Lee

Email: jordan@northwind.com

deliverabilityvalid mailbox

Write
Phone: +1 415 555 0142

line statusdisconnected, number reassigned

Hold
Title: Director of PMM

conflict vs stored 'Senior PMM'job-change detected

Human review
Employees: 480

confidencehigh

Write

Written: 2 · Held: 1 · Review: 1

The gate's job is to write fewer values, not more: a verified, high-confidence value updates the record, while a failed or conflicting one is held so it never overwrites something a rep trusts.

Encode that trust hierarchy in your write logic so a high-confidence enrichment never clobbers a rep-verified value, and exclude manually maintained fields, deal notes, custom scores, relationship context, from automated updates entirely. Overwriting a rep's institutional knowledge with a vendor's guess is the fastest way to kill adoption.

Step 5: Write clean values back without creating duplicates

The write-back is where good intentions create messes, so use the right action for what you hold.

Because you imported records carrying their Salesforce Record ID, the correct write is the Update record action, which takes the Record ID as its key and lands on that exact record. Turn on Ignore blank values so a missing enrichment never wipes a field that already has data. You will not create duplicates, because you are updating a known record rather than creating one. Two related actions cover the other cases: Create record, which Clay configures to prevent duplicates by default, for net-new rows; and Upsert, which creates-or-updates in one step but requires an external ID on the object, for when you key on your own identifier instead of the Salesforce Record ID.

Auto-maps fields, then shows why matching on the Record ID prevents duplicates. Click a row to inspect its write behavior.

Verified emailEmailUpdate if changed
Direct phonePhoneUpdate if changed
Employee countNumberOfEmployeesUpdate if changed
IndustryIndustry__cUpdate if changed
Last enrichment dateLast_Enrichment_Date__cUpdate always
Salesforce Record IDIdMatch key (Update record)
Account Owner NotesProtected · excluded from sync
Matched on Id: writes to the existing record. 0 duplicates created.

Updating on the Salesforce Record ID lands every enriched value on the exact existing record with zero duplicates, while Create prevents duplicates by default and Upsert is the path only when you key on an external ID.

Test the whole mapping against your Salesforce Test Env sandbox before it touches production. A sandbox mirrors your setup against throwaway data, so you can confirm the right fields update on the right records first. Treat the first production run like a release, not an experiment, because a Salesforce write cannot be undone.

Step 6: Put the loop on a schedule so the data stays fresh

A one-time backfill is a snapshot of a moving target. The schedule is what makes enrichment hold.

The mechanism is a Salesforce list that maintains itself. Add a custom field, Last Enrichment Date, and build a dynamic list filtered to records where that date is older than your chosen window. Records aging past the window join the list on their own; records you just refreshed drop off on their own. Clay imports that list on a schedule, runs the same waterfall-and-verify workflow, writes the verified values back, and stamps the date so each record leaves the queue until its next cycle. Nobody has to remember to run anything.

Scope the refresh, because credits follow the work. Every enrichment spends Actions for the orchestration on each row, and provider results spend Data Credits, so contacts in active deals and target accounts earn a tighter window than closed-lost or do-not-contact records, which you can exclude from the loop entirely. That scoping is the difference between an enrichment project and an enrichment engine: the project ends, the engine keeps the database honest.

Clay has become the orchestration layer for everything GTM. Salesforce for record-keeping, Snowflake for product data, and Clay for turning it all into automated action.

When the loop runs, coverage climbs and stays climbed instead of sliding back.

80%+

enrichment coverage Vanta holds across its CRM contacts after moving to Clay's continuous waterfall

Read the full story

Common failure modes, and how to avoid them

Most enrichment loops fail in predictable ways. Watch for these.

  • Enriching everything instead of what reps use: Importing the whole org and filling every field spends credits on data nobody acts on. Filter the Salesforce view before the import, and enrich only the fields that change who gets called and what gets said.
  • Writing unverified values straight to Salesforce: A found email that bounces costs more than a blank one, because it trains reps to distrust the whole CRM. Route every value through the verify gate first, and hold anything that fails or conflicts.
  • Overwriting rep-verified and manually maintained fields: A vendor guess that silently replaces a rep's deal notes or a corrected title destroys trust fast. Encode a trust hierarchy and exclude manually maintained fields from automated updates.
  • Using the wrong write action: A repeated Create with no match logic is how duplicates appear. For records you imported, use Update record keyed on the Salesforce Record ID; reach for Upsert only when you key on an external ID. Turn on Ignore blank values so empty enrichments never overwrite good data.
  • Running it once and calling it done: A backfill decays at 3 to 5 percent a month. Without the dynamic list and the scheduled refresh, you are back to stale data within two quarters. The loop, not the backfill, is the deliverable.

Build a Salesforce enrichment loop that keeps itself current

Pull records, waterfall-enrich the gaps, verify, and write clean data back on a schedule.

Frequently asked questions

How do I enrich Salesforce records with verified data without overwriting good values?

Route every enriched value through a verification step before it writes, and encode a trust hierarchy so a high-confidence enrichment never clobbers a rep-verified or manually maintained field. In Clay you run conditional logic so a field updates only when the new value passes deliverability or confidence checks and outranks what is already there, and you enable Ignore blank values so an empty result never wipes existing data. Anything that fails or conflicts is held for review.

Which Salesforce write action should I use to avoid duplicates?

For records you imported with their Salesforce Record ID, use the Update record action keyed on that Record ID. It lands on the exact existing record, so re-running the workflow refreshes data instead of duplicating it. Use Create record (which Clay configures to prevent duplicates by default) for net-new rows, and Upsert only when you match on an external ID rather than the Salesforce Record ID.

Should I enrich Salesforce records on creation or on a schedule?

Both, for different fields. Enrich on creation for the contact and firmographic data a rep needs immediately to qualify and route a new lead. Schedule a recurring refresh for fields that decay, like title, employer, and phone, since roughly 3 to 5 percent of records go stale every month. A dynamic Salesforce list filtered on a Last Enrichment Date field lets records queue themselves for refresh automatically.

How much can multi-provider enrichment improve Salesforce coverage?

A single vendor caps out at its own database coverage. Stacking providers in a waterfall, checking the next source only when the previous one comes up empty, lifts usable coverage well past any one vendor's ceiling while billing each provider only against the records the one before it missed. Hex filled 88 percent of its data gap this way versus its previous single vendor.

Can I test Salesforce enrichment before it touches production?

Yes. Connect your sandbox as a Salesforce Test Env under Settings, then run the full mapping and write against throwaway data first to confirm the right fields update on the right records. This matters because a Salesforce write from Clay cannot be undone, so the sandbox run is your safety check before the first production write.