DEV Community

Timothy Kelvin
Timothy Kelvin

Posted on

I built an Apify Actor that turns a list of company domains into a ranked "who to call first" list

If you've ever done account-based prospecting, you know the drill: pull open
roles from a company's careers page, eyeball their homepage for what tools
they're running, dig up a contact email, then repeat that for every account
on the list — and manually decide who actually looks worth calling first.

I build small data-focused Apify Actors as a side project, and this one
(Company Buying Signal Report) started from wanting to stop doing that
join by hand.

What it does

Give it a list of company domains. For each one it pulls three signals in
parallel:

  • Hiring signal — open roles straight from the company's own Greenhouse or Lever job board API (the same public JSON endpoints that power their careers page), matched against a list of role keywords you care about ("account executive", "growth", whatever signals urgency for your product).
  • Tech stack fingerprint — CMS, ecommerce platform, analytics, payment, and live-chat tools detected from response headers, meta tags, and script sources on the homepage — the same signature-matching approach tools like Wappalyzer use.
  • Public contact info — email, phone, and social links pulled from the homepage and one linked contact/about page.

Then it computes a low/medium/high buying-signal score with the actual
reasons behind it ("142 open roles (actively scaling)",
"uses paid ecommerce/payment/chat/analytics tooling"), so the output is a
ranked call list, not three raw feeds you still have to reconcile yourself.

The part I actually had to think about: slugs

Greenhouse and Lever both key their public job-board API by a "slug" —
boards-api.greenhouse.io/v1/boards/{slug}/jobs — and that slug usually,
but not always, matches the company's domain name. stripe.comstripe
works. Plenty of companies don't follow that pattern.

The actor guesses the slug from the domain by default (fast, works most of
the time), but lets you pass greenhouseSlug/leverSlug explicitly per
company when you already know it (it's sitting right there in the careers
page URL). Rather than silently returning nothing for a guess that misses,
it's an explicit opt-in override — a small design choice, but the kind of
thing that's easy to get wrong in either direction (over-trusting a guess,
or forcing every user to look up slugs manually even when the guess would've
worked fine).

No proxy, no login, no headless browser

All three signals come from data companies already publish for anyone to
see — their own careers-page API, their own homepage HTML, their own contact
page. No scraping behind auth, no browser automation, no residential proxy
bill. It's just three passive HTTP lookups run per company and joined into
one row.

Why billed per company, not per signal

It's priced as one charge per company report, regardless of whether that
company has 3 open roles or 300, or how many tech-stack signatures matched.
The point of combining the three lookups was to replace three separate tool
runs (and the spreadsheet join after) with one — pricing it per sub-signal
would've defeated that.


If you're doing target-account prioritization and this saves you a step:
try it on Apify
· source on GitHub

Happy to answer questions about the Greenhouse/Lever API shapes or the
signature-matching approach if anyone's building something similar.

Top comments (0)