> ## Documentation Index
> Fetch the complete documentation index at: https://docs.emanate.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Account Enrichment

> Automatically enriching accounts with company, contact, and intelligence data

Account enrichment automatically appends company data, decision-maker contacts, verified addresses, and AI intelligence scoring to each account, giving your team the context they need to prioritize outreach and close deals.

<Note>
  **Updated in v2.8**: New domain-resolution pre-stage, verified billing addresses with alternate-address review, `needs_review` workflow, duplicate detection, and automatic phone-number lookup with built-in fallback. See [Release Notes](/about/release-notes) for details.
</Note>

The enrichment pipeline is shared with [leads](/leads/enrichment): same stages, same behavior, same review tools. This page describes it from the account perspective.

## What Gets Enriched

### Company Data

| Field                | Description                                                                            |
| -------------------- | -------------------------------------------------------------------------------------- |
| **Company Name**     | Official company name                                                                  |
| **Domain**           | Company website                                                                        |
| **Industry**         | Industry classification                                                                |
| **Employee Count**   | Company size                                                                           |
| **Revenue**          | Estimated annual revenue                                                               |
| **Location**         | Headquarters location                                                                  |
| **Technologies**     | Tech stack used                                                                        |
| **Funding**          | Recent funding info                                                                    |
| **Verified Address** | Street, city, state, postal code, and country                                          |
| **Segment**          | Specific business classification (e.g., "Mid-market manufacturer of structural steel") |

### Contact Data

For each decision-maker contact discovered on an account:

| Field              | Description                                      |
| ------------------ | ------------------------------------------------ |
| **Title**          | Job title (e.g., "VP of Operations")             |
| **Department**     | Function (Sales, Engineering, etc.)              |
| **LinkedIn**       | LinkedIn profile URL                             |
| **Direct Phone**   | Direct dial number                               |
| **Mobile**         | Direct mobile number (populated by phone reveal) |
| **Personal Email** | Additional email addresses                       |

### Account Intelligence

After company and contact data are populated, AI generates:

| Field                | Description                                                       |
| -------------------- | ----------------------------------------------------------------- |
| **Fit Score**        | How well the account matches your ICP (1–100)                     |
| **Heat / Grade**     | Overall priority indicator (A / B / C) derived from the Fit Score |
| **Why This Account** | Plain-language summary of the firmographic match                  |
| **Why Now**          | Timing signal: recent triggers (funding, hiring, news)            |
| **Priority Action**  | Recommended next step                                             |

These appear on the **Intelligence** sub-tab of the account drawer.

#### How the Fit Score Is Calculated

The Fit Score is produced by an LLM synthesis pass over five weighted insight categories. Each category gets its own 1–100 sub-score and short reasoning paragraph; the headline Fit Score is the synthesis output, not a hand-tuned linear formula.

| Insight                   | What it measures                                               |
| ------------------------- | -------------------------------------------------------------- |
| **Firmographic Fit**      | Industry, employee count, revenue, growth stage vs your ICP    |
| **Recent Activity**       | Funding, hiring, product launches, news in the trailing window |
| **Pain Points / Needs**   | Likely challenges inferred from industry, size, and tech stack |
| **Decision-Maker Access** | Who to contact, typical buying process for the account size    |
| **Competitive Landscape** | Market position, competitors, differentiation angles           |

Score-to-verdict mapping used across the UI:

| Score      | Verdict    | Grade |
| ---------- | ---------- | ----- |
| **80–100** | Strong fit | **A** |
| **60–79**  | Good fit   | **B** |
| **40–59**  | Neutral    | **C** |
| **1–39**   | Weak fit   | **C** |

<Note>
  Re-running enrichment (or any per-column Fill that changes a firmographic input) recomputes the Fit Score on the next pipeline pass. You can also re-compute the three intelligence explanations individually via [per-column Fill](#per-column-fill).
</Note>

## Enrichment Triggers

### Auto-Enrichment on Import

When importing accounts via the Import Wizard, the **Auto-enrich imported accounts** toggle on the Column Mapping step runs enrichment automatically as soon as rows land. Matched/duplicate rows are skipped. You can run enrichment on them manually if needed.

### Manual

Enrich on demand from any account row:

1. Open the account drawer
2. Click **Enrich**
3. Wait for data to populate

### Bulk: Selection-Driven Enrich Button

The **Enrich** button at the top of the Accounts (and Leads) table retargets based on what's selected:

| Selection state            | Button label                      | What gets enriched                                                |
| -------------------------- | --------------------------------- | ----------------------------------------------------------------- |
| Nothing selected           | **Enrich First 50 of N Filtered** | First 50 rows of the current filtered page (legacy default)       |
| 1–50 rows checked          | **Enrich N Selected**             | Exactly those rows                                                |
| 51+ rows checked           | **Enrich First 50 of N Selected** | First 50 of the checked set                                       |
| Select-all-across-pages on | **Enrich First 50 of N Selected** | First 50 across the whole session, minus any rows you've excluded |

Server-side `BATCH_LIMIT = 50` is intentional. Pick the 50 highest-priority rows and run again rather than raising the cap. The button is disabled while any visible row is already queued or enriching.

### Per-Column Fill

You don't have to re-run the whole pipeline to refresh a single value. Each enrichable column on the Accounts and Leads tables has its own **Fill** action: an icon next to the column header (and a per-row variant where available) that re-fills just that field for the targeted rows.

Four pipelines share the registry; each owns a distinct slice:

| Pipeline                                   | Fields it owns                                                           |
| ------------------------------------------ | ------------------------------------------------------------------------ |
| **Web research**                           | `industry`, `revenue`, `employees`, `founded`, `segment`, `funding`      |
| **Company resolver** (Claude 4.6 fallback) | `domain`, `website`, `companyName`, `address`                            |
| **GPT**                                    | `whyThisAccount`, `whyNow`, `priorityAction` (intelligence explanations) |
| **Contact lookup**                         | `primaryContact` (name / email / phone discovered together)              |

Each cell tracks its own lifecycle state in the DB (`<field>_fill_status` = `queued` → `filling` → `NULL`) so the cell shows a **Queued…** or **Filling…** badge live without polling other columns. Each pipeline only asks for the slice it owns: "Fill domain" never touches website, name, or address; "Fill industry" never touches revenue.

#### Prerequisite Check

Per-column Fill only runs when each row has enough input for the pipeline to ground the lookup. The column-header button is **disabled with a tooltip** if any visible row is missing a prerequisite:

| Pipeline         | Required input                     |
| ---------------- | ---------------------------------- |
| Web research     | Company name **or** website/domain |
| Company resolver | Company name                       |
| GPT intelligence | Company name                       |
| Contact lookup   | Company name **or** website/domain |

The tooltip names the missing field(s) so you can fix the gap or narrow the selection.

<Tip>
  Use per-column Fill when you only need one field refreshed. Re-enriching a whole row costs a full pipeline pass and overwrites nothing that's already set. Targeted Fill is also the right tool when a single provider returned `—` and you want to retry just that slice.
</Tip>

### Hover for Source Citations

Enriched **Revenue**, **Employees**, and **Industry** cells carry per-field citations from the original lookup. Hover any of those cells to reveal a tooltip with:

* The **citation URL** that grounded the value (typically a LinkedIn company page or industry profile)
* The **page title** so you can confirm the source before clicking through
* The model's **confidence** when reported (high / medium / low)

If a row was enriched before the citations layer shipped, the tooltip stays hidden. There's no "Sources unavailable" placeholder cluttering the cell. Re-enriching (or per-column Fill) will populate citations going forward.

## The Enrichment Pipeline

Each enrichment run flows through several stages.

### Stage 0: Domain Resolution

Before any lookup runs, an AI step resolves messy company strings (abbreviations, misspellings, customer-list short codes) into a canonical domain. This dramatically improves match rates downstream and lets enrichment work on rows that only have a company name.

<Tip>
  Internal acronyms in your customer list (e.g., "DOFASC" → "Dofasco") are auto-expanded during this stage so they match real company records.
</Tip>

### Stage 1: Decision-Maker Discovery

Searches the company for decision-makers and surfaces the most senior contact available, attaching them to the account's Contacts tab.

If a primary contact already exists on the account, newly discovered contacts land as **secondary contacts** rather than overwriting the primary. Phone-only primaries created from import are preserved.

### Stage 2: Company Data

Populates verified company data including industry, employee count, revenue, technologies, headquarters address, and a specific segment classification.

### Stage 3: Phone Reveal

Requests a direct mobile number for the primary contact. If the initial lookup doesn't return a number quickly, the system automatically falls back to a secondary source so the **Mobile** column populates reliably.

### Stage 4: CRM Sync, Intelligence & Embeddings

The pipeline finishes with CRM sync (if a CRM is connected), AI **intelligence scoring** (fit score, timing signal, and priority actions) and vector embeddings that power **natural-language semantic search** across your account base.

### Estimated Run Time

Enrichment runs in batches of **up to 100 leads or accounts** at a time, with the actual batch size adjusted in real time based on available resources. This applies to all enrichment: auto-enrichment on import, manual single-row enrichment, and bulk re-enrichment. Plan for roughly **12 minutes per batch** end-to-end. Rows that match an existing record (duplicates) are skipped by auto-enrichment but can be enriched manually.

## Revenue Formatting

Revenue is **stored as a raw integer** and rendered everywhere through a single `formatRevenue` helper:

| Raw value                | Displayed |
| ------------------------ | --------- |
| `1_500_000_000`          | `$1.5B`   |
| `50_000_000`             | `$50M`    |
| `250_000`                | `$250K`   |
| `999`                    | `$999`    |
| `0`, negative, or `null` | `—`       |

The web-research prompt is constrained to return a clean integer (no `$`, no `K`/`M`/`B`, no ranges, no "approx") and Fill-revenue paths route through the same helper. Pre-EMA-263 rows with messy strings are normalized on read.

## Overwrite Behavior

Enrichment **never overwrites existing data**. If a field already has a value, it's preserved; if it's empty, enrichment fills it in. This applies to every enriched field: name, email, phone, title, LinkedIn URL, company info, and so on.

Addresses are handled with an extra layer: a verified billing address that differs from the existing one is stored as an [alternate address](#verified-addresses--alternate-addresses) for you to **Accept** or **Keep Existing** rather than being applied silently.

Decision-maker contacts follow the same principle: newly discovered contacts land as **secondary contacts** when a primary already exists, and never replace the primary automatically.

## Verified Addresses & Alternate Addresses

When enrichment returns a verified billing address that differs from the address already on the account, the new address is **stored as an alternate** instead of silently overwriting the existing one. The drawer's **Address** section grows an **Alternate Addresses** card with **Accept** and **Keep Existing** buttons so you can promote or dismiss each candidate.

| Action            | Effect                                                                             |
| ----------------- | ---------------------------------------------------------------------------------- |
| **Accept**        | Promotes the alternate to be the primary address; the previous primary is archived |
| **Keep Existing** | Dismisses the alternate; the existing address remains                              |

## Enrichment Review

After a batch run completes, the **Enrichment Review** dialog highlights every account with discrepancies between previously stored data and the newly enriched values. Each row is tagged:

| Tag             | Meaning                                                        |
| --------------- | -------------------------------------------------------------- |
| `match`         | Existing data matched the enrichment result, no action needed  |
| `auto_filled`   | Field was empty before; enrichment populated it                |
| `kept_existing` | Existing value was preserved (e.g., primary address protected) |
| `mismatch`      | Existing value disagrees with enrichment; review recommended   |
| `uncertain`     | Enrichment could not establish high confidence                 |

Synthetic alternate-address cards are surfaced inline so you can resolve them in a single review pass.

## The `needs_review` Status

Accounts that require human attention move to a dedicated **`needs_review`** state, surfaced as an amber pill in the table and an **N need review** count badge next to the enrichment ETA. Filtering the status column shows friendly labels for each state.

Common reasons an account enters `needs_review`:

* Enrichment matched a domain already claimed by another account (potential duplicate)
* An alternate address was returned that disagrees with the existing primary
* Confidence on a critical field is below threshold

## Duplicate Detection

If enrichment resolves to a domain that's already claimed by another account, the second account is flagged `needs_review` and the **Duplicate Review** dialog gives you three choices:

| Option            | Effect                                                                                       |
| ----------------- | -------------------------------------------------------------------------------------------- |
| **Keep Separate** | Treats both accounts as distinct; clears the review flag                                     |
| **Merge**         | Folds the new account into the existing record, preserving custom fields, tags, and contacts |
| **Delete**        | Removes the duplicate account entirely                                                       |

Duplicate detection runs on **both leads and accounts**, with parity in the review experience.

## Semantic Search

Vector embeddings produced in Stage 4 power natural-language search across your account base. Type a query like "mid-market manufacturers in the Midwest hiring engineers" and the system returns the closest-matching accounts ranked by similarity.

## Enrichment Quality

### Match Confidence

Enrichment results carry a confidence label that's surfaced on alternate-address cards and contact matches:

| Label      | Meaning                                       |
| ---------- | --------------------------------------------- |
| **High**   | Strong match, high reliability                |
| **Medium** | Good match, review recommended                |
| **Low**    | Uncertain, review before relying on the value |

### Handling Low Confidence

Low-confidence fields are tagged `uncertain` in the [Enrichment Review](#enrichment-review) dialog, and accounts containing them move to the [`needs_review`](#the-needs_review-status) state so they're easy to spot and action manually.

## Monitoring Enrichment

### Dashboard Metrics

| Metric              | Description                           |
| ------------------- | ------------------------------------- |
| **Enrichment Rate** | % of accounts enriched                |
| **Match Rate**      | % with high-confidence match          |
| **Needs Review**    | Accounts flagged for manual attention |
| **Failed**          | Enrichment failures                   |

### Enrichment Status

| Status           | Meaning                                                                                  |
| ---------------- | ---------------------------------------------------------------------------------------- |
| **Pending**      | Queued for enrichment                                                                    |
| **Processing**   | Currently enriching                                                                      |
| **Enriched**     | Successfully completed                                                                   |
| **Partial**      | Some fields populated                                                                    |
| **Needs Review** | Requires manual review (duplicate suspected, alternate address, or low-confidence field) |
| **Failed**       | Could not enrich                                                                         |
| **No Match**     | No matching record found                                                                 |

## Troubleshooting

<AccordionGroup>
  <Accordion title="No match found">
    * Verify the company name and domain are correct
    * Try the canonical domain (e.g., `acme.com` rather than a regional subdomain)
    * The company may not be in the enrichment provider's index
  </Accordion>

  <Accordion title="Outdated information">
    * Enrichment data can become stale over time
    * Re-run enrichment from the account drawer to refresh
  </Accordion>

  <Accordion title="Enrichment failed">
    * Re-run enrichment from the account drawer or the **Bulk Actions** menu
    * Check the account's status: `needs_review` accounts require manual action before re-enrichment will help
    * If the failure persists across many accounts, contact support
  </Accordion>
</AccordionGroup>

## Best Practices

### Enrich Strategically

<Tip>
  Use [duplicate detection](#duplicate-detection) and the `needs_review` queue to focus attention where it matters. The system already skips matched rows automatically.
</Tip>

### Review Alternate Addresses Promptly

When enrichment surfaces alternate addresses, action them quickly so your account records reflect ground truth. Stale alternates can clutter the drawer and obscure what's authoritative.

### Monitor Quality

Regularly review enrichment quality:

* Spot check enriched accounts
* Track match rates and the `needs_review` count
* Action `needs_review` accounts promptly so the queue doesn't pile up

## Next Steps

<CardGroup cols={2}>
  <Card title="Accounts Overview" icon="building-2" href="/accounts/overview">
    Custom fields, sessions, and duplicate detection
  </Card>

  <Card title="Contacts" icon="users" href="/accounts/contacts">
    Manage contacts and primary contact
  </Card>

  <Card title="Lead Conversion" icon="arrow-right" href="/accounts/lead-conversion">
    Convert qualified leads into accounts
  </Card>

  <Card title="Lead Enrichment" icon="sparkles" href="/leads/enrichment">
    Same pipeline on the lead side
  </Card>
</CardGroup>
