Salesforce Lead & Contact Enrichment
Research-driven enrichment: find records with gaps, verify facts from public
sources, and update Salesforce only with citations attached and approval
given. Accuracy beats completeness — a wrong Industry is worse than a blank
one.
The universal record-writing rules this skill obeys are shared canon at
../../shared/standards/record-data-quality.md; object-level stewardship
(profiling, dedupe/merge, batched fixes, mass updates) belongs to
sf-records.
Dispatch
| Argument or intent |
Workflow |
find, "which leads need enrichment" |
Gap Analysis |
enrich (+ name or criteria) |
Enrich |
report, after a batch |
Results Report |
Initialize the org connection first (org_init convention — see
references/execution-modes.md) — unless running in Demo mode (below),
which has no org to connect to.
Gap Analysis
SELECT Id, FirstName, LastName, Company, Title, Email, Phone, Industry,
LeadSource, Website, NumberOfEmployees, Status
FROM Lead
WHERE IsConverted = false
AND (Title = null OR Industry = null OR Website = null
OR NumberOfEmployees = null)
ORDER BY CreatedDate DESC LIMIT 20
Adapt the WHERE to the user's criteria (status, source, owner, recency).
Report the gap profile — which fields are missing at what rate — before
enriching; sometimes the answer is a process fix, not 500 enrichments.
Enrich
Per record, in order:
- Identify uniquely. Name + company must resolve to one real person.
Ambiguous (common name, no company domain, multiple matches) → skip and
say why. Never guess identities.
- Research via web search / page fetch (and a LinkedIn tool when
connected): official company website, industry (from what the company
actually does, mapped to the org's Industry picklist values — fetch them
via describe, don't invent new ones), current title, employee-count
band, person and company LinkedIn URLs.
Apply the shared canon
../../shared/standards/record-data-quality.md
throughout (lead-specific notes: references/data-quality-rules.md):
active-picklist
verification (§1), org-dominant address/code conventions and HQ rule
(§2), field-length checks (§3), first-party email corroboration (§6),
and stated-not-inferred source attribution (§5).
- Record confidence + source per field. High = company's own site or
the person's own profile. Medium = third-party databases. Low = inference
— Low-confidence values are presented but not written unless the user
opts in.
- Propose, then write. Show the proposed field changes as a table
(current → proposed, source, confidence). On approval, update via the
MCP DML tool in batches of ≤10. NEVER overwrite an existing non-null
value unless explicitly asked — enrichment fills gaps, it doesn't
relitigate CRM history.
- Verify after write. Re-query the updated records — Flows, validation
rules, and sync automations can accept a write and then revert it. If a
field reverts, automation owns it: capture intent in a notes field and
tell the user rather than retrying (record-data-quality §8).
Contacts: same workflow against Contact (Account.Website often answers
company questions — check inside Salesforce before searching outside).
Results Report
| Name |
Company |
Fields updated |
Source |
Confidence |
Plus: records skipped (with reasons), low-confidence findings awaiting a
decision, and any picklist values that had no good match (data model
feedback for the admin).
When the user wants a document deliverable, follow the sf-audit skill's
report-template.md (from this skill: ../sf-audit/references/report-template.md) §7–8 rather than inventing a
report format.
Rules (non-negotiable)
- User approval before every write — no silent updates
- Source URL attached to every written value
- No identity guesses; skip ambiguous records loudly
- Existing data wins unless the user says otherwise
- Batches ≤10 records; respect API limits
- PII discipline: enrich business data (title, company, industry) — do not
hunt personal phone numbers, home addresses, or private accounts
- Opt-out is a one-way door: never unset an email opt-out without documented
re-opt-in; bounced addresses are unverified until corroborated first-party
- Departed contacts: flag, never delete — and spawn a cross-referenced lead
at the new company when relevant (record-data-quality §7)
References
| File |
Read when |
../../shared/standards/record-data-quality.md |
Before any batch of writes — the shared canon: picklist, convention, attribution, and verification rules |
references/data-quality-rules.md |
Alongside the canon — lead-specific notes (HQ addresses, LeadSource evidence bar, converted leads, ≤10 batches) |
references/execution-modes.md |
Start of session |
Cross-skill handoffs
- Bulk data quality beyond enrichment → sf-data / sf-audit
- Duplicate leads/contacts, object-wide data health, batched corrections →
sf-records
- Campaign-sourced lead performance → sf-campaigns
Custom-field discernment (customized orgs)
Orgs frequently track lead data in custom fields the standard gap query
won't see — a custom Industry_Segment__c used instead of Industry, a
LinkedIn_Profile__c, a custom company-size picklist. Before gap analysis
in an unfamiliar org, describe Lead/Contact, spot populated custom fields
that shadow the standard ones (populated-rate sampling, as in
record-data-quality §1-2 verification style), and confirm with the user
which fields the org actually maintains. Enriching a standard field the
org ignores creates the illusion of data quality without the substance.
Demo mode (no org)
The repo ships synthetic leads at sample-data/leads.csv with realistic
gaps and ~10% wrong-domain emails. When no Salesforce MCP server is
connected — or the user asks for a demo — run gap analysis and enrichment
proposals against that CSV (research steps simulated or run for real;
writes proposed only, since there's no org). Skip org_init in demo mode —
there is no org to initialize.
1---2name: sf-leads3description: Enriches Salesforce Lead and Contact records with verified data from web research — titles, industries, websites, company size, LinkedIn profiles — writing back via a Salesforce MCP server with per-field source citations and user approval before every update. Use when the user asks to enrich leads or contacts, fill in missing lead data, research a lead's company, update lead info from the web, or fix incomplete lead records. Do NOT use for bulk SOQL or DML against lead records (use sf-data), campaign performance and ROI analysis (use sf-campaigns), or org-wide data-quality auditing (use sf-audit). Usage: /sf-leads [find|enrich|report] {lead-name|criteria} ...4---56# Salesforce Lead & Contact Enrichment78Research-driven enrichment: find records with gaps, verify facts from public9sources, and update Salesforce only with citations attached and approval10given. Accuracy beats completeness — a wrong Industry is worse than a blank11one.1213The universal record-writing rules this skill obeys are shared canon at14`../../shared/standards/record-data-quality.md`; object-level stewardship15(profiling, dedupe/merge, batched fixes, mass updates) belongs to16**sf-records**.1718## Dispatch1920| Argument or intent | Workflow |21| ------------------------------------------ | -------- |22| `find`, "which leads need enrichment" | Gap Analysis |23| `enrich` (+ name or criteria) | Enrich |24| `report`, after a batch | Results Report |2526Initialize the org connection first (`org_init` convention — see27`references/execution-modes.md`) — unless running in Demo mode (below),28which has no org to connect to.2930## Gap Analysis3132```sql33SELECT Id, FirstName, LastName, Company, Title, Email, Phone, Industry,34 LeadSource, Website, NumberOfEmployees, Status35FROM Lead36WHERE IsConverted = false37 AND (Title = null OR Industry = null OR Website = null38 OR NumberOfEmployees = null)39ORDER BY CreatedDate DESC LIMIT 2040```4142Adapt the WHERE to the user's criteria (status, source, owner, recency).43Report the gap profile — which fields are missing at what rate — before44enriching; sometimes the answer is a process fix, not 500 enrichments.4546## Enrich4748Per record, in order:49501. **Identify uniquely.** Name + company must resolve to one real person.51 Ambiguous (common name, no company domain, multiple matches) → skip and52 say why. Never guess identities.532. **Research** via web search / page fetch (and a LinkedIn tool when54 connected): official company website, industry (from what the company55 actually does, mapped to the org's Industry picklist values — fetch them56 via describe, don't invent new ones), current title, employee-count57 band, person and company LinkedIn URLs.58 Apply the shared canon `../../shared/standards/record-data-quality.md`59 throughout (lead-specific notes: `references/data-quality-rules.md`):60 active-picklist61 verification (§1), org-dominant address/code conventions and HQ rule62 (§2), field-length checks (§3), first-party email corroboration (§6),63 and stated-not-inferred source attribution (§5).643. **Record confidence + source per field.** High = company's own site or65 the person's own profile. Medium = third-party databases. Low = inference66 — Low-confidence values are presented but not written unless the user67 opts in.684. **Propose, then write.** Show the proposed field changes as a table69 (current → proposed, source, confidence). On approval, update via the70 MCP DML tool in batches of ≤10. NEVER overwrite an existing non-null71 value unless explicitly asked — enrichment fills gaps, it doesn't72 relitigate CRM history.735. **Verify after write.** Re-query the updated records — Flows, validation74 rules, and sync automations can accept a write and then revert it. If a75 field reverts, automation owns it: capture intent in a notes field and76 tell the user rather than retrying (record-data-quality §8).7778Contacts: same workflow against Contact (Account.Website often answers79company questions — check inside Salesforce before searching outside).8081## Results Report8283| Name | Company | Fields updated | Source | Confidence |84| ---- | ------- | -------------- | ------ | ---------- |8586Plus: records skipped (with reasons), low-confidence findings awaiting a87decision, and any picklist values that had no good match (data model88feedback for the admin).8990When the user wants a document deliverable, follow the sf-audit skill's91report-template.md (from this skill: `../sf-audit/references/report-template.md`) §7–8 rather than inventing a92report format.9394## Rules (non-negotiable)9596- User approval before every write — no silent updates97- Source URL attached to every written value98- No identity guesses; skip ambiguous records loudly99- Existing data wins unless the user says otherwise100- Batches ≤10 records; respect API limits101- PII discipline: enrich business data (title, company, industry) — do not102 hunt personal phone numbers, home addresses, or private accounts103- Opt-out is a one-way door: never unset an email opt-out without documented104 re-opt-in; bounced addresses are unverified until corroborated first-party105- Departed contacts: flag, never delete — and spawn a cross-referenced lead106 at the new company when relevant (record-data-quality §7)107108## References109110| File | Read when |111| --- | --- |112| `../../shared/standards/record-data-quality.md` | Before any batch of writes — the shared canon: picklist, convention, attribution, and verification rules |113| `references/data-quality-rules.md` | Alongside the canon — lead-specific notes (HQ addresses, LeadSource evidence bar, converted leads, ≤10 batches) |114| `references/execution-modes.md` | Start of session |115116## Cross-skill handoffs117118- Bulk data quality beyond enrichment → **sf-data** / **sf-audit**119- Duplicate leads/contacts, object-wide data health, batched corrections →120 **sf-records**121- Campaign-sourced lead performance → **sf-campaigns**122123## Custom-field discernment (customized orgs)124125Orgs frequently track lead data in custom fields the standard gap query126won't see — a custom `Industry_Segment__c` used instead of `Industry`, a127`LinkedIn_Profile__c`, a custom company-size picklist. Before gap analysis128in an unfamiliar org, describe Lead/Contact, spot populated custom fields129that shadow the standard ones (populated-rate sampling, as in130record-data-quality §1-2 verification style), and confirm with the user131which fields the org actually maintains. Enriching a standard field the132org ignores creates the illusion of data quality without the substance.133134## Demo mode (no org)135136The repo ships synthetic leads at `sample-data/leads.csv` with realistic137gaps and ~10% wrong-domain emails. When no Salesforce MCP server is138connected — or the user asks for a demo — run gap analysis and enrichment139proposals against that CSV (research steps simulated or run for real;140writes proposed only, since there's no org). Skip `org_init` in demo mode —141there is no org to initialize.