8 min read

I built an agent that finds buyers in anonymous traffic

Table of Contents

A client’s dashboard told me a 200-person building automation firm had spent time on their pricing page that morning. Good lead. Exactly the kind of company they sell to.

Then I went to push it into the cold email sequence and found out I couldn’t. Not because of a bug. Because RB2B’s native Instantly integration doesn’t accept company-level visitors, and it says so in the docs:

At the present time, the Instantly integration does not allow for the sending of company-level visitors.

Source: RB2B Instantly FAQs

That would be a footnote if company-level were a rounding error. It isn’t. RB2B’s own benchmark is 40 to 45% contact-level identification on unique US traffic. So somewhere north of half of everything the pixel identifies resolves to a company and no person, and the native integration has nowhere to put it.

Half your intent data, sitting in a dashboard, decomposing.

The fix is four steps. Three of them are harder than they sound.

1. What actually shows up

When only the company resolves, here’s the whole payload:

{
"Company Name": "Northwind Labs",
"Website": "https://northwindlabs.example",
"Industry": "Computer Software",
"Employee Count": "201-500",
"City": "Arlington",
"State": "VA",
"Referrer": "https://www.google.com/",
"Captured URL": "https://example.co/pricing"
}

No name. No email. No LinkedIn. You get a company, a rough size, a location, and the page they cared about.

Note what isn’t there: a country field. City and State only. That becomes a problem in step three, and the fix is hiding in plain sight.

2. Finding the decision makers

“Just enrich the company and find the buyers” is one sentence and about four days of work.

Gate before you spend. Every person you reveal in Apollo costs a credit. Before writing any of this I audited ten days of the client’s identified traffic by hand against their ICP. 70% were offshore agencies browsing for design inspiration, a 500,000-employee consultancy’s overseas office, two trade schools, and a medical regulatory council in Brazil.

Enrich everything and you’re paying to find buyers at companies you’d never sell to, then emailing them. Gate first, enrich second. That order is the whole cost model.

Then rank, don’t just fetch. This is the part I got wrong three separate times.

Apollo returns people in no useful order. My first version took the first three decision-maker-ish titles it found. Here’s the actual shortlist it produced for one company:

Co-Founder & CEO (100)
Director of Product Marketing (70)
Head of Payments | Principal Product Manager (0)
Director of Enterprise & Mid-Market Sales (0)

That company’s CTO and VP of Engineering are not in that list. They exist. They just weren’t in the first page of results, because I’d set per_page=10 on a search that costs nothing to widen. Search is free in Apollo. Only the reveal costs. Pull 50, rank the whole pool, then spend credits on the top of it.

Also note Director of Product Marketing scoring 70 and sitting second. My title matcher was checking whether “director of product” appeared in the title. It does appear in “director of product marketing.” A product marketing director is not buying an engineering retainer.

And the ranking itself needed the titles normalised before matching, because this happened:

[ 40] Senior Vice President, Engineering
[ 40] Vice President Human Resources
[ 40] Vice President, Client Management

Everyone scored 40 because “president” is a substring of “vice president,” so every VP matched the low-tier pattern and nothing else. Collapse the variants first, then match on word boundaries:

for long, short in (("senior vice president", "svp"),
("vice president", "vp"),
("chief technology officer", "cto")):
t = t.replace(long, short)

After that, plus a filter that zeroes out non-buying functions (marketing, sales, HR, compliance, legal), the same company ranked properly:

[100] Co-Founder, CTO
[ 90] Chief Technology Officer
[ 85] Senior Vice President, Engineering
[ 75] Vice President of Application Development
[ 0] Vice President Human Resources

Last one: never pad the quota. “Top 3 decision makers” means up to three qualified people, not three people. Ranking only orders the list. On a company with two real buyers, my code happily filled the third slot with a Head of People Operations, because she was next. That’s a wasted credit and, worse, an email to someone who will wonder why she got it.

One more trap. When Apollo has no domain on a company record, the obvious fallback is searching by name. That search is fuzzy. Looking up “Summit Controls” also returns “Summit Controls Group,” a different company in a different state. Enrich that and you’re cold-emailing executives at a business that has never heard of you and never visited your site. If a company was matched by name rather than by domain, don’t resolve people from it at all.

3. Verifying it

Enrichment gives you plausible addresses. You are about to send from domains you care about, so plausible isn’t the bar.

The catch-all problem. MillionVerifier returns catch_all for a large share of perfectly real B2B domains, because the mail server accepts everything and tells you nothing. My first pass treated that as a hard fail. It immediately discarded the single best-fit lead on the list, a co-founder at a US SaaS company who’d hit the pricing page twice.

So now a catch_all is not a verdict, it’s a tiebreak. It sends only when Apollo independently reports the same address as verified:

tiebreak accepted [email protected] (mv=catch_all, apollo=verified)

Two providers disagreeing is information. One provider hedging is not. unknown and invalid stay hard fails.

Geo, from the fields you have. Remember there’s no country in the payload. But there is a State, and a two-letter region that isn’t a US state or Canadian province tells you plenty. PB is Punjab. 34 is Istanbul.

This caught an offshore agency that had already made it to the enrichment stage in production, on day one, and was only stopped because Apollo happened to have no contacts for it.

It is also not sufficient on its own, and you should know why: TN is Tennessee and also Tamil Nadu. GA is Georgia and also Goa. So this is a cheap pre-filter, backed by an authoritative country check after enrichment. Two cheap layered checks beat one clever check that you trust too much.

Don’t email someone already in a sequence. Obvious at the person level. Less obvious at the company level: if a colleague of theirs is mid-sequence, skip the whole company. Otherwise two different pitches land at one company in the same week and you look like a spray.

4. Sending it

Here’s the trap that only exists for company-level.

These people did not visit your website. Somebody at their company did, and you don’t know which one. So the line that works beautifully for person-level identification, “noticed you were checking out our pricing,” is now a claim you cannot attribute to the person reading it. Send that to three colleagues and at least one of them knows it wasn’t them.

Company-level needs its own campaign and its own opening. Lead with something useful. Never claim a visit you can’t attribute.

Then the boring parts that matter: dedupe against your sending tool workspace-wide before adding anyone, cap daily volume so a traffic spike can’t turn into a blast, and log what you sent to whom.


The native integrations are fine. They’re just built for the easy half, where a name and an email arrive gift-wrapped and you can pipe them straight into a sequence.

The other half needs you to decide whether the company is worth anything, work out who inside it actually buys, prove the address is real, and write copy that doesn’t lie about how you found them. None of those are integration problems. They’re judgment problems, which is why the integration doesn’t have them.

That’s also why the half nobody automates is the half worth automating.

Interested in an audit on your GTM stack?

Grab 30 minutes with me here: cal.com/dylanbaker