
Cmo Advisor
- 248 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
cmo-advisor is a fractional CMO agent skill that guides B2B SaaS marketing strategy, demand generation, lead scoring, channel budgets, and funnel measurement using benchmarked frameworks and Python analyzers.
About
cmo-advisor is version 1.0.0 of borghei/Claude-Skills c-level-advisor plugin, acting as a fractional CMO for B2B SaaS marketing leadership. Its seven-step workflow gathers stage and ICP context, audits funnel conversion against benchmarks, drafts positioning statements, allocates budget across a seven-channel performance table, configures a lead scoring model with a 50-point MQL threshold, plans campaigns from a structured template, and sets daily-through-quarterly reporting cadence. Bundled Python scripts include marketing_roi_calculator.py, brand_health_tracker.py, channel_mix_optimizer.py, campaign_analyzer.py, lead_scoring.py, content_calendar.py, and attribution.py. Developers and growth engineers reach for cmo-advisor when building demand-gen plans, diagnosing rising blended CAC, or aligning marketing-sourced pipeline above 40% of total pipeline.
- Positioning and messaging strategy
- Channel mix prioritization
- Campaign and launch planning
- Lifecycle funnel optimization
- Brand and growth narrative
Cmo Advisor by the numbers
- 248 all-time installs (skills.sh)
- Ranked #269 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/borghei/claude-skills --skill cmo-advisorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 248 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
How do you plan B2B SaaS demand generation?
Receive CMO-level guidance on positioning, channel mix, campaign strategy, and lifecycle marketing while scaling acquisition and retention.
Who is it for?
Technical founders and growth engineers at B2B SaaS companies who need structured CMO-level marketing strategy with measurable funnel benchmarks.
Skip if: Hands-on creative production, social posting execution, or non-B2B consumer marketing without funnel or pipeline metrics.
When should I use this skill?
A developer or operator asks for marketing strategy, demand-gen planning, lead scoring design, channel budget allocation, or CAC and pipeline analysis.
What you get
Positioning statement, channel budget plan, 50-point MQL lead scoring model, campaign template, and ROI or attribution reports from bundled scripts.
- Positioning statement
- Channel budget allocation plan
- Campaign plan with success metrics
By the numbers
- Version 1.0.0 with 7-step marketing workflow
- MQL threshold set at 50 lead scoring points
- Bundles 7 Python analysis scripts
Files
CMO Advisor
The agent acts as a fractional CMO, providing strategic marketing guidance grounded in B2B SaaS benchmarks and proven frameworks.
Workflow
1. Gather context -- Identify company stage, ICP, current ARR, and marketing team size. Validate that at least stage and ICP are defined before proceeding. 2. Audit current performance -- Collect funnel metrics (visitors, MQLs, SQLs, pipeline, revenue). Flag any stage where conversion is below the benchmarks in the Channel Performance table. 3. Define positioning -- Draft a positioning statement using the template below. Confirm differentiation against the top two competitors. 4. Build channel plan -- Select channels from the Channel Performance Framework, allocate budget using the B2B SaaS Budget Allocation split, and set per-channel CAC targets. 5. Design lead scoring -- Configure the Lead Scoring Model and set the MQL threshold. Validate that the threshold produces a manageable volume for the sales team. 6. Create campaign plan -- Fill in the Campaign Planning Template for the first priority campaign. Include success metrics and required assets. 7. Establish measurement cadence -- Set daily, weekly, monthly, and quarterly review rhythms using the Reporting Cadence below.
Positioning Statement Template
For [target customer]
Who [statement of need or opportunity]
[Product name] is a [product category]
That [statement of key benefit]
Unlike [primary competitive alternative]
Our product [statement of primary differentiation]Marketing Budget Allocation (B2B SaaS Typical)
| Function | % of Budget |
|---|---|
| Demand Generation | 35-45% |
| Content & Brand | 15-20% |
| Marketing Ops & Tech | 15-20% |
| Events & Field | 10-15% |
| People & Overhead | 15-20% |
Channel Performance Framework
| Channel | CAC | Volume | Quality | Scalability |
|---|---|---|---|---|
| Organic Search | $ | High | Medium | Medium |
| Paid Search | $$ | Medium | High | High |
| Social Organic | $ | Medium | Low | Medium |
| Social Paid | $$ | High | Medium | High |
| Content | $ | High | High | Medium |
| Events | $$$ | Low | High | Low |
| Partnerships | $$ | Medium | High | Medium |
Lead Scoring Model
| Action | Points |
|---|---|
| Website visit | 1 |
| Content download | 5 |
| Email open | 1 |
| Email click | 3 |
| Webinar registration | 10 |
| Webinar attendance | 15 |
| Demo request | 25 |
| Pricing page visit | 10 |
MQL Threshold: 50 points
Lead Stages
Visitor > Known > Engaged > MQL > SAL > SQL > Opportunity > Customer
Campaign Planning Template
CAMPAIGN: [Name]
OBJECTIVE: [Specific goal]
AUDIENCE: [Target segment]
CHANNELS: [Distribution channels]
TIMELINE: [Start - End dates]
BUDGET: [Total investment]
KEY MESSAGES:
- Primary: [Main message]
- Secondary: [Supporting points]
SUCCESS METRICS:
- Leads: [Target]
- Pipeline: [Target]
- Cost per lead: [Target]
ASSETS REQUIRED:
- [ ] Landing page
- [ ] Email sequence
- [ ] Ad creative
- [ ] Content piecesMessaging Framework
| Audience | Pain Point | Solution | Proof Point |
|---|---|---|---|
| Buyer 1 | [Problem] | [How we help] | [Evidence] |
| Buyer 2 | [Problem] | [How we help] | [Evidence] |
| User 1 | [Problem] | [How we help] | [Evidence] |
Reporting Cadence
- Daily: Campaign performance (spend, clicks, conversions)
- Weekly: Pipeline and stage-over-stage conversion
- Monthly: Full funnel analysis, MQL-to-SQL conversion, CAC trend
- Quarterly: Channel ROI review, budget reallocation decisions
Multi-Touch Attribution Model
| Touch | Weight |
|---|---|
| First Touch | 30% |
| Lead Creation | 20% |
| Opportunity Creation | 30% |
| Closed Won | 20% |
Content Types by Funnel Stage
| Stage | Formats |
|---|---|
| Awareness | Blog posts, social content, podcasts, industry reports |
| Consideration | Ebooks/guides, webinars, case studies, comparison guides |
| Decision | Product demos, ROI calculators, testimonials, implementation guides |
Example: Series-B SaaS Demand-Gen Plan
A Series-B SaaS company ($8M ARR, 12-person marketing team) targeting mid-market DevOps buyers:
Budget: $2.4M annual ($200K/mo)
Allocation:
Demand Gen (40%): $960K -- Paid search ($300K), LinkedIn Ads ($250K),
Content syndication ($200K), Events ($210K)
Content & Brand (18%): $432K
Ops & Tech (17%): $408K
People (25%): $600K
Targets:
MQLs/month: 400 | SQL conversion: 25% | Pipeline/quarter: $6M
Blended CAC: $18K | CAC Payback: 14 monthsMarketing Org by Stage
| Stage | Roles |
|---|---|
| Series A (5-10) | Head of Marketing, Content/Brand, Demand Gen, Marketing Ops |
| Series B (10-20) | CMO, Director Brand, Director Demand Gen, Manager Content, Manager Ops, ICs |
| Series C+ (20+) | CMO, VP Brand, VP Demand Gen, VP Revenue Marketing, VP Marketing Ops, Specialized teams |
Scripts
# Campaign performance analyzer
python scripts/campaign_analyzer.py --campaign Q1-ABM
# Lead scoring calculator
python scripts/lead_scoring.py --leads leads.csv
# Content calendar generator
python scripts/content_calendar.py --pillars topics.yaml
# Attribution reporter
python scripts/attribution.py --period monthlyReferences
references/brand_guidelines.md-- Brand standards and usagereferences/demand_gen_playbook.md-- Campaign execution guidereferences/content_strategy.md-- Content planning frameworkreferences/martech_stack.md-- Technology recommendations
---
Tool Reference
marketing_roi_calculator.py
Calculates per-channel ROI, blended CAC, Marketing Efficiency Ratio (MER), pipeline contribution, and multi-touch attribution. Produces board-ready marketing performance reports.
# Run with demo data (6-channel mix)
python scripts/marketing_roi_calculator.py
# From JSON with channel data
python scripts/marketing_roi_calculator.py --input marketing_data.json
# JSON output
python scripts/marketing_roi_calculator.py --jsonbrand_health_tracker.py
Monitors brand health across 5 dimensions: awareness, perception, differentiation, engagement, and loyalty. Tracks competitive share of voice.
# Run with demo data
python scripts/brand_health_tracker.py
# From JSON with brand metrics
python scripts/brand_health_tracker.py --input brand_data.json
# JSON output
python scripts/brand_health_tracker.py --jsonchannel_mix_optimizer.py
Optimizes marketing budget allocation across channels based on ROI, efficiency frontiers, and diminishing returns. Projects impact of reallocation.
# Run with demo data (ROI optimization)
python scripts/channel_mix_optimizer.py
# Optimize for pipeline
python scripts/channel_mix_optimizer.py --goal pipeline
# Set total budget
python scripts/channel_mix_optimizer.py --budget 800000
# From JSON with channel performance
python scripts/channel_mix_optimizer.py --input channels.json
# JSON output
python scripts/channel_mix_optimizer.py --json---
Troubleshooting
| Problem | Likely Cause | Fix |
|---|---|---|
| Blended CAC increasing quarter over quarter | Channel saturation or scaling into less efficient channels | Run channel_mix_optimizer.py; cut lowest-ROI channels; increase investment in highest-ROI |
| Marketing sourced pipeline below 40% of total | Over-reliance on outbound/sales-sourced; marketing underinvesting in demand gen | Shift budget: target 40-60% marketing-sourced pipeline; invest in content + paid channels |
| Brand awareness below 30% in target market | Insufficient top-of-funnel investment; brand treated as afterthought | Allocate 15-20% of budget to brand; measure aided awareness quarterly |
| MQL-to-SQL conversion below 20% | Lead scoring threshold too low or ICP mismatch | Recalibrate MQL threshold; audit scoring model; tighten ICP definition |
| Marketing Efficiency Ratio (MER) below 1.0x | Spending more on marketing than generating in new ARR | Audit channel mix; pause negative-ROI channels; focus on proven converters |
| No brand tracking in place | Half of B2B SaaS companies don't track brand at all | Implement quarterly brand health survey using brand_health_tracker.py framework |
---
Success Criteria
- Marketing Efficiency Ratio (MER) above 1.5x -- every $1 of marketing generates $1.50+ in new ARR
- Blended CAC below target for company stage (Series A: $15K, Series B: $25K, Series C: $35K)
- Pipeline coverage at 3-4x of quarterly new ARR target (measured monthly)
- Marketing-sourced pipeline contribution above 40% of total pipeline
- CAC payback under 18 months (under 12 months for top-quartile performance)
- Brand health score improving quarter-over-quarter (tracked via brand_health_tracker.py)
- Channel mix optimization reviewed quarterly with budget reallocation acting on data
---
Scope & Limitations
In Scope: Marketing ROI calculation, channel performance analysis, brand health tracking, lead scoring, campaign planning, budget allocation optimization, multi-touch attribution, competitive share of voice.
Out of Scope: Content creation, creative design, social media posting, email campaign execution, event logistics, PR execution, website development.
Limitations: Marketing ROI calculator uses provided attribution data -- accuracy depends on attribution model quality. Brand health tracker relies on survey data which may have sampling bias. Channel mix optimizer uses historical performance with diminishing returns modeling -- future performance may differ due to market changes. MER calculation requires accurate new ARR attribution which many companies struggle to measure precisely.
---
Integration Points
| Skill | Integration |
|---|---|
cro-advisor | Pipeline contribution alignment; marketing-sourced vs sales-sourced targets |
cfo-advisor | Marketing budget as % of revenue; CAC payback for unit economics |
ceo-advisor | Brand positioning alignment with company vision |
cpo-advisor | Product marketing alignment; feature launch campaigns |
board-deck-builder | Growth/marketing section with CAC, pipeline, channel performance |
chief-of-staff | Routes market strategy and brand questions |
competitive-intel | Competitive positioning; share of voice vs competitors |
#!/usr/bin/env python3
"""
Brand Health Tracker - Monitor brand awareness, perception, and competitive position.
Tracks brand lift metrics, awareness levels, NPS trends, share of voice,
and competitive perception. Produces board-ready brand health reports.
"""
import argparse
import json
import sys
from datetime import datetime
def assess_brand(data: dict) -> dict:
"""Assess brand health across key dimensions."""
results = {
"timestamp": datetime.now().isoformat(),
"company": data.get("company", "Company"),
"overall_score": 0,
"dimensions": {},
"trends": [],
"competitive_position": {},
"recommendations": [],
"board_summary": {},
}
# Dimension scoring (each 0-100)
dimensions = {
"awareness": {
"aided_awareness_pct": data.get("aided_awareness_pct", 0),
"unaided_awareness_pct": data.get("unaided_awareness_pct", 0),
"search_volume_index": data.get("search_volume_index", 0),
"weight": 0.20,
},
"perception": {
"nps": data.get("nps", 0),
"brand_sentiment_pct": data.get("brand_sentiment_positive_pct", 0),
"consideration_pct": data.get("consideration_pct", 0),
"weight": 0.25,
},
"differentiation": {
"unique_positioning_score": data.get("unique_positioning_score", 0),
"category_association_pct": data.get("category_association_pct", 0),
"weight": 0.20,
},
"engagement": {
"share_of_voice_pct": data.get("share_of_voice_pct", 0),
"social_engagement_rate": data.get("social_engagement_rate", 0),
"content_amplification": data.get("content_amplification_rate", 0),
"weight": 0.15,
},
"loyalty": {
"nrr_pct": data.get("nrr_pct", 100),
"referral_rate_pct": data.get("referral_rate_pct", 0),
"repeat_purchase_pct": data.get("repeat_purchase_pct", 0),
"weight": 0.20,
},
}
total_score = 0
for dim_name, dim_data in dimensions.items():
weight = dim_data.pop("weight")
values = [v for v in dim_data.values() if isinstance(v, (int, float)) and v > 0]
# Normalize NPS (-100 to 100) to 0-100 scale
if dim_name == "perception" and "nps" in dim_data:
nps = dim_data["nps"]
dim_data["nps_normalized"] = (nps + 100) / 2
avg = sum(values) / len(values) if values else 0
# Cap at 100
avg = min(100, avg)
weighted = avg * weight
total_score += weighted
rating = "Strong" if avg >= 70 else "Adequate" if avg >= 45 else "Weak"
results["dimensions"][dim_name] = {
"score": round(avg, 1),
"weighted_score": round(weighted, 1),
"rating": rating,
"metrics": {k: v for k, v in dim_data.items() if isinstance(v, (int, float))},
}
results["overall_score"] = round(total_score, 1)
# Trends
historical = data.get("historical", [])
if historical:
for period in historical:
results["trends"].append({
"period": period.get("period", ""),
"awareness": period.get("aided_awareness_pct", 0),
"nps": period.get("nps", 0),
"sov": period.get("share_of_voice_pct", 0),
})
# Competitive position
competitors = data.get("competitors", [])
if competitors:
results["competitive_position"] = {
"company_sov": data.get("share_of_voice_pct", 0),
"competitors": [
{"name": c.get("name", ""), "sov": c.get("share_of_voice_pct", 0), "awareness": c.get("aided_awareness_pct", 0)}
for c in competitors
],
}
# Recommendations
for dim_name, dim_data in results["dimensions"].items():
if dim_data["rating"] == "Weak":
if dim_name == "awareness":
results["recommendations"].append("Increase brand awareness through top-of-funnel content, PR, and thought leadership campaigns.")
elif dim_name == "perception":
results["recommendations"].append("Improve brand perception: invest in customer success stories, address negative sentiment drivers.")
elif dim_name == "differentiation":
results["recommendations"].append("Sharpen positioning: conduct competitive messaging audit and update value proposition.")
elif dim_name == "engagement":
results["recommendations"].append("Boost engagement: increase content frequency, launch community programs, invest in social.")
elif dim_name == "loyalty":
results["recommendations"].append("Strengthen loyalty: launch referral program, improve onboarding, address churn drivers.")
if not results["recommendations"]:
results["recommendations"].append("Brand health is strong across all dimensions. Focus on maintaining and extending leadership position.")
# Board summary
results["board_summary"] = {
"brand_health_score": f"{results['overall_score']:.0f}/100",
"strongest_dimension": max(results["dimensions"].items(), key=lambda x: x[1]["score"])[0] if results["dimensions"] else "N/A",
"weakest_dimension": min(results["dimensions"].items(), key=lambda x: x[1]["score"])[0] if results["dimensions"] else "N/A",
"nps": data.get("nps", "N/A"),
"share_of_voice": f"{data.get('share_of_voice_pct', 0)}%",
}
return results
def format_text(results: dict) -> str:
"""Format as human-readable report."""
lines = [
"=" * 60,
"BRAND HEALTH REPORT",
"=" * 60,
f"Company: {results['company']} | Date: {results['timestamp'][:10]}",
f"Overall Brand Health: {results['overall_score']:.0f}/100",
"",
f"{'Dimension':<18} {'Score':>7} {'Weighted':>9} {'Rating':<10}",
"-" * 50,
]
for name, dim in results["dimensions"].items():
lines.append(f"{name.title():<18} {dim['score']:>6.0f}/100 {dim['weighted_score']:>8.1f} {dim['rating']:<10}")
for metric, val in dim["metrics"].items():
if metric != "nps_normalized":
unit = "%" if "pct" in metric else ""
lines.append(f" {metric.replace('_', ' ').title()}: {val}{unit}")
if results["competitive_position"].get("competitors"):
lines.extend(["", "COMPETITIVE SHARE OF VOICE:"])
lines.append(f" {results['company']}: {results['competitive_position']['company_sov']}%")
for c in results["competitive_position"]["competitors"]:
lines.append(f" {c['name']}: {c['sov']}%")
if results["recommendations"]:
lines.extend(["", "RECOMMENDATIONS:"])
for r in results["recommendations"]:
lines.append(f" -> {r}")
lines.extend(["", "=" * 60])
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Track and assess brand health metrics")
parser.add_argument("--input", "-i", help="JSON file with brand data")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.input:
with open(args.input) as f:
data = json.load(f)
else:
data = {
"company": "SaaSCo",
"aided_awareness_pct": 42,
"unaided_awareness_pct": 18,
"search_volume_index": 55,
"nps": 38,
"brand_sentiment_positive_pct": 72,
"consideration_pct": 35,
"unique_positioning_score": 60,
"category_association_pct": 28,
"share_of_voice_pct": 15,
"social_engagement_rate": 3.2,
"content_amplification_rate": 2.1,
"nrr_pct": 112,
"referral_rate_pct": 18,
"repeat_purchase_pct": 85,
"competitors": [
{"name": "Competitor A", "share_of_voice_pct": 28, "aided_awareness_pct": 65},
{"name": "Competitor B", "share_of_voice_pct": 22, "aided_awareness_pct": 55},
{"name": "Competitor C", "share_of_voice_pct": 18, "aided_awareness_pct": 40},
],
}
results = assess_brand(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Channel Mix Optimizer - Optimize marketing budget allocation across channels.
Analyzes historical channel performance and recommends budget reallocation
based on ROI, efficiency frontiers, and diminishing returns modeling.
"""
import argparse
import json
import sys
from datetime import datetime
import math
def optimize_mix(data: dict) -> dict:
"""Optimize channel budget allocation."""
channels = data.get("channels", [])
total_budget = data.get("total_budget", 0)
target_cac = data.get("target_cac", None)
optimization_goal = data.get("optimization_goal", "roi") # roi, pipeline, volume
results = {
"timestamp": datetime.now().isoformat(),
"total_budget": total_budget,
"optimization_goal": optimization_goal,
"current_allocation": [],
"recommended_allocation": [],
"reallocation_summary": [],
"projected_impact": {},
"constraints": [],
"recommendations": [],
}
# Analyze current performance
channel_metrics = []
for ch in channels:
name = ch.get("name", "")
spend = ch.get("current_spend", 0)
pipeline = ch.get("pipeline_generated", 0)
customers = ch.get("customers_won", 0)
revenue = ch.get("revenue_attributed", 0)
roi = ((revenue - spend) / spend) if spend > 0 else 0
cac = spend / customers if customers > 0 else float("inf")
pipeline_per_dollar = pipeline / spend if spend > 0 else 0
efficiency = revenue / spend if spend > 0 else 0
# Diminishing returns factor (higher spend = lower marginal return)
saturation = ch.get("saturation_pct", 50) / 100
marginal_efficiency = efficiency * (1 - saturation * 0.5)
channel_metrics.append({
"name": name,
"current_spend": spend,
"pct_of_budget": round(spend / total_budget * 100, 1) if total_budget > 0 else 0,
"roi": round(roi, 2),
"cac": round(cac) if cac != float("inf") else 0,
"pipeline_per_dollar": round(pipeline_per_dollar, 2),
"efficiency": round(efficiency, 2),
"marginal_efficiency": round(marginal_efficiency, 2),
"saturation_pct": ch.get("saturation_pct", 50),
"min_spend": ch.get("min_spend", 0),
"max_spend": ch.get("max_spend", spend * 3),
"customers_won": customers,
"pipeline_generated": pipeline,
"revenue_attributed": revenue,
})
results["current_allocation"] = channel_metrics
# Optimize based on goal
if optimization_goal == "roi":
sort_key = "marginal_efficiency"
elif optimization_goal == "pipeline":
sort_key = "pipeline_per_dollar"
else:
sort_key = "customers_won"
# Sort by efficiency metric
ranked = sorted(channel_metrics, key=lambda x: x[sort_key], reverse=True)
# Allocate budget using efficiency-weighted distribution
remaining_budget = total_budget
recommended = []
# First pass: ensure minimums
for ch in ranked:
min_spend = ch["min_spend"]
if min_spend > 0:
remaining_budget -= min_spend
# Second pass: allocate by efficiency
total_efficiency = sum(ch[sort_key] for ch in ranked if ch[sort_key] > 0)
for ch in ranked:
if total_efficiency > 0 and ch[sort_key] > 0:
share = ch[sort_key] / total_efficiency
allocated = ch["min_spend"] + remaining_budget * share
allocated = min(allocated, ch["max_spend"])
allocated = max(allocated, ch["min_spend"])
else:
allocated = ch["min_spend"]
change = allocated - ch["current_spend"]
change_pct = (change / ch["current_spend"] * 100) if ch["current_spend"] > 0 else 0
# Project new performance (linear approximation adjusted for saturation)
scale_factor = allocated / ch["current_spend"] if ch["current_spend"] > 0 else 1
# Apply diminishing returns
effective_scale = 1 + (scale_factor - 1) * (1 - ch["saturation_pct"] / 200)
proj_pipeline = ch["pipeline_generated"] * effective_scale
proj_customers = ch["customers_won"] * effective_scale
proj_revenue = ch["revenue_attributed"] * effective_scale
rec = {
"name": ch["name"],
"current_spend": ch["current_spend"],
"recommended_spend": round(allocated),
"change": round(change),
"change_pct": round(change_pct, 1),
"action": "Increase" if change > 0 else "Decrease" if change < 0 else "Maintain",
"projected_pipeline": round(proj_pipeline),
"projected_customers": round(proj_customers),
"projected_revenue": round(proj_revenue),
"projected_cac": round(allocated / proj_customers) if proj_customers > 0 else 0,
}
recommended.append(rec)
if abs(change_pct) > 10:
results["reallocation_summary"].append({
"channel": ch["name"],
"action": rec["action"],
"amount": abs(round(change)),
"reason": f"{'High' if change > 0 else 'Low'} marginal efficiency ({ch[sort_key]:.2f})",
})
results["recommended_allocation"] = recommended
# Projected impact
current_total_pipeline = sum(ch["pipeline_generated"] for ch in channel_metrics)
current_total_customers = sum(ch["customers_won"] for ch in channel_metrics)
current_total_revenue = sum(ch["revenue_attributed"] for ch in channel_metrics)
new_total_pipeline = sum(r["projected_pipeline"] for r in recommended)
new_total_customers = sum(r["projected_customers"] for r in recommended)
new_total_revenue = sum(r["projected_revenue"] for r in recommended)
results["projected_impact"] = {
"pipeline_change_pct": round((new_total_pipeline - current_total_pipeline) / current_total_pipeline * 100, 1) if current_total_pipeline > 0 else 0,
"customer_change_pct": round((new_total_customers - current_total_customers) / current_total_customers * 100, 1) if current_total_customers > 0 else 0,
"revenue_change_pct": round((new_total_revenue - current_total_revenue) / current_total_revenue * 100, 1) if current_total_revenue > 0 else 0,
"new_blended_cac": round(total_budget / new_total_customers) if new_total_customers > 0 else 0,
"current_blended_cac": round(total_budget / current_total_customers) if current_total_customers > 0 else 0,
}
# Recommendations
increases = [r for r in recommended if r["action"] == "Increase"]
decreases = [r for r in recommended if r["action"] == "Decrease"]
if increases:
results["recommendations"].append(
f"Increase spend on {len(increases)} channel(s): {', '.join(r['name'] for r in increases[:3])}"
)
if decreases:
results["recommendations"].append(
f"Reduce spend on {len(decreases)} channel(s): {', '.join(r['name'] for r in decreases[:3])}"
)
if target_cac and results["projected_impact"]["new_blended_cac"] > target_cac:
results["recommendations"].append(
f"Projected CAC ${results['projected_impact']['new_blended_cac']:,.0f} exceeds target ${target_cac:,.0f}. Further optimization needed."
)
return results
def format_text(results: dict) -> str:
"""Format as human-readable report."""
lines = [
"=" * 80,
"CHANNEL MIX OPTIMIZATION",
"=" * 80,
f"Budget: ${results['total_budget']:,.0f} | Goal: {results['optimization_goal'].upper()}",
"",
f"{'Channel':<16} {'Current':>10} {'Recommend':>10} {'Change':>10} {'Proj Pipeline':>14} {'Proj CAC':>9}",
"-" * 80,
]
for r in results["recommended_allocation"]:
sign = "+" if r["change"] > 0 else ""
lines.append(
f"{r['name']:<16} ${r['current_spend']:>9,.0f} ${r['recommended_spend']:>9,.0f} "
f"{sign}${r['change']:>8,.0f} ${r['projected_pipeline']:>13,.0f} ${r['projected_cac']:>8,.0f}"
)
pi = results["projected_impact"]
lines.extend([
"",
"PROJECTED IMPACT:",
f" Pipeline: {pi['pipeline_change_pct']:+.1f}% | Customers: {pi['customer_change_pct']:+.1f}% | Revenue: {pi['revenue_change_pct']:+.1f}%",
f" Blended CAC: ${pi['current_blended_cac']:,.0f} -> ${pi['new_blended_cac']:,.0f}",
])
if results["reallocation_summary"]:
lines.extend(["", "KEY MOVES:"])
for r in results["reallocation_summary"]:
lines.append(f" {r['action'].upper()}: {r['channel']} by ${r['amount']:,.0f} ({r['reason']})")
if results["recommendations"]:
lines.extend(["", "RECOMMENDATIONS:"])
for r in results["recommendations"]:
lines.append(f" -> {r}")
lines.extend(["", "=" * 80])
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Optimize marketing channel budget allocation")
parser.add_argument("--input", "-i", help="JSON file with channel performance data")
parser.add_argument("--budget", type=float, help="Total marketing budget")
parser.add_argument("--goal", choices=["roi", "pipeline", "volume"], default="roi", help="Optimization goal")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.input:
with open(args.input) as f:
data = json.load(f)
else:
data = {
"total_budget": 600000,
"optimization_goal": args.goal,
"target_cac": 18000,
"channels": [
{"name": "Paid Search", "current_spend": 150000, "pipeline_generated": 840000, "customers_won": 14, "revenue_attributed": 420000, "saturation_pct": 60, "min_spend": 50000, "max_spend": 250000},
{"name": "Content", "current_spend": 80000, "pipeline_generated": 660000, "customers_won": 11, "revenue_attributed": 330000, "saturation_pct": 30, "min_spend": 40000, "max_spend": 200000},
{"name": "LinkedIn Ads", "current_spend": 120000, "pipeline_generated": 480000, "customers_won": 8, "revenue_attributed": 240000, "saturation_pct": 45, "min_spend": 30000, "max_spend": 200000},
{"name": "Events", "current_spend": 100000, "pipeline_generated": 360000, "customers_won": 6, "revenue_attributed": 180000, "saturation_pct": 70, "min_spend": 20000, "max_spend": 150000},
{"name": "Outbound", "current_spend": 90000, "pipeline_generated": 300000, "customers_won": 5, "revenue_attributed": 100000, "saturation_pct": 40, "min_spend": 30000, "max_spend": 150000},
{"name": "Referral", "current_spend": 10000, "pipeline_generated": 480000, "customers_won": 8, "revenue_attributed": 320000, "saturation_pct": 20, "min_spend": 5000, "max_spend": 50000},
],
}
if args.budget:
data["total_budget"] = args.budget
results = optimize_mix(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Marketing ROI Calculator - Calculate ROI, CAC, and efficiency across channels.
Computes per-channel ROI, blended CAC, marketing efficiency ratio (MER),
pipeline contribution, and produces board-ready marketing performance reports.
"""
import argparse
import json
import sys
from datetime import datetime
CHANNEL_BENCHMARKS = {
"organic_search": {"cac_range": "Low", "quality": "Medium-High", "scalability": "Medium"},
"paid_search": {"cac_range": "Medium", "quality": "High", "scalability": "High"},
"social_organic": {"cac_range": "Low", "quality": "Low-Medium", "scalability": "Medium"},
"social_paid": {"cac_range": "Medium", "quality": "Medium", "scalability": "High"},
"content": {"cac_range": "Low", "quality": "High", "scalability": "Medium"},
"events": {"cac_range": "High", "quality": "High", "scalability": "Low"},
"partnerships": {"cac_range": "Medium", "quality": "High", "scalability": "Medium"},
"email": {"cac_range": "Low", "quality": "Medium", "scalability": "Medium"},
"outbound": {"cac_range": "High", "quality": "Medium-High", "scalability": "Medium"},
"referral": {"cac_range": "Low", "quality": "Very High", "scalability": "Low"},
}
def calculate_roi(data: dict) -> dict:
"""Calculate marketing ROI across all channels."""
channels = data.get("channels", [])
total_revenue = data.get("total_revenue", 0)
total_marketing_spend = data.get("total_marketing_spend", 0)
arr = data.get("arr", 0)
new_arr = data.get("new_arr_period", 0)
results = {
"timestamp": datetime.now().isoformat(),
"period": data.get("period", "Quarter"),
"channel_analysis": [],
"blended_metrics": {},
"efficiency_metrics": {},
"attribution": {},
"recommendations": [],
"board_summary": {},
}
total_spend = 0
total_pipeline = 0
total_customers = 0
total_mqls = 0
for ch in channels:
name = ch.get("name", "Unknown")
spend = ch.get("spend", 0)
leads = ch.get("leads", 0)
mqls = ch.get("mqls", 0)
sqls = ch.get("sqls", 0)
opportunities = ch.get("opportunities", 0)
customers = ch.get("customers_won", 0)
pipeline = ch.get("pipeline_generated", 0)
revenue = ch.get("revenue_attributed", 0)
# Per-channel metrics
cpl = spend / leads if leads > 0 else 0
cpmql = spend / mqls if mqls > 0 else 0
cpsql = spend / sqls if sqls > 0 else 0
cac = spend / customers if customers > 0 else 0
roi = ((revenue - spend) / spend * 100) if spend > 0 else 0
pipeline_roi = (pipeline / spend) if spend > 0 else 0
lead_to_mql = (mqls / leads * 100) if leads > 0 else 0
mql_to_sql = (sqls / mqls * 100) if mqls > 0 else 0
sql_to_close = (customers / sqls * 100) if sqls > 0 else 0
channel_result = {
"name": name,
"spend": spend,
"leads": leads,
"mqls": mqls,
"sqls": sqls,
"opportunities": opportunities,
"customers_won": customers,
"pipeline_generated": pipeline,
"revenue_attributed": revenue,
"cost_per_lead": round(cpl),
"cost_per_mql": round(cpmql),
"cost_per_sql": round(cpsql),
"cac": round(cac),
"roi_pct": round(roi, 1),
"pipeline_roi": round(pipeline_roi, 1),
"lead_to_mql_pct": round(lead_to_mql, 1),
"mql_to_sql_pct": round(mql_to_sql, 1),
"sql_to_close_pct": round(sql_to_close, 1),
"benchmark": CHANNEL_BENCHMARKS.get(name.lower().replace(" ", "_"), {}),
"efficiency_rating": "Efficient" if roi > 200 else "Good" if roi > 100 else "Break-even" if roi > 0 else "Losing",
}
results["channel_analysis"].append(channel_result)
total_spend += spend
total_pipeline += pipeline
total_customers += customers
total_mqls += mqls
# Sort by ROI
results["channel_analysis"].sort(key=lambda x: x["roi_pct"], reverse=True)
# Blended metrics
blended_cac = total_spend / total_customers if total_customers > 0 else 0
blended_cpmql = total_spend / total_mqls if total_mqls > 0 else 0
results["blended_metrics"] = {
"total_spend": round(total_spend),
"total_pipeline": round(total_pipeline),
"total_customers": total_customers,
"total_mqls": total_mqls,
"blended_cac": round(blended_cac),
"blended_cost_per_mql": round(blended_cpmql),
"pipeline_to_spend_ratio": round(total_pipeline / total_spend, 1) if total_spend > 0 else 0,
}
# Marketing Efficiency Ratio (MER) and other efficiency metrics
mer = new_arr / total_marketing_spend if total_marketing_spend > 0 else 0
marketing_pct_revenue = (total_marketing_spend / total_revenue * 100) if total_revenue > 0 else 0
pipeline_coverage = (total_pipeline / new_arr) if new_arr > 0 else 0
results["efficiency_metrics"] = {
"marketing_efficiency_ratio": round(mer, 2),
"mer_interpretation": "Strong" if mer > 2.0 else "Good" if mer > 1.0 else "Needs improvement" if mer > 0.5 else "Poor",
"marketing_pct_of_revenue": round(marketing_pct_revenue, 1),
"benchmark_pct_revenue": "8-12% (Series A), 15-25% (Growth)",
"pipeline_coverage": round(pipeline_coverage, 1),
"pipeline_coverage_target": "3-4x",
"cac_payback_note": f"Blended CAC ${blended_cac:,.0f} - divide by monthly gross profit per customer for payback months",
}
# Attribution summary
if results["channel_analysis"]:
top_roi = results["channel_analysis"][0]
top_pipeline = max(results["channel_analysis"], key=lambda x: x["pipeline_generated"])
top_volume = max(results["channel_analysis"], key=lambda x: x["mqls"])
results["attribution"] = {
"top_roi_channel": f"{top_roi['name']} ({top_roi['roi_pct']:.0f}% ROI)",
"top_pipeline_channel": f"{top_pipeline['name']} (${top_pipeline['pipeline_generated']:,.0f})",
"top_volume_channel": f"{top_volume['name']} ({top_volume['mqls']} MQLs)",
}
# Recommendations
losing = [c for c in results["channel_analysis"] if c["roi_pct"] < 0]
if losing:
results["recommendations"].append(
f"Cut or pause {len(losing)} losing channel(s): {', '.join(c['name'] for c in losing)}"
)
efficient = [c for c in results["channel_analysis"] if c["roi_pct"] > 200]
if efficient:
results["recommendations"].append(
f"Increase investment in {len(efficient)} high-ROI channel(s): {', '.join(c['name'] for c in efficient)}"
)
if marketing_pct_revenue > 25:
results["recommendations"].append(
f"Marketing spend at {marketing_pct_revenue:.0f}% of revenue - above typical benchmark. Review efficiency."
)
# Board summary
results["board_summary"] = {
"total_spend": f"${total_spend:,.0f}",
"pipeline_generated": f"${total_pipeline:,.0f}",
"blended_cac": f"${blended_cac:,.0f}",
"mer": f"{mer:.2f}x",
"top_channel": results["attribution"].get("top_roi_channel", "N/A"),
"channels_losing": len(losing),
}
return results
def format_text(results: dict) -> str:
"""Format as human-readable report."""
lines = [
"=" * 78,
"MARKETING ROI REPORT",
"=" * 78,
f"Period: {results['period']} | Date: {results['timestamp'][:10]}",
"",
f"{'Channel':<16} {'Spend':>10} {'MQLs':>6} {'Cust':>5} {'CAC':>8} {'Pipeline':>10} {'ROI':>7} {'Rating':<12}",
"-" * 78,
]
for ch in results["channel_analysis"]:
lines.append(
f"{ch['name']:<16} ${ch['spend']:>9,.0f} {ch['mqls']:>6} {ch['customers_won']:>5} "
f"${ch['cac']:>7,.0f} ${ch['pipeline_generated']:>9,.0f} {ch['roi_pct']:>+6.0f}% {ch['efficiency_rating']:<12}"
)
bm = results["blended_metrics"]
em = results["efficiency_metrics"]
lines.extend([
"",
"BLENDED METRICS:",
f" Total Spend: ${bm['total_spend']:,.0f} | Pipeline: ${bm['total_pipeline']:,.0f} | Customers: {bm['total_customers']}",
f" Blended CAC: ${bm['blended_cac']:,.0f} | Pipeline:Spend = {bm['pipeline_to_spend_ratio']:.1f}x",
"",
"EFFICIENCY:",
f" Marketing Efficiency Ratio (MER): {em['marketing_efficiency_ratio']:.2f}x ({em['mer_interpretation']})",
f" Marketing % of Revenue: {em['marketing_pct_of_revenue']:.1f}% (benchmark: {em['benchmark_pct_revenue']})",
f" Pipeline Coverage: {em['pipeline_coverage']:.1f}x (target: {em['pipeline_coverage_target']})",
])
if results["recommendations"]:
lines.extend(["", "RECOMMENDATIONS:"])
for r in results["recommendations"]:
lines.append(f" -> {r}")
lines.extend(["", "=" * 78])
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Calculate marketing ROI and efficiency metrics")
parser.add_argument("--input", "-i", help="JSON file with marketing data")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.input:
with open(args.input) as f:
data = json.load(f)
else:
data = {
"period": "Q4 2025",
"arr": 8000000,
"new_arr_period": 600000,
"total_revenue": 2000000,
"total_marketing_spend": 600000,
"channels": [
{"name": "Paid Search", "spend": 150000, "leads": 3000, "mqls": 450, "sqls": 112, "opportunities": 56, "customers_won": 14, "pipeline_generated": 840000, "revenue_attributed": 420000},
{"name": "Content", "spend": 80000, "leads": 5000, "mqls": 600, "sqls": 90, "opportunities": 45, "customers_won": 11, "pipeline_generated": 660000, "revenue_attributed": 330000},
{"name": "LinkedIn Ads", "spend": 120000, "leads": 2000, "mqls": 380, "sqls": 76, "opportunities": 38, "customers_won": 8, "pipeline_generated": 480000, "revenue_attributed": 240000},
{"name": "Events", "spend": 100000, "leads": 400, "mqls": 120, "sqls": 48, "opportunities": 24, "customers_won": 6, "pipeline_generated": 360000, "revenue_attributed": 180000},
{"name": "Outbound", "spend": 90000, "leads": 800, "mqls": 200, "sqls": 60, "opportunities": 30, "customers_won": 5, "pipeline_generated": 300000, "revenue_attributed": 100000},
{"name": "Referral", "spend": 10000, "leads": 100, "mqls": 60, "sqls": 30, "opportunities": 18, "customers_won": 8, "pipeline_generated": 480000, "revenue_attributed": 320000},
],
}
results = calculate_roi(data)
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text(results))
if __name__ == "__main__":
main()
Related skills
How it compares
Use cmo-advisor for strategic B2B SaaS funnel and budget planning; pair with cro-advisor when aligning marketing-sourced pipeline targets with sales conversion.
FAQ
What MQL threshold does cmo-advisor recommend?
cmo-advisor defines a lead scoring model where actions like demo request earn 25 points and webinar attendance earns 15 points, with an MQL threshold of 50 points before a lead is sales-ready.
Which scripts ship with cmo-advisor?
cmo-advisor bundles seven Python scripts: marketing_roi_calculator.py, brand_health_tracker.py, channel_mix_optimizer.py, campaign_analyzer.py, lead_scoring.py, content_calendar.py, and attribution.py for ROI, brand, and channel analysis.
What success metrics does cmo-advisor target?
cmo-advisor targets Marketing Efficiency Ratio above 1.5x, marketing-sourced pipeline above 40% of total, CAC payback under 18 months, and quarterly channel mix reviews with budget reallocation based on ROI data.