Open menu

How to Build a Lookalike Account List With the CUFinder API

How to Build a Lookalike Account List With the CUFinder API

Your best customer is a 200-person logistics company in the Netherlands. You’d love forty more just like them.

So how do you find them? Most people open LinkedIn and start filtering by industry and headcount, which sort of works, but it misses the companies that look nothing like your filters and everything like your customer.

Here’s the API version of building a lookalike account list. It takes the companies you already love and hands you back the ones that resemble them: scored, ranked, and ready for your CRM.

What a lookalike account list is (and isn’t)

A lookalike account list is a set of named companies that resemble your best existing customers, built for sales and ABM outreach.

That word “named” is doing the heavy lifting, because there are two things people mean by “lookalike” and they get confused constantly:

  • A lookalike ACCOUNT list: actual company names your team can research, call, and route to reps. You own the list. This article builds one of these.
  • A lookalike AUDIENCE: an anonymous targeting segment inside an ad platform. You upload a source audience, and Meta’s lookalike system (or LinkedIn’s equivalent) finds similar people to show ads to. You never see who’s in it.

Both are built on the same idea: start from who’s already good, find who’s similar. But an ad audience lives and dies inside one platform, while an account list feeds everything: outbound, account-based marketing, partnerships, even your ads targeting if you upload it as a company list.

And do lookalikes still work? For account lists, yes: firmographic similarity is durable, because “companies like our best customers” is just your ideal customer profile expressed as evidence instead of opinion. The ad-platform version depends on signal quality that shifts year to year. Lists are the sturdier bet.

Under the hood, the matching compares a company’s profile (industry, size band, location, business type, and the rest of its firmographic shape) against the seed’s, and returns the closest neighbours. Firmographics, if the word is new, are simply the demographic facts of a company: what it does, how big it is, where it sits. Which means the quality of your output is decided by ONE input: the seed. Garbage seed, garbage neighbourhood. That’s why the next two decisions (which customer, and how many) get their own sections.

The idea in one line

Your best accounts → find their lookalikes → pool the overlaps → score against your ICP → ranked list

Two endpoints do the work:

ICP, for anyone new to the term, is your ideal customer profile: the industry, size, geography, and business model of the customers you win and keep. Hold that thought, because the scoring step turns it into code.

Step 1: Get the lookalikes

from cufinder import Cufinder

client = Cufinder('your-api-key-here')

similar = client.fcl('apple')
print(similar)

One company in, a list out. The query argument takes a company name, a domain, or a LinkedIn company URL, and when you have the domain, use the domain. “Apple” is ambiguous; apple.com isn’t.

Here’s the part the old me didn’t appreciate: the response doesn’t just name similar companies. Each entry under data.companies arrives with its firmographics already attached:

{
    "status": 1,
    "data": {
        "confidence_level": 98,
        "query": "apple",
        "companies": [
            {
                "name": "amazon",
                "domain": "amazon.com",
                "employee_count": 747435,
                "size": "10,001+",
                "industry": "software development",
                "country": "united states",
                "state": "washington",
                "city": "seattle",
                "type": "public company",
                "linkedin_url": "linkedin.com/company/amazon",
                "founded_year": null,
                "followers_count": 31850999
            }
        ]
    }
}

Name, domain, industry, size band, headcount, location, company type: that’s enough to score a candidate WITHOUT paying for another call. Remember that; it’s the money-saver the whole pipeline is built around. The reference lists the endpoint at 98% confidence, and each record found costs 5 credits.

What does that confidence figure mean in practice? That the returned companies really are who the record says they are; it’s a data-accuracy claim, not a promise that every candidate fits YOUR business. Fit is your scoring function’s job. The API’s job is not lying to you about headcount.

In TypeScript, same one-liner:

const similar = await client.fcl('apple');

But here’s where people go wrong before they’ve written a line of code: they seed with their biggest logo instead of their best-fit customer. Those aren’t the same thing. Seeding with an enterprise account you closed once by luck will hand you forty more enterprises you’ll never close.

📌 Seed rule: seed with the customer who renewed twice and referred someone, not your biggest logo.

I learned this the embarrassing way. In 2023 I seeded an ABM push from our shiniest enterprise logo, the deal everyone mentioned in board slides. The lookalike list came back full of household-name enterprises, sales chased them for a quarter, and we closed exactly none. Then we reseeded from two mid-market customers who had renewed twice and expanded, and the very same workflow produced a list the team actually converted from. Same code. Different seed. Completely different quarter.

Step 2: Seed from several customers, not one

So which customers do you seed with? Three to five of your best-fit ones, because one seed gives you one neighbourhood, and three or four seeds give you the shape of your actual market.

“Best-fit” deserves a definition, because it’s where this goes right or wrong. My checklist for a seed:

  • Renewed at least once: they chose you twice
  • Expanded or upgraded: the product genuinely lands there
  • Referred someone, or would: the strongest fit signal there is
  • Closed in a normal sales cycle: not a heroic one-off

And the anti-seeds, which feel tempting and poison the list: the biggest logo (prestige isn’t fit), the newest win (no renewal evidence yet), and the account one loud stakeholder loves for reasons nobody can articulate. Pick boring, proven customers. Boring seeds build lists that close.

from collections import Counter

SEEDS = ['acmelogistics.com', 'northwindfreight.com', 'brightlineshipping.com']

def pooled_lookalikes(client, seeds):
    counts = Counter()
    profiles = {}
    for seed in seeds:
        res = client.fcl(seed)
        for c in res.get('data', {}).get('companies') or []:
            domain = c.get('domain')
            if domain:
                counts[domain] += 1
                profiles[domain] = c
    return counts, profiles

That Counter is the whole trick. A company that shows up as a lookalike for three of your best customers resembles your MARKET, not just one account, and that overlap count is the strongest single signal in this entire workflow.

Notice we key the counter by domain, not by name. The same company can surface as “Acme”, “Acme Corp”, and “Acme Corporation” across three calls, but acme.com is acme.com every time. Domains dedupe for free.

And the overlap costs you nothing extra to compute. You already made the calls.

One practical warning from doing this a dozen times: run the seeds in one sitting and keep the raw responses. If you pool seeds enriched weeks apart, you can’t tell whether a company appearing once means “weak match” or “wasn’t checked against the newer seeds.” Same-day pooling keeps the overlap signal honest, and the saved responses mean you can re-tune the scoring later without paying for the calls again.

Step 3: Score against your ICP

That’s the candidate pool. Now let’s rank it.

Because the lookalike response already carries industry, size, and country, you can score every candidate before spending another credit. A simple weighted function over the returned fields is genuinely enough:

ICP = {
    'industries': {'transportation, logistics, supply chain and storage'},
    'sizes': {'51-200', '201-500'},
    'countries': {'netherlands', 'germany', 'belgium'},
}

def score(company, overlap):
    s = 0
    if company.get('industry') in ICP['industries']:
        s += 3
    if company.get('size') in ICP['sizes']:
        s += 2
    if company.get('country') in ICP['countries']:
        s += 2
    s += overlap        # resembles 2+ of your customers = strongest signal
    return s

Tune the weights to your business; the exact numbers matter less than the discipline of writing them down. A scoring function is your ICP made testable, and the first time it disagrees with your gut about a candidate, one of the two is wrong in an instructive way.

Why score BEFORE enriching, and not the other way around? Order of operations is the whole economy of this pipeline. Scoring on the fields you already hold is free. Enrichment costs credits per record. Run the free filter first and the paid step only touches winners. Run them in the other order and you’ve paid full price to learn which candidates you never needed.

Then, and only then, enrich the shortlist. Company Enrichment takes the same kind of query (name, domain, or LinkedIn URL) and returns the fuller record (founded year, address, description, the works) at 4 credits per record found:

detail = client.enc('cufinder')

One honest note on scope, because I promised you no surprises: enrichment gives you the company profile, not everything imaginable. If your ICP scoring needs revenue bands, revenue lives on its own endpoint, and technology signals have a dedicated tech stack finder. Bolt those onto the shortlist step only if your scoring genuinely uses them; every extra call per candidate multiplies across the list.

Putting it together

Here’s the whole build in one function: seeds in, ranked and enriched list out. Deliberately plain code, because a list-building script should be something anyone on the team can read and tweak:

import time
from collections import Counter
from cufinder import Cufinder

client = Cufinder('your-api-key-here')
SEEDS = ['acmelogistics.com', 'northwindfreight.com', 'brightlineshipping.com']

def build_list(min_overlap=2, enrich_top=50):
    counts, profiles = Counter(), {}
    for seed in SEEDS:
        try:
            res = client.fcl(seed)
            for c in res.get('data', {}).get('companies') or []:
                domain = c.get('domain')
                if domain:
                    counts[domain] += 1
                    profiles[domain] = c
        except Exception as e:
            print(f'lookalike call failed for {seed}: {e}')
        time.sleep(0.7)

    shortlist = [d for d, n in counts.most_common()
                 if n >= min_overlap][:enrich_top]
    print(f'{len(counts)} candidates, {len(shortlist)} passed the overlap filter')

    ranked = []
    for domain in shortlist:
        c = profiles[domain]
        row = {'domain': domain, 'name': c.get('name'),
               'overlap': counts[domain], 'score': score(c, counts[domain])}
        try:
            row['detail'] = client.enc(domain).get('data', {}).get('company')
        except Exception as e:
            print(f'enrichment failed for {domain}: {e}')
        ranked.append(row)
        time.sleep(0.7)

    return sorted(ranked, key=lambda r: r['score'], reverse=True)

See the min_overlap filter? That’s your credit saver. You might get 400 candidates back across three seeds, but only 60 of them appear more than once, and those are the only ones worth the enrichment call.

The time.sleep(0.7) keeps you under the 100 requests per minute cap; exceed it and you’ll get a 429 mid-run. For bigger builds, swap the flat sleep for retries with backoff, but honestly, at lookalike-list volumes the sleep is usually fine.

Reading the output before you ship it

The pipeline hands you rows like this: a domain, a name, an overlap count, a score, and the enriched detail. Before any of it reaches a CRM, do two things.

First, skim the top twenty by score, with a human eye. You’re looking for the candidates that pass every filter and still feel wrong: the consulting firm that matches your industry label, the reseller that matches your size band. Kill them manually and, if a pattern emerges, turn the pattern into a new scoring rule. The list gets smarter every quarter this way.

Second, look at the score DISTRIBUTION, not just the ranking. A healthy build has a clear top tier and a long tail. If every candidate scores nearly the same, your ICP definition is too loose to discriminate; widen the weights or tighten the sets. And if almost nothing clears min_overlap, your seeds are too different from each other; they’re describing three markets, not one.

What does a lookalike run cost?

For a three-seed build with a filtered shortlist, a few hundred credits under the documented per-call costs. Here’s the arithmetic:

💡 Credit math: 3 lookalike calls (5 per record found) → overlap filter keeps 60 → enrich 60 × 4 credits. Enriching all 400 candidates instead would cost ~7x more, for a worse list.

That last clause is the point people miss. Skipping the filter doesn’t just waste credits; it produces a WORSE list, because the one-seed-wonder candidates dilute the genuine market-shaped ones. The cheap version and the good version are the same version. It’s rare that economics and quality agree this hard, so enjoy it.

Two billing behaviors to know: calls that return no match generally don’t charge you, and duplicate inputs are charged separately, so dedupe your seed list too, in case two stakeholders nominated the same favorite customer.

Put real numbers on it and the shape gets even clearer. Three seeds returning, say, 130 candidates each is 390 records at 5 credits; that part’s fixed. The variable part is enrichment: 60 shortlisted × 4 credits versus 390 × 4 credits. The overlap filter just turned the biggest line item into the smallest one. And because a lookalike build runs quarterly, that saving repeats four times a year without anyone thinking about it again.

What breaks

Your seed is too generic. Seed with a household name and you’ll get other household names, which are useless to you. Seed with companies your size, in your niche; the ten-second test below catches this instantly.

Everything comes back in one country. Lookalike matching leans on the seed’s profile, so a US-only seed set gives you a US-heavy list. If you sell into three regions, seed from customers in all three, deliberately.

You already sell to half the list. Always diff the output against your CRM before it reaches sales. Nothing kills trust in a list faster than existing customers showing up as “new” prospects. I’ve watched a rep spot their own account in row three of a “fresh” list; you don’t rebuild credibility from that in one quarter.

Mixed business models sneak in. A company can match your seed’s industry and size while selling in a completely different motion: an agency that looks like a SaaS on paper. That’s what the type field and a human skim of the top twenty are for. Similarity finds resemblance, not intent; the last mile of judgment stays yours.

Your “ICP” is secretly two ICPs. If the overlap filter keeps coming up empty, your best customers may genuinely belong to two different markets: say, mid-market logistics AND enterprise retail. Don’t average them into mush. Split the seeds into two pools, build two lists, and let each one be coherent.

How this fits your ABM motion

A ranked list is the start of the motion, not the end. Here’s the handoff pattern that works:

  • Route the top tier to owners. The high-score, high-overlap accounts get named reps and real research; they’ve earned it.
  • Fill the accounts with people. A company list becomes a pipeline when you find the decision-makers inside each account; that’s its own workflow, and I’ve written it up in build a targeted prospect list.
  • Refresh quarterly. Company attributes move slowly, and your seed set changes even more slowly. Rebuild four times a year, diff against the previous list, and hand sales only what’s new.

And measure it like you’d measure any source. Tag the accounts that came from the lookalike build and compare them against your cold-sourced accounts a quarter later: reply rate, meetings booked, win rate. In my experience the lookalike tier reliably outperforms cold filters, but YOUR numbers are the ones that will keep this workflow funded. A list that can show its win rate never has to argue for its budget.

One more honest boundary: this list tells you who RESEMBLES your customers, not who is ready to buy. Resemblance plus timing is the winning combination; layer intent or trigger signals on top for the accounts you work hardest.

🧠 Ten-second test: read one seed's lookalikes out loud to the account owner. Their face tells you whether the matching fits your market, before you build anything else.

Frequently asked questions

What is a lookalike audience in marketing?

An anonymous ad-platform segment of people who resemble a source audience you upload. It’s a targeting mechanism inside Meta or LinkedIn, different from a lookalike account list, which is a named set of companies you own and work directly.

Do lookalike audiences still work?

For sales lists, yes: firmographic similarity to proven customers is a durable signal. For ad platforms it varies with each platform’s data quality, which is exactly why owning a named account list is the safer foundation.

How do I create a lookalike list from my customer list?

Pick three to five best-fit customers as seeds, run a lookalike call for each, pool the results, and keep the companies that appear for more than one seed. Then score the survivors against your ICP and enrich only the shortlist.

How many seeds should I use?

Three to five works well. Fewer and you get a narrow neighbourhood, more and the overlap signal gets noisy because almost everything matches something.

Can I filter lookalikes by size or country directly?

Not in the lookalike call itself. But the response already includes size, industry, and country for every candidate, so filter and score on those fields after the call, or go filter-first with Company Search when you’d rather describe your target than seed from an example.

How often should I rebuild the list?

Quarterly is plenty for most teams. Company attributes move slowly, and your seed set changes even more slowly. Diff each rebuild against the last so sales only sees genuinely new accounts.

Try it with one seed

Take your single best customer: the one who renewed, expanded, and never makes you nervous at contract time. Run client.fcl() on their domain and read the list out loud to whoever owns that account.

You’ll know within about ten seconds whether the matching works for your market, and that’s a much faster answer than building the whole pipeline first and hoping. Then add seeds, add the scorer, and let the overlap filter do its quiet magic.

Forty more customers like your best one isn’t a fantasy. It’s three API calls, a Counter, and the discipline to seed with the right companies. The rest of the API workflow guides are here when you’re ready to chain this into something bigger.

How would you rate this article?
Bad
Okay
Good
Amazing
Comments (0)
Comments (0)
98% accuracy, GDPR & CCPA ready

Prefer to Explore on Your Own?

Skip the call and start free: 15 credits, no credit card required. Upgrade or talk to us whenever you’re ready.

Free plan available · 50 credits/month · no credit card required