The Problem
After 10 years in building SaaS startups in sales intelligence, I kept seeing the same pattern:
B2B companies spending millions on sales and marketing tools, but losing hundreds of thousands to operational gaps nobody was measuring.
Lead response time? Nobody tracked it.
MQL rejection rate? "That's just how it is."
Pipeline velocity by stage? "We'd need a data analyst for that."
So I built a tool to automate the audit: Artemis GTM
π Try the Flash Audit
Here's how it works under the hood.
The Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (React) β
β - Multi-step audit form β
β - Real-time validation β
β - Dynamic question branching β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Analysis Engine β
β - Industry benchmark comparison β
β - Revenue impact calculations β
β - Leak identification & prioritization β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supabase Backend β
β - Audit data storage β
β - User session management β
β - Analytics & reporting β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The Data Model
Industry Benchmarks
The core of the audit is comparing user metrics against industry benchmarks. I built a structured benchmark database:
const INDUSTRY_BENCHMARKS = {
'SaaS': {
deal_size: 15000,
sales_cycle: 45,
win_rate: 25,
lead_to_opp: 15,
pipeline_coverage: 3.5,
lead_response_time: 5, // minutes
},
'FinTech': {
deal_size: 35000,
sales_cycle: 75,
win_rate: 20,
lead_to_opp: 12,
pipeline_coverage: 4.0,
lead_response_time: 5,
},
// ... more industries
};
Growth Motion Variations
B2B companies operate differently based on their growth motion. I account for three models:
type GrowthMotion = 'PLG' | 'SLG' | 'Hybrid';
const PLG_METRICS = {
trial_to_paid: 7, // %
activation_rate: 40, // %
expansion_revenue: 30, // %
};
const SLG_METRICS = {
meetings_per_sdr: 12,
demo_to_proposal: 50, // %
enterprise_deal_size: 50000,
};
The Analysis Engine
Revenue Leak Detection
Each audit answer feeds into a leak detection algorithm:
interface RevenueLeak {
issue: string;
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
revenue_impact: string;
evidence: string[];
recommendation: string;
}
function detectLeaks(auditData: AuditData, benchmarks: Benchmarks): RevenueLeak[] {
const leaks: RevenueLeak[] = [];
// Lead Response Time Analysis
if (auditData.lead_response_time > 60) { // minutes
const impactMultiplier = calculateResponseImpact(
auditData.lead_response_time,
benchmarks.lead_response_time
);
leaks.push({
issue: 'Lead Response Time Exceeds Benchmark',
severity: auditData.lead_response_time > 1440 ? 'CRITICAL' : 'HIGH',
revenue_impact: formatCurrency(
auditData.monthly_leads *
impactMultiplier *
auditData.deal_size *
auditData.conversion_rate *
12
),
evidence: [
`Current response time: ${auditData.lead_response_time} minutes`,
`Benchmark: ${benchmarks.lead_response_time} minutes`,
`Response rate degradation: ${(impactMultiplier * 100).toFixed(0)}%`
],
recommendation: 'Implement automated lead routing with <5 min SLA'
});
}
// ... more leak detection logic
return leaks;
}
Revenue Impact Calculation
The revenue impact formulas are based on published research and validated against real company data:
function calculateLeadResponseImpact(
actualMinutes: number,
monthlyLeads: number,
dealSize: number,
baselineConversion: number
): number {
// Based on Lead Response Management Study
// Conversion drops 80% after 30 minutes
// Additional 10% per hour after that
let conversionMultiplier = 1;
if (actualMinutes > 5) {
conversionMultiplier *= 0.79; // 21% drop after 5 min
}
if (actualMinutes > 30) {
conversionMultiplier *= 0.20; // 80% drop after 30 min
}
if (actualMinutes > 60) {
const additionalHours = Math.floor((actualMinutes - 60) / 60);
conversionMultiplier *= Math.pow(0.9, additionalHours);
}
const lostConversions = monthlyLeads * baselineConversion * (1 - conversionMultiplier);
const annualImpact = lostConversions * dealSize * 12;
return annualImpact;
}
Dynamic Question Branching
The audit adapts based on answers. PLG companies get different questions than enterprise SLG motions:
function getNextQuestion(
currentAnswer: Answer,
growthMotion: GrowthMotion,
companyStage: CompanyStage
): Question {
if (growthMotion === 'PLG') {
return PLG_QUESTIONS[currentQuestionIndex + 1];
}
if (growthMotion === 'SLG' && companyStage === 'Enterprise') {
return ENTERPRISE_SLG_QUESTIONS[currentQuestionIndex + 1];
}
// Default B2B flow
return STANDARD_QUESTIONS[currentQuestionIndex + 1];
}
The Frontend
Built with React + TypeScript + Tailwind. Key components:
Multi-Step Form
const AuditForm: React.FC = () => {
const [stage, setStage] = useState<'intro' | 'audit' | 'results'>('intro');
const [currentQuestion, setCurrentQuestion] = useState(0);
const [auditData, setAuditData] = useState({});
const handleAnswer = (answer: Answer) => {
setAuditData(prev => ({ ...prev, [currentQuestion]: answer }));
if (currentQuestion < questions.length - 1) {
setCurrentQuestion(prev => prev + 1);
} else {
runAnalysis();
}
};
// ...
};
Results Visualization
The results page shows:
- Overall health score (0-100)
- Revenue leaks ranked by impact
- Prioritized recommendations
- Implementation timelines
const HealthScore: React.FC<{ score: number }> = ({ score }) => {
const color = score >= 70 ? 'green' : score >= 40 ? 'amber' : 'red';
return (
{score}
GTM Health Score
);
};
Data Security
Since we're handling business metrics:
- All sensitive fields encrypted at rest (AES-GCM)
- Row-level security in Supabase
- No PII stored (email hashed for returning user lookup)
- GDPR-compliant data handling
async function encryptSensitiveData(data: string): Promise {
const encoder = new TextEncoder();
const keyData = encoder.encode(ENCRYPTION_KEY);
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'AES-GCM' },
false,
['encrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
cryptoKey,
encoder.encode(data)
);
// Combine IV + encrypted data for storage
return base64Encode(iv) + '.' + base64Encode(encrypted);
}
What I Learned
Benchmarks are tricky
Initial benchmarks came from industry reports, but real-world validation showed significant variance. I had to build in confidence intervals and segment by company size, not just industry.Users don't know their own metrics
Most users can't answer "What's your average lead response time?" from memory. I added the option to use industry benchmarks as defaults, with the ability to override.The analysis has to be actionable
Early versions showed the leaks but didn't prioritize them. Users were overwhelmed. Now everything is ranked by revenue impact Γ effort to fix.
Try It
Artemis GTM
Run the Flash Audit
2 minutes. Free. No credit card.
Find out where your GTM motion is leaking revenue.
What's Next
- API access for teams to run programmatic audits
- CRM integrations to pull real data automatically
- Benchmarking against anonymized peer data
If you're working on similar problems in RevOps tooling, I'd love to connect.
Built by Tom Regan β Revenue operations nerd, recovering consultant, and builder of tools that probably should have existed years ago.
Top comments (0)