salesascode
← All feature docs
Feature docs · /enrichment

Contact Enrichment

Fill a contact's missing facts by walking your providers cheapest first, stopping per field on the first valid hit, with the full spend trail shown.

Included with gtmcron . A seat without it sees an upsell here instead of the page.

Overview

Contact Enrichment runs the enrichment waterfall for a single contact: you enter what you know, and the cascade walks your configured providers cheapest first, filling each missing field on the first valid hit and stopping there so no field is paid for twice. It is the interactive front end to the same waterfall primitive the scheduled runs use, so what you see here matches what the agents get.

What it is for, on the page. Under the headline, this page says what it produces, what makes it run, and where the output lands. Every Work page reads that line from one registry, so the three answers cannot drift from the page.

How the waterfall works

You supply at least a name, a LinkedIn URL, or a company domain, and choose which fields to fill (email, phone, title, seniority, company, LinkedIn, employee count, industry). The cascade asks each provider only for the fields still missing, in cost order, and writes the first valid value it gets. Email values pass a deliverability check before they are returned; an email that fails is rejected and the chain keeps looking. The result shows every filled field with the provider that supplied it, the credits spent, and a per-provider trail (hit, miss, skipped, not-configured, error) so the spend and coverage are fully auditable.

Honest by default

A provider with no credentials is reported as not-configured and never called, so it costs nothing and fabricates nothing. If you have not connected any enrichment providers yet, every provider shows not-configured and the result is empty, that is the honest state, not an error. As each vendor path is verified and its credentials are added, the same panel gets stronger with no change to how you use it. Add provider credentials in Settings under Connect your tools.

A provider we did not call reads as its own state, deliberately not as "no record". A no-record result says the vendor was asked and had nothing, which is a fact about your contact. The other says we did not ask, which is a fact about us. Nothing is charged either way, and the panel now names the reason per provider rather than lumping them together, because the reasons differ and only some of them are yours to act on.

Hunter and Apollo are both called for real once you add a key, and they are the two you can turn on by yourself: sign up, generate a key, paste it. ZoomInfo and Cognism need a partner agreement with the vendor before their API contract is even available to build against, so there is nothing to call yet. Clay is a different shape: it has a public API, but the synchronous lookup a cascade needs is an enterprise endpoint with no published contract, and its documented HTTP integration is a column inside a Clay table that calls out to somebody else rather than answering us. Clay enrichment runs through its own webhook path instead, not through this page.

Spend counts against your cap

Every run is charged against the same credit budget the scheduled re-enrichment uses, so the cap you set on Enrichment Budget governs this button too. With the budget used up, nothing is requested and nothing is spent, and the panel says so rather than showing an empty result. Only credits a provider actually reported are charged, which is zero for a provider we did not call.

If we cannot read your cap at all, the run is refused the same way, and the credits tile reads "cap unknown" instead of "no cap set". Those are different answers: one is a setting of yours, the other is a failure of ours, and we will not spend a vendor credit against a cap we could not check. Try the run again in a moment.

What Hunter fills, and why it goes first

Hunter answers one narrow question well: what is this person's address at this company. Give it a first and last name plus a domain or company name and it returns the work email with a confidence score, and the job title and company name arrive on the same response at no extra cost.

It goes first in the cascade because it is the cheapest and narrowest. Email is the field asked for most often and the one a draft is useless without, so answering it before a broader provider is asked is what cost order is for. Whatever Hunter leaves open falls straight through to Apollo, which is then asked only for the rest.

An address below Hunter's own confidence boundary is not written. Hunter returns a pattern-matched guess with a low score rather than nothing, and accepting that would fill the field with an invention and stop the cascade from asking a provider that actually knows. The guess is discarded, the field stays open, and the next provider is asked.

It does not fill a phone number, seniority, headcount or industry. Those are not fields Hunter has, so they fall through rather than come back blank. Hunter bills the request whether or not it finds an address, so a miss is charged to your budget and the panel shows it, which is the honest reading of what a run cost.

What Apollo fills, and what it does not

Apollo can fill the work email, title, seniority, LinkedIn URL, and the company's name, industry and headcount. A person it has no record of costs nothing; a person it matches costs one credit whether or not we could use what came back, because that is what Apollo bills for.

It does not fill a phone number here. Apollo reveals phone numbers asynchronously: it takes the request, returns a ticket, and delivers the number later. This page answers while you wait, so asking would spend credits on something it cannot collect. The phone field falls through to the next provider instead, which is the honest outcome rather than a silent blank. Apollo also returns a placeholder address for an email your plan has not unlocked; that is dropped rather than written to your contact, so the field stays open for another provider.

What a run leaves behind

Since 12 September 2026 a run is written where it was for. Pass a record (persist: { entity, id }, a prospect, contact, account or target account) and the filled facts land on it: each field at the top level where the record had none, so a value you typed is never overwritten, the whole result under enrichment with the provider per field, and one dated line on the record's research log saying which fields, from whom, at what cost. The scheduled re-enrichment writes the same line. Research passes on a contact or an account write theirs. The log keeps the newest twenty.

When the record came from a connected CRM (its id says so: an Attio person, a HubSpot deal, a Salesforce contact, a Pipedrive person), the same line is pushed there too, as a note, a task or an activity through the write-back adapter for that CRM. Attio gained a note adapter for this; it is marked preview until it has run against a live workspace.

The shared pool. Before a run spends a credit, the cascade reads the platform's pool of company facts for the contact's domain and seeds what it already holds (company, industry, headcount), so those fields cost nothing. The pool is built from what tenants who opted in found: company facts and dated findings with a public source, keyed on domain, with no tenant id and nothing about a person. Turn contribution on under Connect; reading is on for everyone. The response says which fields the pool seeded (poolSeeded) and whether this run contributed (contributed).

When the pool is trusted. A fact seeds a run only once two or more accounts have contributed the same domain: one contribution is one vendor's answer copied once, two is corroboration. A row with a single contributor is read and not settled, so the cascade still asks a vendor. Sourced findings are different: each carries the public page it came from, so the account-research pass cites them as prior evidence at any contributor count, marked stale until a fresh read confirms them, and the rep checks the page rather than the count.

What it does not do

Contact Enrichment fills facts for one contact on demand; it does not bulk-enrich a list. It reads what you type into the form and returns the filled facts to the page, and stores them only when you name a record to write to. Bulk re-enrichment on a schedule stays with the gtmcron scheduled runs, which call the same waterfall over your book. The design mockup drew this as a bulk cascade dashboard with rows-in and coverage-percent aggregates across thousands of rows; those are omitted here rather than fabricated, because this endpoint is single-contact. The per-contact provider cascade shows the same walk honestly for the one contact.