B2b Lead Qualifier avatar
B2b Lead Qualifier

Pricing

Pay per usage

Go to Apify Store
B2b Lead Qualifier

B2b Lead Qualifier

Score and rank B2B leads by analyzing company websites for 30+ business quality signals. Get a score (0-100), letter grade, and transparent signal breakdown for every domain. No AI keys needed — pure rule-based scoring. Integrates with Website Contact Scraper and Email Pattern Finder.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

ryan clinton

ryan clinton

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

0

Monthly active users

6 days ago

Last modified

Share

Score and rank B2B leads by analyzing company websites for business quality signals. Give it a list of domains and get back a score (0-100), letter grade (A-F), and a breakdown of exactly which signals contributed to the score.

No AI API keys needed. Pure rule-based scoring from publicly visible HTML — fast, transparent, and affordable.

How to score B2B leads

  1. Go to the B2B Lead Qualifier on Apify
  2. Enter company domains (e.g., stripe.com, zapier.com)
  3. Click Start — get back scored, ranked leads with signal breakdowns
  4. Sort by score to focus on the highest-quality leads first

What does it analyze?

The Actor crawls each company website and checks for 30+ business quality signals across 5 categories:

CategoryMax PointsWhat It Measures
Contact Reachability30Can you actually reach someone? Email, phone, LinkedIn, decision-makers
Business Legitimacy25Is this a real, active business? Privacy policy, SSL, content depth
Online Presence20Marketing sophistication: blog, analytics, chat widget, testimonials
Website Quality15Technical professionalism: meta tags, structured data, mobile-ready
Team Transparency10Can you see who works there? Team page, named contacts, job titles

Grading scale

ScoreGradeMeaning
90-100AExcellent — highly reachable, established business
75-89BGood — solid web presence, likely reachable
60-74CAverage — some signals present, may need more research
40-59DBelow average — limited online presence
0-39FPoor — minimal signals, likely hard to reach

Output

Each domain produces one scored result. Here's a real result from analyzing apify.com:

{
"domain": "apify.com",
"url": "https://apify.com",
"score": 62,
"grade": "C",
"scoreBreakdown": {
"contactReachability": 10,
"businessLegitimacy": 22,
"onlinePresence": 15,
"websiteQuality": 12,
"teamTransparency": 3
},
"signals": [
{ "signal": "hasLinkedInCompany", "category": "contactReachability", "points": 4, "detail": "http://linkedin.com/company/apify/" },
{ "signal": "hasContactPage", "category": "contactReachability", "points": 3, "detail": "Contact page link found" },
{ "signal": "hasGenericEmail", "category": "contactReachability", "points": 3, "detail": "Found: hello@apify.com" },
{ "signal": "hasCopyrightCurrent", "category": "businessLegitimacy", "points": 3, "detail": "Copyright 2026" },
{ "signal": "hasPrivacyPolicy", "category": "businessLegitimacy", "points": 3, "detail": "Privacy policy link found" },
{ "signal": "hasMarketingTools", "category": "onlinePresence", "points": 3, "detail": "hubspot" },
{ "signal": "hasAnalytics", "category": "onlinePresence", "points": 2, "detail": "google-analytics, segment" }
],
"extractedData": {
"emails": ["hello@apify.com"],
"phones": [],
"contactNames": [],
"socialLinks": { "linkedin": "http://linkedin.com/company/apify/", "twitter": "https://x.com/apify" },
"address": null,
"cmsDetected": null,
"techSignals": ["google-analytics", "segment", "hubspot"]
},
"pagesScraped": 5,
"qualifiedAt": "2026-02-07T01:57:12.078Z"
}

Signals array shortened for brevity — the full output includes all 25 signals that fired.

Output fields

FieldTypeDescription
domainStringCompany domain analyzed
scoreIntegerLead quality score (0-100)
gradeStringLetter grade: A, B, C, D, F
scoreBreakdownObjectPoints per category (contactReachability, businessLegitimacy, onlinePresence, websiteQuality, teamTransparency)
signalsArrayEvery signal that contributed to the score, with signal name, category, points, and human-readable detail
extractedDataObjectAll extracted contact data: emails, phones, contact names, social links, address, CMS, tech stack
pagesScrapedIntegerNumber of pages crawled for this domain
qualifiedAtStringISO timestamp

Use cases

Prioritize outreach from a lead list

You have 500 company domains. Instead of contacting them all, run them through the qualifier to rank them by quality. Focus your outreach on grade A and B leads first — they have the best web presence and are most likely to respond.

Filter low-quality leads before enrichment

Running email enrichment on 1,000 domains is expensive. Pre-qualify them first: filter out grade D and F leads (set minScore to 60) and only enrich the promising ones.

Complete the lead generation pipeline

Google Maps Scraper Website Contact Scraper Email Pattern Finder B2B Lead Qualifier
┌──────────────────┐ ┌──────────────────────┐ ┌────────────────────┐ ┌───────────────────┐
"plumbers in LA" │ ────>500 website URLs │ ───> │ Detect email │ ──> │ Score & rank │
│ │ sites │ │ data │ patterns │ │ all 500 leads │
500 businesses │ │ emails, names, titles │ │ Generate addresses │ │ Focus on grade A │
└──────────────────┘ └──────────────────────┘ └────────────────────┘ └───────────────────┘

Want this entire pipeline in one click? Use B2B Lead Generation Suite — it chains all 3 actors automatically with a single input.

Input

FieldTypeDescriptionDefault
domainsArray of stringsCompany domains to score (required)
pipelineDataArray of objectsPre-scraped data from Website Contact Scraper / Email Pattern Finder (optional)[]
maxPagesPerDomainInteger (1-15)Max pages to crawl per website5
minScoreInteger (0-100)Only output leads at or above this score0
proxyConfigurationObjectProxy settings for website scrapingApify Proxy

Example input

{
"domains": ["stripe.com", "zapier.com", "basecamp.com"],
"maxPagesPerDomain": 5,
"minScore": 50
}

Pipeline integration input

Feed output from Website Contact Scraper directly as pipelineData to skip re-scraping contact info:

{
"domains": ["buffer.com"],
"pipelineData": [
{
"domain": "buffer.com",
"emails": ["hello@buffer.com"],
"contacts": [
{ "name": "Joel Gascoigne", "title": "Founder CEO" },
{ "name": "Jenny Terry", "title": "VP of Finance & Operations" }
],
"socialLinks": {
"linkedin": "https://www.linkedin.com/company/bufferapp",
"twitter": "https://x.com/buffer"
}
}
]
}

How to use the API

Python

from apify_client import ApifyClient
client = ApifyClient(token="YOUR_API_TOKEN")
run = client.actor("ryanclinton/b2b-lead-qualifier").call(
run_input={
"domains": ["stripe.com", "zapier.com", "basecamp.com"],
"minScore": 50,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{item['domain']}: {item['score']}/100 ({item['grade']})")
for signal in item["signals"]:
print(f" +{signal['points']} {signal['signal']}: {signal['detail']}")

JavaScript / Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('ryanclinton/b2b-lead-qualifier').call({
domains: ['stripe.com', 'zapier.com', 'basecamp.com'],
minScore: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
console.log(`${item.domain}: ${item.score}/100 (${item.grade})`);
item.signals.forEach(s => console.log(` +${s.points} ${s.signal}: ${s.detail}`));
});

Python — full pipeline example

from apify_client import ApifyClient
client = ApifyClient(token="YOUR_API_TOKEN")
# Step 1: Get businesses from Google Maps
maps_run = client.actor("compass/crawler-google-places").call(
run_input={"searchStringsArray": ["dentists in Austin TX"]}
)
websites = []
for biz in client.dataset(maps_run["defaultDatasetId"]).iterate_items():
if biz.get("website"):
websites.append(biz["website"])
# Step 2: Scrape contact info
scraper_run = client.actor("ryanclinton/website-contact-scraper").call(
run_input={"urls": websites, "maxPagesPerDomain": 5}
)
pipeline_data = []
domains = []
for item in client.dataset(scraper_run["defaultDatasetId"]).iterate_items():
domains.append(item["domain"])
pipeline_data.append(item)
# Step 3: Qualify and rank leads
qualifier_run = client.actor("ryanclinton/b2b-lead-qualifier").call(
run_input={
"domains": domains,
"pipelineData": pipeline_data,
"minScore": 50,
}
)
# Step 4: Get ranked results
for item in client.dataset(qualifier_run["defaultDatasetId"]).iterate_items():
print(f"{item['domain']}: {item['score']}/100 ({item['grade']}) - {len(item['signals'])} signals")

Signals reference

Contact Reachability (30 points max)

SignalPointsWhat triggers it
Personal email found8Non-generic email discovered (not info@, sales@, etc.)
Generic email found3At least a role-based email like info@ exists
Phone number5Phone number found via tel: link or in contact sections
Physical address4Street address detected in footer, contact page, or <address> tag
Contact page3Link to a contact/get-in-touch page found in navigation
LinkedIn company4LinkedIn company page linked from the website
Decision-maker3C-level, founder, or president found in team contacts

Business Legitimacy (25 points max)

SignalPointsWhat triggers it
Privacy policy3Link to a privacy policy page
Terms of service2Link to terms of service
Current copyright3Copyright year is recent (2024+)
About page3Link to an about/company page
Structured data3JSON-LD or microdata markup present
Multiple pages3Navigation has 3+ internal links
Content depth3Homepage has 200+ words
Favicon2Custom favicon set
SSL active3HTTPS connection successful

Online Presence (20 points max)

SignalPointsWhat triggers it
Social media1-51 point per platform linked (LinkedIn, Twitter, Facebook, Instagram, YouTube)
Blog/news3Link to blog, news, or press section
Testimonials3Customer testimonials, case studies, or "trusted by" section
Analytics2Google Analytics, Segment, Mixpanel, Hotjar, or Plausible detected
Marketing tools3HubSpot, Marketo, Pardot, Mailchimp, or Klaviyo detected
Chat widget2Intercom, Drift, Crisp, Tawk, Zendesk, or Freshdesk detected
Pricing page2Link to a pricing or plans page

Website Quality (15 points max)

SignalPointsWhat triggers it
Meta description2Meaningful meta description tag present
Open Graph2OpenGraph meta tags for social sharing
Mobile viewport2Responsive viewport meta tag configured
Proper title2Page title exists, is longer than 10 characters
H1 heading1H1 element present on the page
Schema.org Org3Organization or LocalBusiness structured data
Images1At least 3 images on the page
Navigation2Navigation element with 3+ links

Team Transparency (10 points max)

SignalPointsWhat triggers it
Team page3Link to team, people, or leadership page
Named contacts1-41 point per person found, up to 4
Job titles3At least one contact has a job title

Performance and cost

This Actor uses CheerioCrawler (HTTP only, no browser) for minimal cost:

DomainsEstimated timeEstimated platform cost
10~15 seconds< $0.01
100~3 minutes~$0.05
1,000~20 minutes~$1.00

Estimates based on 5 pages per domain with datacenter proxies.

FAQ

How is the score calculated?

The score is a simple sum of points from detected signals. Each signal has a fixed point value, grouped into 5 categories with maximum caps. The scoring is fully transparent — every signal that contributed is listed in the output with its point value and what triggered it.

Does this use AI or LLMs?

No. The scoring is entirely rule-based — it checks for specific HTML elements, meta tags, links, and script patterns. No AI API keys needed, which keeps costs predictable and results reproducible.

Why did my domain get a low score?

Common reasons: the website uses JavaScript rendering (this Actor uses HTTP requests, no browser — JS-rendered content won't be detected), the site has minimal public contact info, or it's a simple single-page website. Check the signals array to see exactly which signals fired and which didn't.

Can I customize the scoring weights?

Not currently — the weights are designed based on B2B outreach best practices. If you need custom scoring, export the signals array and apply your own weights in post-processing.

Does this verify emails or phone numbers?

No — it detects whether contact information is publicly visible on the website. For email verification, use a dedicated verification service after qualifying leads.

What's the difference between standalone and pipeline mode?

Standalone: Just provide domains — the Actor crawls each website and extracts everything from scratch. Pipeline: Provide pre-scraped data from Website Contact Scraper via pipelineData — the Actor uses that contact data instead of re-scraping, but still crawls for website quality and tech signals.

Responsible use

This Actor analyzes publicly visible website content. By using it, you agree to:

  • Comply with all applicable laws, including GDPR, CAN-SPAM, and CCPA
  • Respect each website's Terms of Service
  • Use the scores and extracted data only for legitimate business purposes
  • Not use this tool to facilitate spam or unsolicited bulk outreach

Limitations

  • JavaScript-rendered content — Uses HTTP requests only (CheerioCrawler). SPAs that render everything client-side will score lower because body content isn't visible.
  • No email verification — Detects emails on the page but doesn't verify deliverability.
  • English-centric — Name extraction and signal patterns work best with English-language websites.
  • Snapshot scoring — Scores reflect the website at the time of crawling. Websites change over time.

Pricing

  • $5 per 1,000 domains scored
  • First 100 domains free — try it risk-free
  • Only pay for successful results
DomainsPrice
100Free
1,000$5
5,000$25
10,000$50

Changelog

v1.0 (2026-02-07)

  • Initial release
  • 30+ business quality signals across 5 categories
  • Rule-based scoring (0-100) with letter grades
  • Pipeline integration with Website Contact Scraper and Email Pattern Finder
  • Tech stack detection: CMS, analytics, marketing, chat, e-commerce
  • Contact extraction: emails, phones, social links, physical addresses, team members