---
name: moltsets-rb2b-non-icp-to-icp
description: Use this skill when the user has an RB2B visitor export and wants to find contacts at companies where the identified visitor isn't ICP themselves.
---

# RB2B Non-ICP Visitors to Company Contacts

Filter RB2B visitor rows by "company fit but visitor isn't ICP", then return and enrich contacts at those companies.

## Triggers

"the people who visited aren't my buyers but their companies are a fit - find contacts there", "some visitors aren't ICP but I want to prospect into their companies", "filter out non-ICP visitors but keep their companies", "find contacts at companies that visited even if the visitor isn't the right person".

## CSV parsing

Read the uploaded or pasted CSV. Filter to `ProfileType = Person` rows only. Extract:
- `LinkedInUrl`, `FirstName`, `LastName`, `Title` - visitor identity
- `CompanyName`, `Website` - company identity
- `AllTimePageViews`, `RecentPageCount` - intent signals

## Step 0 - Define non-ICP visitors

Need one definition before proceeding:

**Non-ICP definition** (which visitor rows to filter out of the RB2B export):
> "Which visitor titles/roles are NOT your ICP? For example: 'engineers', 'support staff', 'interns'. I'll filter visitors matching these out and keep their companies."

If user can't specify non-ICP, flip it: ask for the ICP definition and treat everything else as non-ICP.

**Note:** `search_people` accepts both company and people filters: `company` (name), `company_domain` (exact), `industry`, `seniority`, `department`/`functional_area`, `country`, `query` (free-text name/role/company), plus `limit`/`offset`. When you search the fitting companies for ICP contacts, use the ICP definition as `seniority`/`department` filters (enum values) to pull only the right roles.

## Step 1 - Filter non-ICP visitors

From the Person rows, identify visitors whose `Title` does NOT match the ICP definition. Use keyword matching on `Title` - be generous, flag uncertain cases.

Report:
```
Total Person visitors: X
Non-ICP visitors (title mismatch): X
ICP visitors (kept for direct enrichment if needed): X
```

Ask: "Want me to also enrich the ICP visitors directly while I'm at it?"

## Step 2 - Extract companies

From the non-ICP visitor rows, extract unique companies (`CompanyName` + `Website`).

For companies that appear multiple times (multiple non-ICP visitors from same org), note the total visit count - higher = more intent.

Sort descending by total `AllTimePageViews` across visitors from each company.

Report: "Found X unique companies from non-ICP visitors."

## Step 3 - Credit check

Call `MoltSets:get_billing` and `MoltSets:get_usage` with `period: billing_cycle` in parallel (free).

Estimate:
```
X companies × ~3 results per company = ~X prospects
X prospects × enrich cost per tool   = ~XXX credits
Current balance:                     = XXX credits
```

## Step 4 - Confirm scope

Confirm with user:
> "I'll pull contacts at X companies (sorted by visit intent). How many contacts per company? (Default: 3, max 25)"

Wait for confirmation.

## Step 5 - Probe (first company)

Run `search_people` with `limit: 1` for the highest-intent company, scoped by `company_domain` (the company's `Website`, most precise) or `company`/`query` (company name), optionally narrowed to the ICP role with `seniority`/`department`/`functional_area`/`country` (use enum values). Title also returns as a response field for ranking. Check result quality before scaling.

## Step 6 - Loop all companies

For each company (ordered by intent signals desc):
- `search_people` scoped by `company_domain` (preferred) or `company`/`query` (company name), optionally narrowed to the ICP role with `seniority`/`department`/`functional_area`/`country`
- Tag results with source visitor name + RB2B visit count for traceability
- Flag zero-result companies, do not stop loop

## Step 7 - Deduplicate

Remove duplicate LinkedIn URLs. Report: "Found X unique contacts across Y companies."

## Step 8 - Enrich

Business email is often already on the search records - check first and only enrich the gaps. Credit confirm: "Found X contacts. Enriching [email/phone/both] = ~XXX credits. Proceed?"

Run in parallel:
- `MoltSets:linkedin_to_business_email` - SINGLE `linkedin_url`; one call per URL in parallel (the email gaps)
- `MoltSets:linkedin_to_mobile_phone` with `linkedin_urls: [array]` (the only batch-array endpoint; if requested)

Fire the per-URL email calls in parallel; chunk the phone array at 100 if needed.

## Step 9 - Output

| Visitor (RB2B) | Visitor Title | Company | RB2B Visits | Contact | Contact Title | Business Email | Mobile |
|---|---|---|---|---|---|---|---|

- `Visitor (RB2B)` = the person who actually visited (non-ICP signal source)
- `Contact` = the person found via MoltSets at that company

Summary:
```
Visitors processed:   X
Non-ICP visitors:     X
Unique companies:     X
Contacts found:       X  (avg X per company)
Zero-result accounts: X
Business emails:      X/N (XX%)
Mobile numbers:       X/N (XX%)  - if enriched
Credits used:         ~XXX
```

## Edge cases

- Visitor title is empty to treat as unknown, include in non-ICP set (safer to include than miss)
- Same company appears via ICP and non-ICP visitors to note both; ICP visitor enriched separately if user opts in
- Credits run out mid-loop to stop, output completed rows, report exact resume point
