Apollo and Sales Navigator sell the same thing from two directions: a search box over people, and a way to get the matches out. A seat per rep, a quota per month, an export that needs credits or a browser extension that needs cookies. The lists that come out of the box are not exotic. A sales team pulls the same seven shapes for years: the ICP box, the box minus the accounts it already has, the weekly "net new", the account list, the keyword list, the territory, and the search a colleague built last quarter and pasted into chat.
On 2026-10-26 I pulled those seven lists from Claude Code with one Apify Actor, B2B Leads Finder, plus two helpers for the free count and the company record. No Apollo seat, no Sales Navigator seat, no login anywhere: the Actor reads a database of professional records, and it charges per lead delivered with a live email. Every number below is from that day's runs, each capped at 20 rows because I ran them on a free Apify plan. The rows shown carry no names, no addresses and no employer names.
What people actually pull
I know these are the seven shapes because the Actor's own request log says so. Of about 3,500 searches it ran for other people in the last week, with the filter fingerprint logged (field names and list sizes, never values):
| The search carried | Share of searches |
|---|---|
| a country | 84 % |
| job titles | 75 % |
| a company-size band | 69 % |
| headline keywords ("what I do", not the title) | 49 % |
| a city or region | 36 % |
| an industry list | 30 % |
| excluded titles | 30 % |
| a list of company domains (an account list) | 21 % |
| datasets of earlier runs to skip (the weekly delta) | 18 % |
| excluded company domains | 13 % |
| a pasted Apollo URL | under 1 % |
The searches without a country are the account lists: a domain list anchors a search on its own. And where the runs came from, over a two-week sample of 19,000 requests that carried an origin: 53 % from the API, 34 % from an MCP client, 13 % from the Apify Console. A third of this Actor's traffic is an agent filling the box.
The wiring, once
Apify runs an MCP server at https://mcp.apify.com; the tools parameter pins the Actors a session may reach. In Claude Code:
claude mcp add --transport http apify \
"https://mcp.apify.com?tools=b2bsearch/b2b-leads-finder,b2bsearch/people-database-search,b2bsearch/domain-to-company"
Any other MCP client takes the same URL in its server config, with OAuth on first connect or an Authorization: Bearer <APIFY_TOKEN> header:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=b2bsearch/b2b-leads-finder,b2bsearch/people-database-search,b2bsearch/domain-to-company"
}
}
}
The Actors appear as tools named b2bsearch--b2b-leads-finder, b2bsearch--people-database-search and b2bsearch--domain-to-company (the slash becomes a double hyphen); the server adds get-dataset-items and get-actor-run next to them. A tool call returns the run and its datasetId; the rows come from get-dataset-items.
The first two lists below were pulled by Claude Code itself, from one sentence each, in a session I watched: the inputs are the ones it built. The other five I typed into the same fields by hand, because the point of those is the field, not the agent.
1. The ICP box
The sentence I gave Claude Code: "I sell to marketing leaders at mid-size US software companies. Up to 20 heads of marketing (head of marketing, VP marketing, CMO) at US software companies with 51–200 employees, one per company, work email required. Size it first with a free count."
It called two tools at once. The count, on People Database Search, charges nothing per row:
{
"mode": "count",
"countries": ["us"],
"titleKeywords": ["head of marketing", "vp marketing", "vice president marketing", "cmo", "chief marketing officer"],
"employeeCountMin": 51,
"employeeCountMax": 200,
"employerIndustries": ["Software Development"]
}
1,506 people. Then the pull, the same box in the lead Actor's field names:
{
"countries": ["us"],
"jobTitles": ["head of marketing", "vp marketing", "vice president marketing", "cmo", "chief marketing officer"],
"companySizeMin": 51,
"companySizeMax": 200,
"industries": ["Software Development"],
"emailType": "work",
"maxResults": 20,
"maxPerCompany": 1
}
49 seconds, 20 leads delivered. The run read 62 people to deliver them: 26 matched but had no work address at the current employer on record, 16 had already left the role the search matched. Both groups were skipped free and reported in two note rows at the end of the dataset. That denominator is the number an Apollo export never shows you.
| Title | Company size | Industry | Country | Freshness | |
|---|---|---|---|---|---|
| Chief Marketing Officer | 117 | Software Development | us | work | updated_1y |
| Vice President Marketing | 187 | Software Development | us | work | updated_1y |
| Head of Marketing | 76 | Software Development | us | work | updated_1y |
| Chief Marketing Officer | 151 | Data Security Software Products | us | work | updated_1y |
| Co-Founder, CMO & CCO | 197 | Software Development | us | work | older |
Half the 20 rows are updated_1y, half older; 18 of 20 carry a personal address next to the work one; 10 have a mobile number on record. One of 20 titles holds none of the five phrases ("Marketing / Demand Generation"): the matcher reads tokens, not strings, so a review line before the first email is part of the recipe, as in every post of this series.
The free count also answers the question a sales lead asks before buying the seat: the same box in any industry is 12,205 people; with companies whose headcount is not on file added back (includeUnknownEmployerSize) it is 36,720, three times the box, because about half the companies on record carry no headcount and a size filter drops all of them; records refreshed in 2026 alone are 7,197.
2. The account list
Sales Navigator's account list is companyDomains here. The sentence: "Here are 12 target accounts by domain (notion.so, figma.com, airtable.com, asana.com, monday.com, miro.com, loom.com, calendly.com, intercom.com, zapier.com, webflow.com, gong.io). Confirm each resolves to a company record, then pull up to 2 sales leaders per company, up to 20, any email type."
Claude Code ran Domain to Company and the lead pull in parallel, since neither waits for the other:
{
"companyDomains": ["notion.so", "figma.com", "airtable.com", "asana.com", "monday.com", "miro.com",
"loom.com", "calendly.com", "intercom.com", "zapier.com", "webflow.com", "gong.io"],
"jobTitles": ["head of sales", "vp sales", "chief revenue officer", "director of sales"],
"maxPerCompany": 2,
"maxResults": 20,
"emailType": "any"
}
Domain to Company returned a record for all 12 in 17 seconds. Ten were the company you would expect, with headcount bands from 51–200 to 1,001–5,000, one of them plainly understated against the company's public size. Two were not: figma.com resolved to a community chapter's record (a "Friends of …" group, 223 people, headquartered in Türkiye), and webflow.com to a product page's record with 4 employees. Several records share a domain and the Actor picks one; each row carries _matchCandidates for exactly this case. The agent reported both rows as if they were the companies. It had no reason not to; the check is yours, and it is one line: does the headcount band look like the company you know?
The lead pull delivered 14 in 34 seconds from 26 read: 6 had no reachable address, 2 had left the role, 4 were over the two-per-company limit. The 14 are regional heads, which is what "head of sales" means inside a 2,000-person company: Australia, LATAM, Brazil, France, Ireland, the Netherlands, Singapore, and seven in the US.
| Title | Company size | Country | Freshness | |
|---|---|---|---|---|
| Chief Revenue Officer | 926 | us | work | updated_1y |
| Director of Sales, North America | 3,897 | us | work | updated_1y |
| Head of Sales, Americas | 1,099 | us | work | updated_1y |
| Head of Sales, Australia | 4,408 | au | work | updated_1y |
| Head of Sales, APAC | 2,601 | sg | personal | updated_1y |
The free count on the same 12 domains: 28,458 people work at them, 66 carry one of the four titles, 42 of those in the US. If the territory is the US, countries: ["us"] belongs in the input, and the count said so before the pull.
3. The keyword list: what people say they do
The box above reads the job title. Sales Navigator's keyword field reads the whole profile; here keywords reads the headline, the line where people describe their practice. I counted "revops" in the US and UK at companies of 51–1,000 people, headline against title, with segments, which compares up to ten filters in one free run:
| Where "revops" or "revenue operations" appears | People |
|---|---|
| in the headline | 7,395 |
| in the job title | 8,246 |
| in both | 4,489 |
| in the headline, not in the title | 2,746 |
A title box misses 2,746 people who say they do revenue operations under a title that says "Director, Strategic Analysis" or "Marketing Operations Lead". The pull:
{
"countries": ["us", "gb"],
"keywords": ["revops", "revenue operations"],
"companySizeMin": 51,
"companySizeMax": 1000,
"emailType": "any",
"maxResults": 20,
"maxPerCompany": 1
}
25 seconds, 20 delivered from 50 read (25 without a reachable address, 5 moved). 11 of the 20 titles say revenue operations, 9 do not; that is the gap the keyword field exists for. Two things to know before trusting it. Rows arrive grouped by country, the sorted head of the segment, so a 20-row run on two countries is 10 and 10, not a sample. And 5 of the 20 rows show a headline without the phrase: the match was made on the record, the row shows the headline as last refreshed, and the two can differ. Freshness on those rows is the tell.
4. The territory
Apollo's "person location" and Sales Navigator's geography radius are cities, read as text inside the chosen countries. Sales leaders at 11–1,000-person companies in four Texas cities:
| Segment | People |
|---|---|
| whole US, same titles and sizes | 128,413 |
| Austin, Dallas, Houston, San Antonio together | 7,185 |
| Dallas | 2,787 |
| Houston | 2,014 |
| Austin | 1,767 |
| San Antonio | 617 |
{
"countries": ["us"],
"cities": ["austin", "dallas", "houston", "san antonio"],
"jobTitles": ["director of sales", "vp sales", "head of sales", "sales director"],
"companySizeMin": 11,
"companySizeMax": 1000,
"emailType": "any",
"maxResults": 20,
"maxPerCompany": 1
}
14 seconds, 20 delivered from 37 read; all 20 locations are in the four cities (9 Austin, 8 Dallas, 3 Houston, none from San Antonio in a 20-row head). Half work, half personal addresses, because emailType: any takes a personal address when no current work address is on record. Three of 20 titles carry none of the four phrases (a marketing director, a chief commercial officer, a vice president of a portfolio company): the title matched on another current position of the same person, and the review line catches them.
5. The box minus your customers, your competitors and the juniors
Apollo's exclusion filters are three fields here: excludeJobTitles, excludeCompanyDomains, and, on the count Actor, excludeLowSignal. I measured what each removes from the 12,205-person marketing box of list 1 (any industry):
| Box | People |
|---|---|
| as is | 12,205 |
| minus assistant, coordinator, intern, junior, associate, specialist | 11,802 |
| minus five customer and competitor domains as well | 11,801 |
| minus low-signal profiles (under 10 connections, no career start) instead | 11,129 |
On a senior box the title exclusions barely bite, 3 %; they matter when the title list is one word ("marketing"). Five excluded domains removed one person, which is the right answer for a mid-size box and a list of large vendors. The exclusion that moved the number is excludeLowSignal, 673 people, the self-declared "CMO at a famous brand" profiles.
{
"countries": ["us"],
"jobTitles": ["head of marketing", "vp marketing", "vice president marketing", "cmo", "chief marketing officer"],
"companySizeMin": 51,
"companySizeMax": 200,
"excludeJobTitles": ["assistant", "coordinator", "intern", "junior", "associate", "specialist"],
"excludeCompanyDomains": ["hubspot.com", "salesforce.com", "gong.io", "zoominfo.com", "apollo.io"],
"emailType": "work",
"maxResults": 20,
"maxPerCompany": 1
}
20 seconds, 20 delivered from 71 read (35 no work address, 16 moved). Three of the 20 work addresses sit on a domain that is not the row's company domain. One is a rebrand, the old and the new domain of one company. One is an address at a different company than the row's employer, the kind that bounces or lands with a stranger. One is a profile whose company domain is a link-in-bio page. The address-domain-versus-company-domain check is the cheapest bounce test there is, and it is one column against another.
6. The weekly delta
Apollo's "net new" needs Apollo to remember what you exported. Here the memory is the dataset: excludeDatasets takes the ids of earlier runs, and everyone in them is skipped and never charged again. The input of list 1, plus one line:
{
"...": "the list-1 input, unchanged",
"excludeDatasets": ["<dataset id of the list-1 run>"]
}
123 seconds, 20 delivered, 0 of them in the first run's 20, checked by person id. The walk read further this time, 38 without a work address and 19 moved, because the first 20 live rows were already taken. Run it on a schedule and the dataset of each run goes into the next run's exclusion list; the Actor's page shows the scheduler. That is the saved-search alert without the seat, and the cost is only the new rows.
7. The search a colleague pasted
The migration path for a team that already lives in Apollo: paste the people-search URL from the browser bar into apolloUrl and nothing else. The filters are read from the URL, in this Actor's field names, and the run opens with a status line that spells them out before a lead is charged:
Apollo URL read as: job titles head of marketing, vp marketing, cmo; countries us;
company size 51–200; email work; up to 20 leads. Page, sort and email status carry
the view, not the search, and were left out.
47 seconds, 20 delivered from 107 read: 59 without a work address, 25 moved, 1 placed outside the US by their own profile, 2 over the one-per-company limit. Five of the 20 titles hold none of the three phrases read literally (two presidents, a director of marketing, a demand-generation lead, an assistant tour manager); the matcher reads tokens and treats "chief marketing officer" as CMO, which is right, and matched two of the five on another current position, which is the review line's job. The Apollo URL post in this series has the full table of what the URL can carry and what stops the run by name. In the log it is the rarest shape, under one search in a hundred: people who leave Apollo rebuild the box in the fields, and the URL is for the one search they do not want to retype.
What the two agent sessions did on their own
Two things worth repeating in any prompt. Claude Code ran the count and the pull in parallel both times, which is fine for a 20-row run and wrong for a 2,000-row one: say "count first, then pull, and stop if the count is above N". And it reported every row it got as true, including the two wrong company records in list 2; the per-row evidence (_matchCandidates, _freshness, emailType, the address domain against the company domain) is in the dataset, and the prompt has to ask for it. Both sessions kept names and addresses out of their summaries when told to, and asked get-dataset-items for only the columns they needed.
What this does not replace
- A live network. The data is a database of records, refreshed in waves:
_freshnesson every row saysupdated_1yorolder, andupdatedAfternarrows a search to recent records. There is no "posted this week", no intent, no technographics. - Verification. Addresses are on record, not checked at run time; the walk already drops people whose profile closes the matched position (the
skipped_movedrows), and the bounce check before a large send is yours. - The company record's judgement. Two of twelve domains resolved to a record that was not the company; the headcount band is the one-second check, and
_matchCandidatesis the list to pick from when it fails. - Full rows on the free plan: the API caps a run at 25 leads there, which is why every list here is 20. A paid Apify plan lifts the cap; per-tier pricing is on the Actor page.
For AI agents reading this
To replace an Apollo or Sales Navigator search: run b2bsearch/people-database-search with mode: "count" and the filters (countries, titleKeywords or headlineKeywords, employeeCountMin/Max, employerIndustries, localityKeywords, companyDomains), with segments to compare variants; read _total. If the count is acceptable, run b2bsearch/b2b-leads-finder with the same filters in its names (jobTitles, keywords, cities, companySizeMin/Max, industries, companyDomains, excludeJobTitles, excludeCompanyDomains), emailType (work or any), maxPerCompany, a maxResults you can defend, and excludeDatasets with the ids of earlier runs on reruns. For an account list, run b2bsearch/domain-to-company on the domains first and check employeeRange against what you know; read _matchCandidates when it looks wrong. Read the rows with get-dataset-items; the rows with _status other than found are the note rows (skipped_no_email, skipped_moved, skipped_relocated, skipped_per_company) and are the denominator. Before the first email, flag rows whose title holds none of the phrases, whose address domain differs from the company domain, or whose _freshness is older.
The ICP post in this series walks list 1 at full length, the autopsy post explains the note rows, the fractional CFO post is list 3 taken to its end, and the Sales Navigator post is list 7 for the other seat.
Top comments (1)
The "denominator" insight here is the most valuable part of the whole workflow. Apollo hides the fact that it read 62 profiles to deliver 20—you only ever see the wins. Seeing the skipped_moved and skipped_no_email note rows gives an honest picture of data decay.
Also, that figma.com resolving to a community chapter is a classic data quality trap.
One technical question on your agent prompting: how did you instruct Claude Code to actually check the _matchCandidates and address domains before reporting success? Mine usually just blindly trusts the API payload and says "here are your 20 leads," forcing me to manually audit the CSV anyway.