A CRM is never clean once. It decays the day you stop touching it. The reason is not your reps or your import process. It is the world moving. People change jobs, companies relocate, two accounts merge under a new name, and the contact who championed your last deal leaves for a competitor. None of that shows up as a blank field. It shows up as a field that still looks full and is now wrong, which is the expensive kind. The win is not a one-time cleanup; it is a maintenance loop that runs on its own, detects decay, and refreshes the records that rotted before a rep opens them. That loop sits on top of HubSpot or Salesforce without changing your system of record. This is how to build it.
What you need before you start
- A connected CRM.: A Clay account connected to your CRM through the native HubSpot or Salesforce integration, not CSV exports, which go stale the moment you run them.
- A filterable refresh-date field.: A custom field your CRM can filter on, named something like Last Enrichment Date, that Clay will stamp. This is different from the built-in Last Modified Date.
- A LinkedIn URL on every record.: The job-change monitor matches on each contact's LinkedIn URL, not on a CRM ID, so the URL has to be stored on the record.
- A shortlist of fast-decaying fields.: The fields that change who gets called and what gets said: title, employer, direct phone, email, headcount. Those are worth a refresh schedule. Slow-moving firmographics like founding year can be enriched once and left alone.
This guide is about the recurring freshness loop. Filling fields that have never had a value is net-new enrichment, covered in the guide to enriching Salesforce records. Reconciling fields that disagree with each other is standardization, covered in the guide to cleaning and standardizing CRM data. Here, the records are already in your CRM and already had good values. The job is keeping those values true over time.
Step 1: Measure how fast your CRM is actually decaying
Decay is not a vague worry; it is a rate you can put a number on, and the number decides your whole cadence.
Roughly a third of B2B contact data goes stale in a year as people move and companies change shape. The average is a trap, because decay is not evenly spread. Title and employer rot fastest. Direct phone follows when a number gets reassigned. Industry, HQ city, and founding year barely move. Refresh everything on one calendar reminder and you overspend on the slow fields while under-refreshing the fast ones. Before you build anything, profile your records and sort each field by how quickly it loses accuracy, not by how empty it looks today.
Play 12 months forward and watch which fields rot first
Priya Nair, Head of RevOps at Brightwave
Founding year, HQ city, and industry move rarely and can be enriched once and left alone. The blanks were never the problem; the fields that still look full and have quietly gone wrong are.
Decay is not uniform, so the right refresh cadence is per-field: title and employer rot in months while firmographics barely move, and the field that goes wrong is rarely the one that goes blank.
The fields that flip red early are your high-frequency refresh list. The ones that stay green for a year get a light touch or none. Set the cadence to the field, and you spend on the fields where decay actually happens.
Step 2: Build a dynamic refresh list that fills and drains itself
A static list of records to refresh is stale the moment you save it. A dynamic list is the only version that maintains itself.
The mechanism lives in your CRM, not in a spreadsheet. Create the Last Enrichment Date custom field, then build an active or dynamic list, named something like "Contacts Due for Refresh," filtered on that field being older than your chosen window. A record that ages past the window joins the list on its own. A record Clay just refreshed gets its Last Enrichment Date stamped and drops off on its own. Nobody curates the queue, because the queue is a filter, not a file. Layer in priority so your most important records get the tightest window: contacts in active deals, high lead scores, and target accounts refresh often, while closed-lost and do-not-contact records can be excluded from the loop entirely.
Drag the refresh window and switch the priority filter to reshape the queue
Records older than the window queue themselves; records Clay just refreshed get a fresh stamp and drain out. The queue is a filter, not a file.
Last Enrichment Date is a custom Clay-stamped field, distinct from the CRM's built-in Last Modified Date.
A dynamic list filtered on a last-refresh date is self-maintaining: records queue themselves as they age in and drop off as they are refreshed, so the queue never needs hand-curating.
Clay imports that dynamic list directly through the native integration, mapping the CRM record ID, email, name, the contact's LinkedIn URL, and the Last Enrichment Date field. Two identifiers do different jobs here. The LinkedIn URL is what the job-change monitor in Step 3 matches on. The CRM record ID is what every refreshed value writes back to in Step 6, so the update lands on the exact right record.
Step 3: Monitor job changes, the single highest-value freshness signal
Of every field that decays, one is worth building the whole loop around: where your contact works.
A job change is not just a stale field to repair; it is a buying signal in disguise. When a contact moves, two things happen at once. The account they left now has a hole where your champion used to be, and the company they joined just acquired someone who already knows your product. New hires spend a large share of their budget in their first hundred days and are far more open to a meeting than an entrenched incumbent. So the move that quietly rots your email field is also the move that should trigger your warmest outreach of the quarter. Catching it by hand is the failure mode. By the time a rep notices the bounce, the window has closed.
In Clay, this is the Monitor for job changes signal: Actions, then Monitor for job changes. Point it at your table of contacts, and each contact's LinkedIn URL is the identifier it matches on. Turn on the optional Initial check to surface contacts whose current company already differs from your records, and set how often the signal runs. Each check costs 1 action plus 0.2 data credits, so the cost scales with how many contacts you monitor and how often.
Run the check and watch one job change fan out into three actions
Marcus Lee, VP Marketing at Northwind
Watched on LinkedIn URL · VP Marketing at Northwind
Run frequency
30
checks / contact / month
within a day
a move is caught
1 action + 0.2 credits
per check
Monitoring a 5,000-contact book scales cost with how many contacts you watch and how often. Hourly checks are Enterprise-only.
A tracked job change is worth more than the field it repairs: the same move updates the record, flags the account that lost a champion, and creates a warm lead at the contact's new company.
You can monitor three populations, and the choice matters. Watch the contacts inside your CRM to keep records current. Watch your past customer champions to protect revenue and follow them to their new company. Watch the open market to find net-new movers who fit your profile before they hit anyone else's list. Regency Supply built exactly this, monitoring thousands of contacts so that when one changes roles, the record updates itself and the rep gets pinged the same day.
Key contacts Regency Supply keeps current by automatically tracking job changes in Clay, so reps follow the buyer to their new company.
Read the full storyFor the contacts the monitor flags as moved, an AI research agent confirms the move and structures the result before you act on it. Point Claygent at the record to verify whether the person still works where your CRM says they do, and return a clean value you can route on.
Contact name: {{Full Name}}Stored company: {{Account Name}}Stored title: {{Title}}Using public web sources and the contact's current professional profile, determine whether this person still works at the stored company in the stored role. Return ONLY a JSON object, no prose:{ "still_at_company": <true | false | null>, "current_company": "<name, or null if unconfirmed>", "current_title": "<title, or null if unconfirmed>", "confidence": <0-100>, "evidence_url": "<the single best supporting URL>"}If you cannot confirm the current employer from a credible source, return null for current_company and set still_at_company to null. Do not guess and do not infer a move from an outdated cached page.
The "return null, do not guess" instruction is the part that protects your CRM. A confident wrong answer that overwrites a correct record is worse than no answer at all.
Step 4: Set the refresh cadence to balance freshness against credit cost
More frequent is not more correct; past a point, it is just more expensive.
Refreshing in Clay spends from two separate meters, and naming them keeps the cadence math honest. Actions cover the orchestration: each row enriched, exported, or synced costs one Action. Data Credits cover the provider results, fixed or variable by source, and you spend them only when a lookup returns data. A daily refresh on a 50,000-record book burns Actions on every row and Data Credits on every result, whether or not the field moved. A yearly refresh banks both meters and lets your fastest-decaying fields rot for months. The right answer is per-tier: tight cadence on the records and fields that decay fast and matter most, loose cadence on the slow and the low-priority, and no cadence at all on records you have excluded.
Set a cadence per tier and watch freshness move against Actions and Data Credits
Active-deal contacts
1,500 records · fast decayTarget-account contacts
4,000 records · fast decayGeneral contacts
40,000 records · medium decayClosed-lost / suppressed
8,000 records · irrelevant decay23,200
monthly Actions
12,760
monthly Data Credits
86%
blended freshness
Refresh cadence is a freshness-versus-cost tradeoff best solved per tier, because tightening the cadence on slow or low-priority records spends Actions and Data Credits without buying accuracy that matters.
Clay runs this with Scheduled sources, set on the source itself. Open the source, choose Run this source, then On a schedule, and pick Day, Week, or Month (Hour is Enterprise-only). Turn on the Update existing rows toggle so each re-run refreshes records already in the table instead of only adding new ones. If a tier's freshness rides on enrichment columns rather than the import, use Scheduled columns to re-run those columns on the same kind of clock. The dynamic list from Step 2 feeds it, the cadence here paces it, and the loop runs without anyone remembering to start it.
Step 5: Verify every refreshed value before it overwrites a good one
A refresh that overwrites a correct value with a worse one is not maintenance; it is damage.
This is the failure mode that kills trust faster than stale data ever could. Your monitor says a contact moved, but the source is a cached page from last year and the contact never left. The refresh fires, the correct employer gets replaced with an old one, and a rep emails the wrong company. The fix is a conditional run between the refreshed value and the record: the write executes only if the incoming value is fresher and more confident than what is already stored. A conditional run is Clay's "only run if" logic, so a value that conflicts or fails its check is skipped, never written silently. Vanta hit this exact wall before fixing it: multiple tools enriching the same point into the same field with no way to decide which result was true.
“Clay has helped us simplify complex workflows, eliminate redundant tools, and make smarter decisions faster. It's become a cornerstone of our RevOps strategy.”
Run the gate and watch which refreshed values overwrite and which are skipped
Marcus Lee, refreshed values arriving against the stored record
On a tie, the higher source wins
A conditional run only lets a refreshed value overwrite a stored one when it is both newer and trusted, so a stale source can never silently replace a value a rep relies on.
Encode that hierarchy in the conditional run and exclude manually maintained fields entirely. The point of the gate is to overwrite less, not more.
Step 6: Push verified updates back and stamp the refresh date
The write-back closes the loop, and one detail makes it a loop instead of a runaway.
Use Clay's update action to push the verified values back into HubSpot or Salesforce, keyed on the CRM record ID you carried in at Step 2, so the update lands on the existing record and never spawns a duplicate. Then, in the same write, stamp the Last Enrichment Date with the refresh date pulled from the enrichment metadata (right-click the enrichment to extract its last refresh date, and convert it to a date field if your CRM expects one). That stamp is what drops the record out of the dynamic refresh list until its next cycle. Skip it, and the same record re-qualifies immediately and gets re-enriched forever, quietly draining both Actions and Data Credits. For Salesforce, test the whole write in the Salesforce Test Env connection before it touches production; treat the first live run as a release, not an experiment, because writes cannot be undone.
This is the difference between an enrichment project and an enrichment engine. A project ends and the data slides back to stale. The engine keeps running, so coverage and accuracy climb and stay climbed. Figma built the continuous version of this: Salesforce stayed the system of record while Clay became the layer that keeps the contacts in it current, instead of letting them drift the way an audit first found them.
Common failure modes, and how to avoid them
Freshness loops break in predictable ways. Watch for these.
- Refreshing everything on one calendar reminder.: A single cadence overspends on slow firmographics and under-refreshes fast-decaying titles and employers. Set the cadence per field and per tier, matched to the decay rate you measured.
- Pointing the job-change monitor at the wrong field.: Monitor for job changes matches on each contact's LinkedIn URL, so a record missing that URL is invisible to the signal. Map the LinkedIn URL on import; the CRM record ID is for writing back, not for matching the move.
- Overwriting a correct value with a stale source.: A refresh that writes a cached, lower-confidence value over a rep-trusted one trains the team to distrust the CRM. Gate every refreshed value with a conditional run, and exclude manually maintained fields from automated updates.
- Forgetting to stamp the refresh date.: Without the Last Enrichment Date stamp, a record never leaves the dynamic list, gets re-enriched on every run, and burns Actions and Data Credits with nothing to show. Stamp the date in the same write-back that pushes the values.
- Treating the loop as a one-time backfill.: A backfill is a snapshot of a moving target; a third of contact data decays within a year. The dynamic list, the schedule, and the conditional-run gate, running together, are the deliverable. The loop is the product, not the cleanup.