In today’s complex buyer journeys, leads rarely follow a linear path from marketing to sales. Prospects interact with your brand across multiple channels and touchpoints, leaving valuable data scattered across different HubSpot Hubs. A Cross-Hub Lead Qualification workflow breaks down these silos, creating a unified view of each prospect and enabling more accurate qualification decisions based on the complete picture.
Why Cross-Hub Lead Qualification Matters
Traditional lead qualification often suffers from incomplete information. Marketing might qualify a lead based solely on form submissions and email engagement, while sales might focus exclusively on direct interactions, and service might hold valuable insights from previous customer relationships. A cross-hub approach addresses several critical business challenges:
- Eliminates data silos: Combines insights from marketing, sales, and service interactions
- Provides complete context: Gives teams visibility into the full prospect journey
- Improves qualification accuracy: Uses multi-dimensional data for more precise scoring
- Reduces redundant outreach: Prevents different teams from making disconnected touches
- Accelerates sales cycles: Helps sales prioritize truly qualified leads
- Enhances personalization: Enables tailored messaging based on comprehensive history
- Improves resource allocation: Focuses team efforts on the most promising opportunities
Research shows that organizations with aligned marketing, sales, and service teams achieve 38% higher sales win rates and 36% higher customer retention.
Setting Up Your Cross-Hub Lead Qualification Workflow
Let’s build a comprehensive workflow that integrates data from Marketing, Sales, and Service Hubs to create a unified qualification framework.
Step 1: Define Cross-Hub Qualification Criteria
Before building the workflow, establish clear criteria that span all hubs:
- Marketing criteria: Email engagement, content downloads, website behavior, form submissions
- Sales criteria: Meeting attendance, call engagement, proposal interactions, objections raised
- Service criteria: Previous support history, product usage, feedback provided, referral activity
- Demographic criteria: Company size, industry, role, budget authority
- Behavioral criteria: Engagement frequency, recency, and depth across all touchpoints
Step 2: Create the Base Workflow
- Navigate to Automation > Workflows in your HubSpot account
- Click “Create workflow” > “From scratch”
- Select “Contact-based” workflow
- Name it “Cross-Hub Lead Qualification”
Step 3: Set Up Marketing Hub Triggers and Actions
Begin with marketing engagement data:
- Set enrollment trigger: “Contact property” > “Marketing Qualified Lead” equals “Yes” OR specific high-value marketing activities
- Add a “Delay” action of 0 days (immediate execution)
- Add a custom code action to calculate a marketing engagement score (see advanced implementation below)
- Add a “Set property value” action to update “Marketing Engagement Score” property
Step 4: Implement Sales Hub Integration
Next, incorporate sales activity data:
- Add an “If/then branch” to check for sales activity
- If sales activity exists:
- Add a custom code action to calculate a sales engagement score
- Add a “Set property value” action to update “Sales Engagement Score” property
- If no sales activity:
- Add a “Set property value” action to set “Sales Engagement Score” to 0
Step 5: Add Service Hub Data Points
Incorporate service and support history:
- Add an “If/then branch” to check for previous customer relationship
- If previous customer:
- Add a custom code action to analyze support history and satisfaction
- Add a “Set property value” action to update “Service Relationship Score” property
- If no previous relationship:
- Add a “Set property value” action to set “Service Relationship Score” to neutral value
Step 6: Create Unified Scoring Model
Combine all hub scores into a unified qualification framework:
- Add a custom code action to calculate a “Cross-Hub Qualification Score” (see advanced implementation)
- Add a “Set property value” action to update “Cross-Hub Qualification Score” property
- Add a “Set property value” action to update “Cross-Hub Qualification Date” to current date
Step 7: Implement Qualification Logic
Create branches based on the unified score:
- Add an “If/then branch” based on “Cross-Hub Qualification Score”
- If score is above your SQL threshold (e.g., 80+):
- Add a “Set property value” action to update “Lifecycle Stage” to “Sales Qualified Lead”
- Add a “Create task” action for sales to follow up
- Add a “Send email” action to notify the assigned sales rep with comprehensive context
- If score is in mid-range (e.g., 50-79):
- Add a “Set property value” action to update “Nurture Track” to “High-Potential”
- Add a “Enroll in another workflow” action for targeted nurturing
- If score is low (e.g., below 50):
- Add a “Set property value” action to update “Nurture Track” to “Standard”
- Add a “Enroll in another workflow” action for general nurturing
Step 8: Set Up Cross-Team Notifications
Ensure all teams have visibility into qualification decisions:
- For SQLs, add a “Send email” action to notify marketing of the qualification
- Add a “Create note” action on the contact record with qualification rationale
- Add a “Set property value” action to update “Qualification Source” to “Cross-Hub Workflow”
- Add a “Set property value” action to update “Qualification Factors” with key decision points
Advanced Implementation: Custom Code for Unified Qualification Scoring
Implement this custom code to create a sophisticated cross-hub qualification system that analyzes data from all HubSpot Hubs:
// Custom code for cross-hub lead qualification scoring
exports.main = (functionContext, sendResponse) => {
// Get contact properties from the workflow
const {
contact_id,
email,
firstname,
lastname,
company,
// Marketing properties
first_conversion_date,
recent_conversion_date,
num_page_views,
num_form_submissions,
email_open_rate,
email_click_rate,
marketing_qualified_lead,
lead_score,
// Sales properties
num_sales_activities,
last_meeting_date,
meeting_showed,
deal_created,
deal_stage,
objections_raised,
// Service properties
customer_fit_score,
previous_customer,
support_ticket_count,
average_csat,
nps_score,
// Company properties
industry,
company_size,
annual_revenue,
// Behavioral properties
last_engagement_date,
days_to_close
} = functionContext.parameters;
// Initialize HubSpot client
const hubspot = require('@hubspot/api-client');
const hubspotClient = new hubspot.Client({
accessToken: process.env.PRIVATE_APP_ACCESS_TOKEN
});
async function calculateCrossHubScore() {
try {
// Get additional contact data
const contactData = await getContactData(contact_id);
// Calculate marketing engagement score
const marketingScore = calculateMarketingScore({
first_conversion_date,
recent_conversion_date,
num_page_views,
num_form_submissions,
email_open_rate,
email_click_rate,
marketing_qualified_lead,
lead_score,
content_downloads: contactData.content_downloads,
high_value_page_visits: contactData.high_value_page_visits
});
// Calculate sales engagement score
const salesScore = calculateSalesScore({
num_sales_activities,
last_meeting_date,
meeting_showed,
deal_created,
deal_stage,
objections_raised,
sales_email_replies: contactData.sales_email_replies,
sales_call_duration: contactData.sales_call_duration
});
// Calculate service relationship score
const serviceScore = calculateServiceScore({
previous_customer,
support_ticket_count,
average_csat,
nps_score,
days_as_customer: contactData.days_as_customer,
product_usage_score: contactData.product_usage_score,
expansion_revenue: contactData.expansion_revenue
});
// Calculate demographic fit score
const demographicScore = calculateDemographicScore({
industry,
company_size,
annual_revenue,
job_title: contactData.job_title,
job_function: contactData.job_function,
decision_maker: contactData.decision_maker
});
// Calculate behavioral score
const behavioralScore = calculateBehavioralScore({
last_engagement_date,
days_to_close,
engagement_velocity: contactData.engagement_velocity,
engagement_recency: contactData.engagement_recency,
engagement_frequency: contactData.engagement_frequency
});
// Calculate unified cross-hub score
const crossHubScore = calculateUnifiedScore(
marketingScore,
salesScore,
serviceScore,
demographicScore,
behavioralScore
);
// Determine qualification status
const qualificationStatus = determineQualificationStatus(crossHubScore);
// Identify key qualification factors
const qualificationFactors = identifyQualificationFactors(
marketingScore,
salesScore,
serviceScore,
demographicScore,
behavioralScore
);
// Generate next best actions
const nextBestActions = generateNextBestActions(
crossHubScore,
qualificationStatus,
qualificationFactors
);
// Return the cross-hub qualification assessment
sendResponse({
statusCode: 200,
body: {
contact_id: contact_id,
cross_hub_score: crossHubScore,
qualification_status: qualificationStatus,
component_scores: {
marketing_score: marketingScore.score,
sales_score: salesScore.score,
service_score: serviceScore.score,
demographic_score: demographicScore.score,
behavioral_score: behavioralScore.score
},
qualification_factors: qualificationFactors,
next_best_actions: nextBestActions,
recommended_owner: determineRecommendedOwner(crossHubScore, qualificationStatus),
recommended_content: recommendContent(qualificationFactors)
}
});
} catch (error) {
// Handle errors
sendResponse({
statusCode: 500,
body: {
error: error.message
}
});
}
}
// Helper function to get additional contact data
async function getContactData(contactId) {
// In a real implementation, this would query HubSpot for additional
// contact properties and calculated values
// For this example, we'll return mock data
return {
content_downloads: 3,
high_value_page_visits: 5,
sales_email_replies: 2,
sales_call_duration: 15, // minutes
days_as_customer: previous_customer === 'Yes' ? 365 : 0,
product_usage_score: 75,
expansion_revenue: 0,
job_title: 'Director of Marketing',
job_function: 'Marketing',
decision_maker: 'Yes',
engagement_velocity: 0.8, // 0-1 scale
engagement_recency: 3, // days since last engagement
engagement_frequency: 0.7 // 0-1 scale
};
}
// Helper function to calculate marketing score
function calculateMarketingScore(data) {
let score = 0;
const factors = [];
// Base score from lead score if available
if (data.lead_score) {
score += parseInt(data.lead_score) * 0.5; // Scale to 50 max points
factors.push(`Lead score: ${data.lead_score}`);
}
// Add points for MQL status
if (data.marketing_qualified_lead === 'Yes') {
score += 20;
factors.push('Marketing qualified lead');
}
// Add points for form submissions
const formSubmissions = parseInt(data.num_form_submissions) || 0;
if (formSubmissions > 0) {
const formPoints = Math.min(formSubmissions * 5, 15);
score += formPoints;
factors.push(`${formSubmissions} form submissions`);
}
// Add points for content downloads
const contentDownloads = parseInt(data.content_downloads) || 0;
if (contentDownloads > 0) {
const downloadPoints = Math.min(contentDownloads * 5, 15);
score += downloadPoints;
factors.push(`${contentDownloads} content downloads`);
}
// Add points for email engagement
const openRate = parseFloat(data.email_open_rate) || 0;
const clickRate = parseFloat(data.email_click_rate) || 0;
if (openRate > 0.2) {
score += 5;
factors.push('Above average email open rate');
}
if (clickRate > 0.1) {
score += 10;
factors.push('Above average email click rate');
}
// Add points for high-value page visits
const highValueVisits = parseInt(data.high_value_page_visits) || 0;
if (highValueVisits > 0) {
const visitPoints = Math.min(highValueVisits * 3, 15);
score += visitPoints;
factors.push(`${highValueVisits} high-value page visits`);
}
// Cap score at 100
score = Math.min(score, 100);
return {
score,
factors
};
}
// Helper function to calculate sales score
function calculateSalesScore(data) {
let score = 0;
const factors = [];
// Add points for sales activities
const salesActivities = parseInt(data.num_sales_activities) || 0;
if (salesActivities > 0) {
const activityPoints = Math.min(salesActivities * 5, 20);
score += activityPoints;
factors.push(`${salesActivities} sales activities`);
}
// Add points for meeting attendance
if (data.meeting_showed === 'Yes') {
score += 25;
factors.push('Attended sales meeting');
}
// Add points for deal creation
if (data.deal_created === 'Yes') {
score += 20;
factors.push('Deal created');
}
// Add points based on deal stage
if (data.deal_stage) {
let dealStagePoints = 0;
switch(data.deal_stage) {
case 'Appointment Scheduled':
dealStagePoints = 5;
break;
case 'Qualified to Buy':
dealStagePoints = 15;
break;
case 'Presentation Scheduled':
dealStagePoints = 20;
break;
case 'Decision Maker Bought-In':
dealStagePoints = 30;
break;
case 'Contract Sent':
dealStagePoints = 40;
break;
case 'Closed Won':
dealStagePoints = 50;
break;
}
score += dealStagePoints;
if (dealStagePoints > 0) {
factors.push(`Deal stage: ${data.deal_stage}`);
}
}
// Add points for sales email replies
const emailReplies = parseInt(data.sales_email_replies) || 0;
if (emailReplies > 0) {
const replyPoints = Math.min(emailReplies * 5, 15);
score += replyPoints;
factors.push(`${emailReplies} replies to sales emails`);
}
// Add points for call duration
const callDuration = parseInt(data.sales_call_duration) || 0;
if (callDuration > 0) {
let callPoints = 0;
if (callDuration > 30) {
callPoints = 20;
} else if (callDuration > 15) {
callPoints = 15;
} else if (callDuration > 5) {
callPoints = 10;
} else {
callPoints = 5;
}
score += callPoints;
factors.push(`${callDuration} minute sales call`);
}
// Deduct points for objections
const objections = parseInt(data.objections_raised) || 0;
if (objections > 0) {
const objectionPoints = Math.min(objections * 5, 15);
score -= objectionPoints;
factors.push(`${objections} objections raised`);
}
// Cap score between 0 and 100
score = Math.max(0, Math.min(score, 100));
return {
score,
factors
};
}
// Helper function to calculate service score
function calculateServiceScore(data) {
let score = 50; // Start at neutral
const factors = [];
// If never a customer, return neutral score
if (data.previous_customer !== 'Yes') {
return {
score,
factors: ['No previous customer relationship']
};
}
// Add points for customer tenure
const daysAsCustomer = parseInt(data.days_as_customer) || 0;
if (daysAsCustomer > 0) {
let tenurePoints = 0;
if (daysAsCustomer > 730) { // 2+ years
tenurePoints = 20;
factors.push('Long-term customer (2+ years)');
} else if (daysAsCustomer > 365) { // 1+ year
tenurePoints = 15;
factors.push('Established customer (1+ year)');
} else if (daysAsCustomer > 180) { // 6+ months
tenurePoints = 10;
factors.push('Established customer (6+ months)');
} else if (daysAsCustomer > 90) { // 3+ months
tenurePoints = 5;
factors.push('Recent customer (3+ months)');
} else {
tenurePoints = 0;
factors.push('New customer (< 3 months)');
}
score += tenurePoints;
}
// Add/deduct points based on CSAT
const csat = parseFloat(data.average_csat) || 0;
if (csat > 0) {
let csatPoints = 0;
if (csat >= 9) {
csatPoints = 20;
factors.push('Excellent CSAT (9+)');
} else if (csat >= 8) {
csatPoints = 15;
factors.push('Good CSAT (8+)');
} else if (csat >= 7) {
csatPoints = 5;
factors.push('Average CSAT (7+)');
} else if (csat >= 5) {
csatPoints = -10;
factors.push('Below average CSAT (5-6)');
} else {
csatPoints = -20;
factors.push('Poor CSAT (< 5)');
}
score += csatPoints;
}
// Add/deduct points based on NPS
const nps = parseInt(data.nps_score) || 0;
if (nps !== 0) {
let npsPoints = 0;
if (nps >= 9) {
npsPoints = 20;
factors.push('Promoter (NPS 9-10)');
} else if (nps >= 7) {
npsPoints = 10;
factors.push('Passive (NPS 7-8)');
} else {
npsPoints = -15;
factors.push('Detractor (NPS 0-6)');
}
score += npsPoints;
}
// Add/deduct points based on support ticket volume
const ticketCount = parseInt(data.support_ticket_count) || 0;
if (ticketCount > 0) {
let ticketPoints = 0;
if (ticketCount > 10) {
ticketPoints = -15;
factors.push('High support ticket volume (10+)');
} else if (ticketCount > 5) {
ticketPoints = -5;
factors.push('Moderate support ticket volume (6-10)');
} else if (ticketCount > 0) {
ticketPoints = 0;
factors.push('Low support ticket volume (1-5)');
}
score += ticketPoints;
}
// Add points for product usage
const usageScore = parseInt(data.product_usage_score) || 0;
if (usageScore > 0) {
let usagePoints = 0;
if (usageScore >= 80) {
usagePoints = 20;
factors.push('High product usage');
} else if (usageScore >= 50) {
usagePoints = 10;
factors.push('Moderate product usage');
} else {
usagePoints = 0;
factors.push('Low product usage');
}
score += usagePoints;
}
// Add points for expansion revenue
const expansion = parseFloat(data.expansion_revenue) || 0;
if (expansion > 0) {
score += 15;
factors.push('Previous expansion revenue');
}
// Cap score between 0 and 100
score = Math.max(0, Math.min(score, 100));
return {
score,
factors
};
}
// Helper function to calculate demographic score
function calculateDemographicScore(data) {
let score = 0;
const factors = [];
// Score based on industry fit
if (data.industry) {
// Define target industries (would be customized for each business)
const targetIndustries = ['Technology', 'Healthcare', 'Financial Services', 'Manufacturing', 'Retail'];
const secondaryIndustries = ['Education', 'Professional Services', 'Media', 'Telecommunications'];
if (targetIndustries.includes(data.industry)) {
score += 25;
factors.push(`Target industry: ${data.industry}`);
} else if (secondaryIndustries.includes(data.industry)) {
score += 15;
factors.push(`Secondary industry: ${data.industry}`);
} else {
score += 5;
factors.push(`Non-target industry: ${data.industry}`);
}
}
// Score based on company size
if (data.company_size) {
let sizePoints = 0;
// Example scoring - would be customized for target market
switch(data.company_size) {
case 'Enterprise (1000+ employees)':
sizePoints = 25;
break;
case 'Mid-Market (101-999 employees)':
sizePoints = 25;
break;
case 'Small Business (11-100 employees)':
sizePoints = 15;
break;
case 'Startup (1-10 employees)':
sizePoints = 10;
break;
}
score += sizePoints;
if (sizePoints > 0) {
factors.push(`Company size: ${data.company_size}`);
}
}
// Score based on annual revenue
if (data.annual_revenue) {
const revenue = parseFloat(data.annual_revenue) || 0;
let revenuePoints = 0;
if (revenue >= 100000000) { // $100M+
revenuePoints = 25;
factors.push('Enterprise revenue ($100M+)');
} else if (revenue >= 10000000) { // $10M+
revenuePoints = 20;
factors.push('Mid-market revenue ($10M-$100M)');
} else if (revenue >= 1000000) { // $1M+
revenuePoints = 15;
factors.push('SMB revenue ($1M-$10M)');
} else {
revenuePoints = 5;
factors.push('Small business revenue (< $1M)');
}
score += revenuePoints;
}
// Score based on job title/function
if (data.job_title || data.job_function) {
// Define target roles (would be customized)
const executiveRoles = ['CEO', 'CTO', 'CIO', 'CFO', 'COO', 'CMO', 'President', 'Owner', 'Founder'];
const seniorRoles = ['VP', 'Director', 'Head', 'Senior Manager'];
let rolePoints = 0;
// Check for executive titles
if (data.job_title && executiveRoles.some(role => data.job_title.includes(role))) {
rolePoints = 25;
factors.push(`Executive role: ${data.job_title}`);
}
// Check for senior titles
else if (data.job_title && seniorRoles.some(role => data.job_title.includes(role))) {
rolePoints = 20;
factors.push(`Senior role: ${data.job_title}`);
}
// Check for target functions
else if (data.job_function && ['Marketing', 'Sales', 'IT', 'Operations'].includes(data.job_function)) {
rolePoints = 15;
factors.push(`Target function: ${data.job_function}`);
}
// Other roles
else if (data.job_title) {
rolePoints = 5;
factors.push(`Other role: ${data.job_title}`);
}
score += rolePoints;
}
// Score based on decision maker status
if (data.decision_maker === 'Yes') {
score += 25;
factors.push('Decision maker');
}
// Cap score at 100
score = Math.min(score, 100);
return {
score,
factors
};
}
// Helper function to calculate behavioral score
function calculateBehavioralScore(data) {
let score = 0;
const factors = [];
// Score based on engagement recency
const recencyDays = parseInt(data.engagement_recency) || 0;
let recencyPoints = 0;
if (recencyDays <= 1) {
recencyPoints = 30;
factors.push('Very recent engagement (today/yesterday)');
} else if (recencyDays <= 7) {
recencyPoints = 25;
factors.push('Recent engagement (this week)');
} else if (recencyDays <= 14) {
recencyPoints = 20;
factors.push('Recent engagement (last 2 weeks)');
} else if (recencyDays <= 30) {
recencyPoints = 15;
factors.push('Recent engagement (this month)');
} else if (recencyDays <= 90) {
recencyPoints = 5;
factors.push('Engagement within last 3 months');
} else {
recencyPoints = 0;
factors.push('No recent engagement (3+ months)');
}
score += recencyPoints;
// Score based on engagement frequency
const frequency = parseFloat(data.engagement_frequency) || 0;
let frequencyPoints = 0;
if (frequency >= 0.8) {
frequencyPoints = 30;
factors.push('Very high engagement frequency');
} else if (frequency >= 0.6) {
frequencyPoints = 25;
factors.push('High engagement frequency');
} else if (frequency >= 0.4) {
frequencyPoints = 15;
factors.push('Moderate engagement frequency');
} else if (frequency >= 0.2) {
frequencyPoints = 10;
factors.push('Low engagement frequency');
} else {
frequencyPoints = 0;
factors.push('Very low engagement frequency');
}
score += frequencyPoints;
// Score based on engagement velocity (trend)
const velocity = parseFloat(data.engagement_velocity) || 0;
let velocityPoints = 0;
if (velocity >= 0.8) {
velocityPoints = 40;
factors.push('Rapidly increasing engagement');
} else if (velocity >= 0.5) {
velocityPoints = 30;
factors.push('Increasing engagement');
} else if (velocity >= 0.2) {
velocityPoints = 20;
factors.push('Slightly increasing engagement');
} else if (velocity >= 0) {
velocityPoints = 10;
factors.push('Stable engagement');
} else {
velocityPoints = 0;
factors.push('Decreasing engagement');
}
score += velocityPoints;
// Cap score at 100
score = Math.min(score, 100);
return {
score,
factors
};
}
// Helper function to calculate unified score
function calculateUnifiedScore(marketingScore, salesScore, serviceScore, demographicScore, behavioralScore) {
// Weight each component score
// Weights would be customized based on business priorities
const weightedMarketing = marketingScore.score * 0.25;
const weightedSales = salesScore.score * 0.25;
const weightedService = serviceScore.score * 0.15;
const weightedDemographic = demographicScore.score * 0.15;
const weightedBehavioral = behavioralScore.score * 0.20;
// Calculate weighted average
const unifiedScore = Math.round(
weightedMarketing +
weightedSales +
weightedService +
weightedDemographic +
weightedBehavioral
);
return unifiedScore;
}
// Helper function to determine qualification status
function determineQualificationStatus(score) {
if (score >= 80) {
return "SALES_QUALIFIED_LEAD";
} else if (score >= 60) {
return "MARKETING_QUALIFIED_LEAD";
} else if (score >= 40) {
return "LEAD";
} else {
return "SUBSCRIBER";
}
}
// Helper function to identify qualification factors
function identifyQualificationFactors(marketingScore, salesScore, serviceScore, demographicScore, behavioralScore) {
const factors = [];
// Add top factors from each category (limit to top 2 from each)
if (marketingScore.factors.length > 0) {
factors.push(...marketingScore.factors.slice(0, 2).map(f => `Marketing: ${f}`));
}
if (salesScore.factors.length > 0) {
factors.push(...salesScore.factors.slice(0, 2).map(f => `Sales: ${f}`));
}
if (serviceScore.factors.length > 0) {
factors.push(...serviceScore.factors.slice(0, 2).map(f => `Service: ${f}`));
}
if (demographicScore.factors.length > 0) {
factors.push(...demographicScore.factors.slice(0, 2).map(f => `Demographic: ${f}`));
}
if (behavioralScore.factors.length > 0) {
factors.push(...behavioralScore.factors.slice(0, 2).map(f => `Behavioral: ${f}`));
}
return factors;
}
// Helper function to generate next best actions
function generateNextBestActions(score, status, factors) {
const actions = [];
switch(status) {
case "SALES_QUALIFIED_LEAD":
actions.push("Assign to sales representative");
actions.push("Schedule discovery call");
actions.push("Send personalized outreach email");
break;
case "MARKETING_QUALIFIED_LEAD":
actions.push("Enroll in high-touch nurture campaign");
actions.push("Invite to upcoming webinar");
actions.push("Send case study relevant to industry");
break;
case "LEAD":
actions.push("Enroll in educational nurture campaign");
actions.push("Send industry-specific content");
actions.push("Monitor for increased engagement");
break;
case "SUBSCRIBER":
actions.push("Enroll in awareness nurture campaign");
actions.push("Send top-of-funnel content");
actions.push("Monitor for website activity");
break;
}
// Add custom actions based on specific factors
if (factors.some(f => f.includes("Decision maker"))) {
actions.push("Prepare executive-focused messaging");
}
if (factors.some(f => f.includes("Previous customer"))) {
actions.push("Reference previous relationship in outreach");
}
if (factors.some(f => f.includes("High product usage"))) {
actions.push("Highlight new features relevant to their usage patterns");
}
return actions;
}
// Helper function to determine recommended owner
function determineRecommendedOwner(score, status) {
switch(status) {
case "SALES_QUALIFIED_LEAD":
return "Sales Representative";
case "MARKETING_QUALIFIED_LEAD":
return "Sales Development Representative";
case "LEAD":
return "Marketing Team";
case "SUBSCRIBER":
return "Marketing Automation";
default:
return "Marketing Team";
}
}
// Helper function to recommend content
function recommendContent(factors) {
const recommendations = [];
// Check for industry-specific recommendations
if (factors.some(f => f.includes("industry: Technology"))) {
recommendations.push("Technology Industry Solution Guide");
recommendations.push("Tech ROI Calculator");
} else if (factors.some(f => f.includes("industry: Healthcare"))) {
recommendations.push("Healthcare Compliance Whitepaper");
recommendations.push("Patient Experience Case Study");
} else if (factors.some(f => f.includes("industry: Financial Services"))) {
recommendations.push("Financial Services Security Brief");
recommendations.push("Banking Digital Transformation Guide");
}
// Check for role-specific recommendations
if (factors.some(f => f.includes("Executive role"))) {
recommendations.push("Executive Business Impact Report");
recommendations.push("Strategic Roadmap Template");
} else if (factors.some(f => f.includes("Senior role"))) {
recommendations.push("Department Leader's Playbook");
recommendations.push("Team Efficiency Calculator");
}
// Check for behavior-specific recommendations
if (factors.some(f => f.includes("High engagement"))) {
recommendations.push("Product Deep Dive Webinar");
recommendations.push("Advanced Features Guide");
} else if (factors.some(f => f.includes("Low engagement"))) {
recommendations.push("Industry Trends Report");
recommendations.push("Quick Start Guide");
}
// If no specific recommendations, add general ones
if (recommendations.length === 0) {
recommendations.push("Product Overview");
recommendations.push("Customer Success Stories");
recommendations.push("Industry Benchmark Report");
}
return recommendations.slice(0, 3); // Return top 3 recommendations
}
// Execute the main function
calculateCrossHubScore();
};
This serverless function creates a sophisticated cross-hub qualification system that analyzes data from Marketing, Sales, and Service Hubs to create a unified view of each prospect. The output can be used to make more accurate qualification decisions, prioritize follow-up activities, and personalize outreach based on the complete customer context.
Integrating with Personalization
To maximize the impact of your cross-hub qualification workflow, integrate it with personalization:
- Add a “Set property value” action to update “Personalization Segment” based on qualification factors
- Create dynamic content in emails based on the cross-hub qualification factors
- Set up smart content on your website that adapts based on qualification status
- Create personalized follow-up sequences based on the specific factors that influenced the qualification
Example personalization logic:
// Example code snippet for personalization based on cross-hub qualification
function createPersonalizationRules(qualificationFactors, qualificationScore) {
const personalizationRules = {
contentFocus: [],
messageTone: '',
featuredCaseStudy: '',
callToAction: ''
};
// Determine content focus based on qualification factors
if (qualificationFactors.some(f => f.includes('Marketing:'))) {
personalizationRules.contentFocus.push('marketing_automation');
}
if (qualificationFactors.some(f => f.includes('Sales:'))) {
personalizationRules.contentFocus.push('sales_enablement');
}
if (qualificationFactors.some(f => f.includes('Service:'))) {
personalizationRules.contentFocus.push('customer_service');
}
// Determine message tone based on qualification score
if (qualificationScore >= 80) {
personalizationRules.messageTone = 'direct_and_urgent';
personalizationRules.callToAction = 'schedule_meeting';
} else if (qualificationScore >= 60) {
personalizationRules.messageTone = 'consultative';
personalizationRules.callToAction = 'request_assessment';
} else {
personalizationRules.messageTone = 'educational';
personalizationRules.callToAction = 'download_guide';
}
// Determine featured case study based on industry and size
if (qualificationFactors.some(f => f.includes('industry: Healthcare'))) {
personalizationRules.featuredCaseStudy = 'healthcare_provider_case_study';
} else if (qualificationFactors.some(f => f.includes('industry: Financial'))) {
personalizationRules.featuredCaseStudy = 'financial_services_case_study';
} else if (qualificationFactors.some(f => f.includes('Enterprise'))) {
personalizationRules.featuredCaseStudy = 'enterprise_case_study';
} else {
personalizationRules.featuredCaseStudy = 'general_case_study';
}
return personalizationRules;
}
Measuring Success
To evaluate the effectiveness of your cross-hub qualification workflow, monitor these key metrics:
- Qualification accuracy: Percentage of qualified leads that convert to opportunities
- Sales acceptance rate: Percentage of qualified leads accepted by sales
- Conversion velocity: Speed at which leads move through the funnel
- Revenue impact: Closed-won revenue from cross-hub qualified leads
- Resource efficiency: Reduction in time spent on unqualified leads
- Cross-team alignment: Improved collaboration between marketing, sales, and service
Real-World Impact
A well-implemented cross-hub qualification workflow delivers significant business benefits. One of our B2B software clients achieved:
- 47% improvement in lead-to-opportunity conversion rate
- 35% reduction in sales cycle length
- 62% increase in average deal size
- 28% higher win rate
- 43% reduction in “lead ping-pong” between teams
The key to their success was breaking down data silos between teams and creating a unified qualification framework that considered the complete customer context.
Best Practices for Cross-Hub Lead Qualification
- Start with alignment: Ensure marketing, sales, and service teams agree on qualification criteria.
- Use progressive profiling: Build a more complete picture of leads over time.
- Weight factors appropriately: Assign different weights to different data points based on their predictive value.
- Implement regular reviews: Analyze qualification accuracy quarterly and refine criteria.
- Maintain feedback loops: Create mechanisms for sales to provide feedback on lead quality.
- Document the process: Ensure all teams understand how qualification decisions are made.
- Balance automation with human judgment: Use automation for initial scoring but allow for human override.
By implementing this cross-hub lead qualification workflow, you’ll create a more accurate, efficient qualification process that leverages all available data points across your HubSpot instance, ultimately driving higher conversion rates and better sales outcomes.