A recruiter opens a candidate record, reaches out, and gets nothing back. The email bounces or the message goes nowhere. They move to the next record and the same thing happens.
The problem is rarely the sourcing. It is that candidate data goes stale faster than almost any other professional data, and most recruiting databases have no mechanism for noticing.
This guide covers what "verified" actually means for candidate data, which fields decay fastest, how to verify at scale without slowing recruiters down, and what accuracy to expect. It is written for recruiting leaders and for anyone building recruiting software.
What "verified" actually means
The word gets used loosely, and it matters because three different claims hide behind it.
Verified contact. The email address accepts mail or the phone number connects. This is a deliverability claim and says nothing about who owns it.
Verified employment. The person currently holds the role your record says they hold. This is the claim recruiters care about most and the one most often wrong.
Verified history. The career history in the record reflects reality, with correct employers, titles and dates.
A record can be verified in one sense and wrong in another. An email that accepts mail belonging to someone who left that company eight months ago is verified contact and unverified employment at the same time. That combination is extremely common and it is responsible for a large share of outreach that goes nowhere.
When a vendor says verified, ask which of the three they mean. Most mean the first.
Why candidate data decays faster
Recruiting databases rot faster than CRM databases, for structural reasons.
Your records are about people who move. A sales CRM holds buyers, who are a stable-ish population. A recruiting database holds candidates, and a candidate is by definition someone who changes jobs. You are maintaining records on the most mobile segment of the workforce.
Work contact details die with employment. A work email address stops working when someone leaves, often immediately. Since your records are weighted toward people who move, this hits you harder than most.
Placed candidates become stale instantly. The moment you place someone, every field in their record changes: employer, title, email, often location. The successful outcome of your own process invalidates your own data.
Records are kept for years deliberately. A candidate who was not right in 2023 may be perfect in 2026, so recruiting teams retain records far longer than other functions. That is correct practice, and it means a large share of any mature database is years old.
Published estimates put roughly 30% of professionals in a new role each year. For a candidate pool specifically, assume worse. A database untouched for two years should be assumed substantially wrong rather than slightly stale, and the general field-level decay model is in CRM data decay.
Verify the right fields
Not every field needs the same treatment, and verifying everything on the same cycle wastes most of the effort.
| Field | Decay | Verify |
|---|---|---|
| Work email | Fastest, dies on job change | Before every outreach |
| Current employer | Fast | Before outreach, and on a refresh cycle |
| Current title | Fast, changes on promotion too | Before outreach |
| Personal email | Slow | Rarely |
| Career history | Append-only, past does not change | On refresh only |
| Skills and certifications | Slow, mostly additive | Periodically |
| Location | Moderate | On refresh |
The pattern: anything tied to current employment is volatile, and anything historical is stable. Spend your verification budget on the first group.
Employment verification is the one that matters
If you verify one thing, verify that the person still works where your record says.
This single check determines whether your outreach makes sense. A message that references someone's current role at a company they left in March tells the recipient immediately that your data is stale, and a recruiter who does that twice to the same person loses them permanently.
The efficient way to do this is not to re-check every record. It is to watch for movement and refresh only what moved.
1from renidly import Renidly
2
3renidly = Renidly() # reads RENIDLY_API_KEY from the environment
4
5moves = renidly.data.job_changes.search(
6 event_type="joined",
7 days_ago=30,
8 title="software engineer",
9 geo_country_code="US",
10 limit=50,
11)If your stack is Node, the same call, with the method name following the language convention while the filter keys stay as the API defines them:
1import { Renidly } from "renidly";
2
3const renidly = new Renidly();
4
5const moves = await renidly.data.jobChanges.search({
6 event_type: "joined",
7 days_ago: 30,
8 title: "software engineer",
9 geo_country_code: "US",
10 limit: 50,
11});Three event types matter here, and recruiting is the one function that benefits from all three:
joined tells you someone started somewhere new. Their work email just changed, so any address in your record is dead, and they are also unlikely to move again soon.
left is the one recruiters should care about most. Someone who just left a role is, for a short window, far more receptive than they will be at any other time. This is the single highest-intent recruiting signal available and almost nobody monitors it systematically.
title_change indicates a promotion, which usually means they are staying put, and also that their seniority band in your record is now wrong.
The implementation detail that breaks every first version is deduplication. The endpoint returns a recency window, not a changelog, so running it daily with a thirty-day window returns the same people every day. Keep a seen-set keyed on a stable identifier with a TTL longer than your window. The full pattern is in job change signals, and the free job change detector will check a single person if you want to see the shape of it before building.
Contact verification
Once you know where someone works, you need a working address.
Two directions, depending on what you hold.
You have an address and want to know if it works:
1check = renidly.emails.verify(candidate.email)
2
3if check.deliverable and not check.catch_all:
4 send(candidate.email)You know the person and company but not the address:
1found = renidly.emails.find(
2 first_name="Jane",
3 last_name="Doe",
4 domain="northwind-logistics.com", # bare hostname, no scheme
5)Two cautions specific to recruiting.
Catch-all domains are everywhere in recruiting. Large employers, universities, hospitals and public-sector organizations disproportionately run catch-all configurations, which means the server accepts every address and verification cannot confirm the mailbox. If you recruit into those sectors, a large share of your addresses will come back unconfirmable. Treat them as a separate segment rather than as clean, and the full handling is in catch-all email domains.
A verified address can belong to someone who left. This is the combination from the opening section, and it is especially common in recruiting because mailboxes at large employers often stay open and forwarding for months. Verification plus employment confirmation is the pair that actually works. Neither alone is sufficient.
The verdict model and what each response means is in the email verification API guide, and the free email verifier checks a single address with no signup.
Refreshing a database without burning budget
Most recruiting databases are too large to refresh wholesale. Prioritize instead.
The ordering that works:
- Anyone with an active requisition match. Highest value, refresh immediately before outreach.
- Anyone flagged by a movement event. You know they changed, so the record is definitely wrong.
- Placed candidates, on their placement anniversary. You caused the change, so you know the date.
- Previously contacted candidates older than twelve months. The re-engagement pool.
- Everyone else, on a slow cycle or never. A record nobody will look at does not need to be correct.
That last line is the one that saves money. Refreshing records nobody queries is pure cost, and most mature recruiting databases contain a large tail of exactly those.
For the bulk operations, batch rather than looping:
1job = renidly.data.people.enrich_batch(ids=[c.person_id for c in cohort])
2result = job.wait()
3
4for row in result.results:
5 update_candidate(row.matched_input, row)1const job = await renidly.data.people.enrichBatch({ ids: cohort.map(c => c.personId) });
2const result = await job.wait();
3
4for (const row of result.results) await updateCandidate(row.matched_input, row);Budget on records submitted rather than records returned, because lookups that resolve nothing are still lookups. If 60% of a cohort resolves, your true cost per usable record is roughly 1.7 times the headline rate. Measure your resolution rate on a 500-record sample before sizing a full refresh. The resumability and cost-control patterns are in batch enrichment at scale.
Write rules that protect recruiter work
This is where automated refresh damages recruiting databases, and the rules are stricter here than in sales.
Never overwrite a recruiter's note or manual correction. A recruiter who spoke to the candidate last week knows more than any dataset. Flag manually entered values and require high confidence to override them.
Never let an empty result delete a populated field. If a refresh returns nothing, the existing value stands. This is usually violated by a bulk job treating null as a value.
Never silently change a field a recruiter is about to act on. If someone has an active outreach sequence against a record, queue the change for review rather than applying it mid-flight.
Log every change with its source. When a recruiter asks why a record changed, you need an answer. This also lets you audit whether refresh is improving the database or just churning it.
1def should_write(field, current, incoming, confidence) -> bool:
2 if not incoming: return False # never overwrite with nothing
3 if recruiter_edited(field): return confidence == "high"
4 if not current: return confidence in ("high", "medium")
5 if current == incoming: return False
6 return confidence == "high"The asymmetry is deliberate. Filling a gap is low risk, so medium confidence passes. Replacing something a recruiter may already have acted on requires certainty.
What accuracy to expect
Be realistic, because unrealistic expectations are why verification projects get judged as failures.
Match rate of 50% to 75% on a realistic candidate database. Senior and technical roles resolve better than junior, frontline and shift-based roles. If you recruit in hospitality, logistics or healthcare support, expect the lower end and plan for it rather than treating it as a vendor failure.
Employment accuracy in the high eighties to low nineties on matched records, with the errors concentrated in recent changes, since every provider has a detection lag.
Contact accuracy varies most, because catch-all domains make a share of it unconfirmable by anyone.
Do not take any vendor's word for these, including ours. Build a golden set: take 100 candidates where you know the truth, because you spoke to them or placed them, and measure against reality rather than against another vendor. Two vendors agreeing on a wrong answer looks identical to two agreeing on a right one. The full methodology is in how to evaluate a B2B data provider.
Where this fits in a recruiting workflow
Three insertion points, in order of return.
Before outreach, per candidate. Verify employment and contact at the moment a recruiter is about to reach out. Highest value, lowest volume, and it directly prevents the wasted outreach that started this post.
On movement, continuously. A daily watch against your talent pool surfaces who moved. Refresh only those records, and route left events to a recruiter immediately, since that window is short.
On a scheduled cycle, by priority. The tiered refresh described above, running against the segments that matter.
Build the first one first. It is the smallest change, it produces an immediate measurable effect on response rates, and it generates the data you need to justify the rest.
For recruiting platforms rather than recruiting teams, the same three points apply as product features rather than internal process, and the recruiting and HR page covers that shape.
Frequently asked questions
What is verified candidate data?
Candidate records where the contact details, current employment, or career history have been checked against a current source rather than assumed from when the record was created. The three are separate claims and a record can be verified in one sense and wrong in another.
How often does candidate data go stale?
Faster than general business data, because candidates are by definition a mobile population. Assume a database untouched for two years is substantially wrong rather than slightly stale.
How do I verify a candidate's current employer?
Watch for movement events rather than re-checking every record. Monitoring joined, left and title_change across your talent pool tells you which records changed, so you refresh only those.
Why do verified emails still bounce?
Usually because the person left. A mailbox at a large employer can stay open and accepting for months after someone departs, which is why employment confirmation and contact verification are separate checks.
What match rate should I expect on a candidate database?
Between 50% and 75% on a realistic database. Senior and technical roles resolve better than frontline and shift-based ones, so your mix matters more than any published benchmark.
Should I verify my whole database?
No. Refresh by priority: active requisition matches first, then records flagged by movement events, then the re-engagement pool. Records nobody queries do not need to be correct.
The one-line version
Verified means three different things, and employment verification is the one that determines whether your outreach lands. Watch for movement rather than re-checking everything, because that turns a database-wide refresh into a queue of records you know changed. Treat catch-all domains as their own segment, since recruiting touches sectors where they are common. And protect recruiter edits from automated refresh, because a recruiter who spoke to someone last week outranks any dataset.
The highest-return single change is also the smallest: verify employment and contact at the moment of outreach rather than trusting a record that was created at some unknown point in the past.
If you want to check a few candidates before building anything, the free tools will resolve a person, verify an address, or check for a job change with no signup. For programmatic use, the Quickstart takes about five minutes, and for volume or a procurement conversation, talk to us directly.


