Find Lookalike Accounts from Your Closed-Won Customers
The problem
Outbound lists are usually built from broad filters, while the best predictor of who will buy, the customers you already closed, sits in the CRM unused, so reps spend sequences on accounts that look nothing like your wins.
Implementation steps
- 1
Export closed-won companies from the last 12 to 24 months from HubSpot or Salesforce with domain, deal size, and segment, and keep the best fits as seeds, for example customers who renewed or closed above your median deal size; export current customers, open opportunities, and recent closed-lost accounts by domain as the exclusion list
- 2
Profile the seeds in Clay: enrich industry, headcount, headquarters country, funding, and technographics, then write down the shared ranges and the traits that disqualify a company, as covered in the closed-won ICP analysis playbook
- 3
Find candidates with Clay: run the Find Company Lookalikes action on your top seed accounts, start the Company Lookalikes source from your seed table, or use Find Companies with the profile as filters (industry, headcount, location, keywords, technographics) and your exclusion list in its exclude companies option
- 4
Normalize domains on candidates and exclusions the same way (lowercase, no protocol, www, or path), turn on auto-dedupe for the domain column, and check each candidate against the CRM by domain so customers, open opportunities, and owned accounts drop out
- 5
Score each candidate 1 to 5 against the profile with a formula or an AI step that returns a one-line reason, and optionally have Claygent check whether the company already uses a direct competitor
- 6
For accounts scoring 4 or 5, find one or two buyers by title with a verified email, add them to an Instantly or Smartlead campaign with an angle drawn from the shared traits (never name the customer they resemble without permission), and create the company in the CRM with lead source lookalike so assignment rules set the owner; send 3s to a rep review list
Template outline
The structure to recreate in your own workspace. Field names and thresholds are starting points.
Part 1: Clay table (UI)
1. Seeds: closed-won companies, last 12 to 24 months, best-fit filter (renewed or above median deal size)
2. Exclusions: customers, open opportunities, closed-lost in the last {{months}} months (domains)
3. Profile: enrich seeds (industry, headcount, HQ country, funding, technographics); write shared ranges and disqualifiers
4. Candidates (pick one):
- Find Company Lookalikes on top seeds
- Company Lookalikes source from the seed table
- Find Companies with profile filters + exclude companies = exclusion list
5. Formula: normalized domain; auto-dedupe rows on it
6. Export: company_domain, company_name, industry, employee_count, country, seed_company, target_title
Part 2: Clay Workflow (CSV trigger, one run per candidate)
1. CRM lookup by domain: is_customer, has_open_deal, owner (skip if any)
2. AI score vs {{your_closed_won_profile}}: score 1 to 5, reason, angle
3. Score 4 or 5: find 1 buyer in {{target_title}}, verified email
4. Sequencer: add lead with angle and industry (do not name the seed customer)
5. CRM: create company, lead source = lookalike, score, reason
6. Score 3: rep review list
Output: a steady list of net-new accounts that match your wins, with existing customers and pipeline excluded and a reason on every accountBuild it in Clay
Copy these commands into your own Clay CLI. They run in your Clay workspace under your login. Nothing runs on our side, and this site never sees your Clay data or login.
This builds the qualification half of the play as a Clay workflow with a CSV trigger. You find lookalike candidates in the Clay UI first (Find Company Lookalikes, the Company Lookalikes source, or Find Companies with your profile as filters), export them, and upload the file. Each candidate becomes one run: check the CRM by domain, score the fit, find a buyer, add them to a sequence, and create the company with an owner task. The Clay CLI cannot create tables or run company searches, so this build uses a workflow.
Not tested by GTM Playbooks
This build was written from the Clay CLI v1.3.1 help output, not from a run. Anything marked “Verify in your workspace”, and every line tagged VERIFY in the script, uses a shape that help does not document. Workflow runs can spend your Clay credits.
Part 1: Before you start
1.Install the Clay CLI
Use version 1.3.1 or later, installed from Clay's own instructions. This page does not include an install command because the CLI reference it was written from does not list one. You also need jq, which the script uses to read the JSON the CLI prints.
2.Log in to your workspace
Browser login is the default. Use the device flow on a headless machine. A static key in the CLAY_API_KEY environment variable also works. Workflow commands need the terracotta:cli scope, so an auth error that names it means your login cannot manage workflows.
Log in with a browser
clay loginLog in on a headless machine
clay login --deviceConfirm who you are logged in as
clay whoami3.Pick the workspace to build in
The workflow is created in your active workspace. Switch first if you belong to more than one.
List workspaces
clay workspaces listShow the active workspace
clay workspaces currentSwitch workspace
clay workspaces switch <workspaceId>4.Find your action keys
Action package ids and keys are specific to your workspace. Save the catalog, search it for your CRM lookup action, an AI text action, a find-people action, your sequencer, and your CRM create action, then paste their ids into the top of the script. Skip "clay workflows actions test": it spends credits.
Save the action catalog
clay workflows actions list > catalog.jsonSearch the catalog
grep -Eio '"[^"]*(hubspot|salesforce|lookup|use ai|generate|find people|instantly|smartlead|create)[^"]*"' catalog.json | sort -uSee an action's inputs and outputs
clay workflows actions schema <packageId> <actionKey>5.Build the candidate list in the Clay UI
Start from a table of your best closed-won companies. Run Find Company Lookalikes on the top accounts, or open the Company Lookalikes source from that table, or use Find Companies with your profile as filters and your customer and open-opportunity domains in its exclude companies option. Normalize domains, turn on auto-dedupe for the domain column, and export the columns in the sample CSV.
6.Write the profile and prepare the sequencer
Write your closed-won profile as one paragraph for the scoring prompt (industries, headcount band, regions, tools, and what disqualifies a company). Connect Instantly or Smartlead in Clay and create an empty test campaign, so early runs do not reach a live sequence.
Part 2: Workflow spec
What the script builds: Lookalike accounts from closed-won.
Trigger
csv_uploadYou upload the candidate companies exported from your lookalike or search table. Each header becomes a string input, and each row becomes one run once the workflow is published.
Verify in your workspace: The trigger type string "csv_upload" is inferred. The CLI help does not show how to create a CSV trigger.
Inputs (CSV headers)
company_domain- Normalized candidate domain
- example.com
company_name- Candidate company name
- Example Co
industry- Industry from the search or enrichment
- Software Development
employee_count- Estimated employees
- 180
country- Headquarters country
- United States
seed_company- The closed-won customer it resembles
- Customer Co
target_title- Buying role to contact
- VP of Sales
- 1
Check the CRM by domain
actionLooks up the domain in HubSpot or Salesforce and returns whether it is a customer, has an open deal, or already has an owner.
- Reads
company_domain- Writes
crm_company_idis_customerhas_open_dealowner
Verify in your workspace: Later steps should skip customers, open deals, and owned accounts. That needs a run condition, which the CLI help does not document, so set it in the Clay UI using your CRM fields.
- 2
Score the fit
actionAn AI text action compares the candidate with your closed-won profile and returns a 1 to 5 score, a reason, and an angle.
- Reads
company_namecompany_domainindustryemployee_countcountryseed_company- Writes
scorereasonangle
Prompt
Score how closely {{company_name}} ({{company_domain}}) matches our best customers. Our closed-won profile: {{your_closed_won_profile}} This company: industry {{industry}}, about {{employee_count}} employees, headquartered in {{country}}, similar to our customer {{seed_company}}. Return JSON with score (1 to 5, where 5 matches every trait in the profile), reason (one sentence naming the traits that match or miss), and angle (one sentence on why this company might care, based only on the inputs). Do not invent facts about the company. No em dashes.
- 3
Find the buyer
actionFinds one person in the target role with a work email. Runs only on candidates that pass the CRM check and score 4 or 5.
- Reads
company_domaintarget_title- Writes
first_namelast_nametitleemail
Verify in your workspace: One run handles one contact. Add a run condition in the Clay UI so this step and the next only run when score is 4 or more.
- 4
Add to the sequence
actionAdds the buyer to your Instantly or Smartlead campaign with the angle and industry as custom fields.
- Reads
emailfirst_namelast_namecompany_nameangleindustry- Writes
Sequencer lead
- 5
Create the company in the CRM
actionCreates the company in the CRM with lead source = lookalike, the score, and the reason, so assignment rules set an owner and the rep sees why it was added.
- Reads
company_domaincompany_namescorereasonseed_company- Writes
CRM record
Part 3: Build script
Creates the workflow, the CSV trigger, and five steps, then pauses so you can map step inputs and the run conditions. It validates the graph, offers one test run, and asks before publishing.
Save it as build-lookalike-accounts.sh, fill in the 10 action ids at the top, then run bash build-lookalike-accounts.sh.
build-lookalike-accounts.sh
#!/usr/bin/env bash# Builds the "Lookalike accounts from closed-won" Clay workflow# in YOUR Clay workspace, using YOUR Clay CLI login.# Written against Clay CLI v1.3.1. Not run or tested by GTM Playbooks.# Lines tagged VERIFY use a shape the CLI help does not document.set -euo pipefail # Copy these from catalog.json (see "Find your action keys").LOOKUP_PACKAGE_ID="" # HubSpot or Salesforce: lookup companyLOOKUP_ACTION_KEY=""SCORER_PACKAGE_ID="" # Use AI or another AI text actionSCORER_ACTION_KEY=""CONTACT_PACKAGE_ID="" # Find people at a company (by title)CONTACT_ACTION_KEY=""SEQUENCER_PACKAGE_ID="" # Instantly or Smartlead: add lead to campaignSEQUENCER_ACTION_KEY=""CRM_PACKAGE_ID="" # HubSpot or Salesforce: create companyCRM_ACTION_KEY="" # One input to test before real traffic. Use yourself or a teammate.TEST_ROW='{"company_domain":"","company_name":"","industry":"","employee_count":"","country":"","seed_company":"","target_title":""}' for v in LOOKUP_PACKAGE_ID LOOKUP_ACTION_KEY SCORER_PACKAGE_ID SCORER_ACTION_KEY CONTACT_PACKAGE_ID CONTACT_ACTION_KEY SEQUENCER_PACKAGE_ID SEQUENCER_ACTION_KEY CRM_PACKAGE_ID CRM_ACTION_KEY; do [[ -n "${!v}" ]] || { echo "Set $v at the top of this script." >&2; exit 1; }donecommand -v clay > /dev/null || { echo "Clay CLI not found on PATH." >&2; exit 1; }command -v jq > /dev/null || { echo "jq is required to read CLI output." >&2; exit 1; }clay whoami > /dev/null || { echo "Not logged in. Run: clay login" >&2; exit 1; } # VERIFY: only "workflows create" documents an "id" field in its output.read_id() { local id id=$(jq -r '.id // empty' "$1") [[ -n "$id" ]] || { echo "No id found in $1. Open it and adjust read_id." >&2; exit 1; } echo "$id"} mkdir -p clay-lookalike-accountscd clay-lookalike-accounts echo "1/9 Create the workflow"clay workflows create --name "Lookalike accounts from closed-won" > workflow.jsonWF_ID=$(read_id workflow.json)WF_URL=$(jq -r '.url // empty' workflow.json) echo "2/9 Add the CSV upload trigger"# VERIFY: triggerType "csv_upload" is inferred; the help does not show it.clay workflows triggers create "$WF_ID" --input '{"triggerType":"csv_upload"}' > trigger.jsonTRG_ID=$(read_id trigger.json) echo "3/9 Step 1: check the crm by domain"# VERIFY: help shows nodeType and name only; actionPackageId and actionKey are a guess.STEP1=$(jq -nc --arg p "$LOOKUP_PACKAGE_ID" --arg k "$LOOKUP_ACTION_KEY" '{nodeType: "tool", name: "Check the CRM by domain", actionPackageId: $p, actionKey: $k}')clay workflows nodes create "$WF_ID" --input "$STEP1" > step1.jsonSTEP1_ID=$(read_id step1.json) echo "4/9 Step 2: score the fit"# VERIFY: action fields inside "step" are inferred from the documented utility example.STEP2=$(jq -nc --arg n "$STEP1_ID" --arg p "$SCORER_PACKAGE_ID" --arg k "$SCORER_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')clay workflows nodes insert "$WF_ID" --input "$STEP2" > step2.jsonSTEP2_ID=$(read_id step2.json) echo "5/9 Step 3: find the buyer"# VERIFY: same inferred insert shape as step 2.STEP3=$(jq -nc --arg n "$STEP2_ID" --arg p "$CONTACT_PACKAGE_ID" --arg k "$CONTACT_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')clay workflows nodes insert "$WF_ID" --input "$STEP3" > step3.jsonSTEP3_ID=$(read_id step3.json) echo "6/9 Step 4: add to the sequence"# VERIFY: same inferred insert shape as step 2.STEP4=$(jq -nc --arg n "$STEP3_ID" --arg p "$SEQUENCER_PACKAGE_ID" --arg k "$SEQUENCER_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')clay workflows nodes insert "$WF_ID" --input "$STEP4" > step4.jsonSTEP4_ID=$(read_id step4.json) echo "7/9 Step 5: create the company in the crm"# VERIFY: same inferred insert shape as step 2.STEP5=$(jq -nc --arg n "$STEP4_ID" --arg p "$CRM_PACKAGE_ID" --arg k "$CRM_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')clay workflows nodes insert "$WF_ID" --input "$STEP5" > step5.jsonclay workflows graph get "$WF_ID" --mode full > graph.json echo "8/9 Map step inputs"cat <<EOF Step inputs are specific to your workspace. Map them before validating: Step 1 lookup: company_domain Step 2 score: company fields, seed_company, and the prompt with your closed-won profile Step 3 contact: company_domain and target_title Step 4 sequencer: email, name, company, angle, industry Step 5 CRM: domain, name, score, reason, seed_company Add run conditions: steps 2 to 5 skip customers, open deals, and owned accounts; steps 3 and 4 run only when score is 4 or more.Map them in the Clay UI${WF_URL:+ at $WF_URL}, or per node with: clay workflows nodes get $WF_ID <nodeId> clay workflows nodes update $WF_ID <nodeId> --input node.jsongraph.json in this folder shows the current nodes and edges. EOFread -r -p "Press Enter when inputs are mapped. " echo "9/9 Validate, test once, publish"clay workflows graph validate "$WF_ID"clay workflows diagram "$WF_ID" if jq -e 'all(.[]; . != "")' <<< "$TEST_ROW" > /dev/null; then read -r -p "Run TEST_ROW once? It can spend Clay credits, add a lead to your sequencer, and create a company in your CRM. [y/N] " answer if [[ "$answer" == [yY] ]]; then clay workflows runs test "$WF_ID" --inputs "$TEST_ROW" > test-run.json echo "Saved test-run.json. Check each step with: clay workflows runs steps $WF_ID <runId>" fielse echo "TEST_ROW is empty, skipping the test run."fi read -r -p "Publish the workflow now? [y/N] " answerif [[ "$answer" == [yY] ]]; then clay workflows publish "$WF_ID" --name v1fi echo "Workflow $WF_ID, CSV upload trigger $TRG_ID. All responses are saved in $(pwd)."Part 4: Candidate CSV
Save this as clay-lookalike-accounts/candidates.csv and replace the sample row with your export. Keep the headers exactly as shown, because they become the trigger inputs.
candidates.csv
company_domain,company_name,industry,employee_count,country,seed_company,target_titleexample.com,Example Co,Software Development,180,United States,Customer Co,VP of SalesPart 5: Run it on your candidates
After publishing, upload the CSV to the trigger and start with a few rows. Each row is one run.
Load the saved ids (run inside clay-lookalike-accounts/)
WF_ID=$(jq -r '.id' workflow.json); TRG_ID=$(jq -r '.id' trigger.json)Upload the CSV (this does not start runs)
clay workflows triggers csv upload "$TRG_ID" --file candidates.csvRun the first 5 rows (needs a published workflow, one run per row)
clay workflows triggers csv run "$TRG_ID" --limit 5List runs
clay workflows runs list "$WF_ID"Inspect one run
clay workflows runs get "$WF_ID" <runId>See each step's output for that run
clay workflows runs steps "$WF_ID" <runId>Verify in your workspace
The Clay CLI help does not document these details. Check each one before you rely on the build.
- The CSV trigger type "csv_upload" is inferred. If "triggers create" exits with code 2 (validation), check which trigger types your workspace accepts.
- The help documents "nodes create" with nodeType and name only. If it rejects actionPackageId and actionKey, create the node with a name only and pick the action in the Clay UI.
- The reference says action steps take actionPackageId and actionKey but shows only a utility example for "nodes insert", so the placement of those fields inside "step" is inferred.
- Only "workflows create" documents an id field in its response. The script reads .id from trigger and node responses too and stops if it is missing.
- Package ids and action keys differ by workspace and depend on which integrations you have connected. Copy them from your catalog; this page does not guess them.
- Step input mapping is dynamic per workspace. The CLI path is "nodes get" then "nodes update", where incomingEdges is a full replacement. The argument order for "nodes get" is inferred from "nodes update".
- The help does not say whether step 1 connects to the trigger automatically. "clay workflows graph validate" reports a disconnected graph.
- Domains must be normalized the same way on both sides (lowercase, no protocol, no www, no path) or the CRM check misses existing accounts.
- "runs test" without --live is assumed to run the draft. The reference lists --live without describing it.
- Workflow runs can spend Clay credits and write to connected tools. Exit code 3 means re-run clay login, and exit code 4 means you are rate limited (wait for details.retryAfter).
Keep going
Related playbooks
- ResearchIntermediate
Analyze Firmographics of Closed-Won Deals to Refine ICP
Your ICP doc was written years ago, and the company profile it describes may no longer match the deals you actually win.
ClayHubSpotClearbitEstimate: 4 hrs/week - OutboundIntermediate
Reactivate Closed-Lost Deals When Fresh Intent Appears
Closed-lost accounts sit untouched while they later raise, hire, or install related tools, and AEs rediscover them too late.
ClayHubSpot or SalesforceApollo+1Estimate: 6 hrs/week - RevOpsIntermediate
Build a Clay Waterfall to Find Verified Work Emails
A single data provider misses many contacts, so reps either work incomplete lists or pay for several tools and copy results between them by hand.
ClayApolloHunter or Prospeo+2Estimate: 4 hrs/week - OutboundIntermediate
Turn Buyer Intent Signals into Outbound Sequences
Intent data shows which accounts are researching your category, but it sits in a dashboard nobody checks daily, so the signal is stale before a rep acts on it.
ClayG2 Buyer Intent or BomboraApollo+2Estimate: 5 hrs/week - OutboundAdvanced
Build Prospect Lists from Plain-English Requests in Slack
Reps and marketers wait days for RevOps to build a prospect list, or pull their own from Apollo with inconsistent filters, no CRM dedupe, and no check on how many credits the pull will burn.
SlackZapier or MakeOpenAI API+4Estimate: 4 hrs/week
Need help implementing a playbook?
Our team builds custom Clay workflows and AI automations for revenue teams.
Get it built for you