
Referral Program
- 80 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Referral Program is a Claude skill for designing referral and affiliate programs, covering the 4-stage referral loop, incentive design, trigger moments and viral-coefficient modeling.
About
Referral Program is a framework for designing referral and affiliate programs covering the 4-stage referral loop, incentive design, trigger-moment optimization, share mechanics, viral-coefficient modeling and an optimization playbook. A founder or growth owner uses it to launch a refer-a-friend or affiliate flow, or to fix a stalled program with a low K-factor. It includes a referral-vs-affiliate decision rule and high-signal trigger moments.
- 4-stage referral loop: trigger, share, referred-user conversion, reward
- Incentive design sized against CAC, margin and LTV
- Viral coefficient (K-factor) modeling and affiliate program architecture
Referral Program by the numbers
- 80 all-time installs (skills.sh)
- Ranked #472 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
referral-program capabilities & compatibility
- Capabilities
- pricing strategy · popup cro · lifecycle marketing
- Use cases
- marketing
- Pricing
- Free
What referral-program says it does
Referral and affiliate program design covering referral loop architecture, incentive design, trigger moment optimization, viral coefficient modeling,
If your customers are enthusiastic and social, start with customer referrals. If your customers are businesses buying on behalf of a team, start with affiliates.
[Trigger Moment] → [Share Action] → [Referred User Converts] → [Reward Delivered] → Loop
npx skills add https://github.com/borghei/claude-skills --skill referral-programAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 80 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Design a referral or affiliate program with the right incentives, trigger moments, share mechanics and viral-coefficient modeling.
Who is it for?
Designing or fixing a referral or affiliate program to drive word-of-mouth acquisition.
Skip if: Pricing tier design (use pricing-strategy) or on-site popup CRO.
When should I use this skill?
Designing a referral program, launching an affiliate program, or reviving a stalled viral loop.
What you get
A referral or affiliate program with the right incentives, trigger moments and a modeled viral coefficient.
- referral loop design
- incentive structure
- viral coefficient model
By the numbers
- 4-stage referral loop
- reward typically < 30% of first payment for customer referrals
Files
Referral Program
Production-grade referral and affiliate program framework covering the 4-stage referral loop, incentive design methodology, trigger moment optimization, share mechanics, viral coefficient modeling, affiliate program architecture, and systematic optimization playbook. Designed to build programs that compound, not collect dust.
Use when
- The user asks to "design a referral program", "launch an affiliate program", or "improve viral growth"
- The decision between customer referral vs affiliate program needs to be made
- An existing referral program has stalled (K-factor <1, low share rate, low referred-user conversion)
- Reward structure needs sizing against CAC, margin, or LTV
- Trigger moments need to be identified (when to ask, which in-product events, which lifecycle emails)
- The user says "word-of-mouth isn't working" or "we want to add a refer-a-friend flow"
---
Table of Contents
- Referral vs Affiliate Decision
- The 4-Stage Referral Loop
- Incentive Design
- Trigger Moment Architecture
- Share Mechanics
- Referred User Experience
- Viral Coefficient Modeling
- Affiliate Program Framework
- Optimization Playbook
- Metrics and Benchmarks
- Program Copy Templates
- Output Artifacts
- Related Skills
---
Referral vs Affiliate Decision
| Factor | Customer Referral | Affiliate Program |
|---|---|---|
| Who promotes | Your existing customers | External partners, bloggers, influencers |
| Motivation | Loyalty, reward, social currency | Commission, audience monetization |
| Best for | B2C, prosumer, SMB SaaS | B2B SaaS, high LTV, content-heavy niches |
| Activation | Triggered by product satisfaction | Recruited and onboarded proactively |
| Payout | Account credit, discount, or cash reward | Revenue share or flat fee per conversion |
| CAC impact | Low -- reward is typically < 30% of first payment | Variable -- commission determines economics |
| Scale | Scales with active user base | Scales with partner recruitment |
Decision rule: If your customers are enthusiastic and social, start with customer referrals. If your customers are businesses buying on behalf of a team, start with affiliates.
---
The 4-Stage Referral Loop
Every referral program runs on this loop. If any stage is weak, the entire program underperforms. Work the stages in order — a broken Stage 1 (trigger) can't be fixed by better rewards at Stage 4.
[Trigger Moment] → [Share Action] → [Referred User Converts] → [Reward Delivered] → Loop- Validate Stage 1: trigger fires on a real satisfaction event, not at signup or in a generic monthly email
- Validate Stage 2: share friction is <3 taps/clicks and pre-filled copy is channel-specific
- Validate Stage 3: referred user lands on a referral-specific page, not the generic homepage
- Validate Stage 4: reward delivery is automatic and notified (manual reward ops kill the loop)
Stage 1: Trigger Moment
When you ask customers to refer. Timing is everything.
High-signal trigger moments:
| Trigger | Why It Works | When to Fire |
|---|---|---|
| After aha moment | User just experienced core value, highest satisfaction | After activation event |
| After milestone | Celebrates achievement, creates social sharing impulse | "You just saved your 100th hour" |
| After great support | Gratitude creates sharing impulse | Post-resolution, NPS 9-10 |
| After renewal/upgrade | Commitment signal, satisfied customer | Day of renewal |
| After public win | Customer tweets about you or posts a case study | Within 24 hours |
| After team growth | New team members = new potential referrers | After Nth team member joins |
What does NOT work:
- Asking at signup (no value experienced yet)
- Asking in every email footer (becomes invisible)
- Asking during onboarding (too early, too distracted)
- Generic monthly "refer a friend" email (no trigger, no urgency)
Stage 2: Share Action
Remove every point of friction between wanting to share and actually sharing.
Required share mechanics:
- Personal referral link (unique per user, trackable)
- Pre-filled share message (editable, not locked)
- Multiple share channels: email invite, link copy, social share
- For B2B: Slack/Teams share option
- One-click send on mobile (native share sheet)
Share message rules:
- Written in first person (sounds like it is from a friend, not marketing)
- Includes the specific benefit the referrer experienced
- Short (2-3 sentences max)
- Includes the referral link with clear CTA
Stage 3: Referred User Converts
The referred user lands on your product. Their experience must:
- Show personalization: "Your friend [Name] invited you"
- Display the incentive clearly above the fold
- Reduce signup friction (pre-fill email if available, offer SSO)
- Track attribution from landing through conversion (multi-session)
Stage 4: Reward Delivered
The reward must be fast and clear. Delayed rewards break the loop.
| Action | Implementation |
|---|---|
| Immediate confirmation | "Your friend just signed up! Here's your reward" |
| In-product visibility | Dashboard: "2 friends joined -- you've earned $40" |
| Email notification | Instant notification when referral converts |
| Easy redemption | Auto-applied credit or one-click claim |
---
Incentive Design
Single-Sided vs Double-Sided
| Type | When to Use | Cost | Conversion Impact |
|---|---|---|---|
| Single-sided (referrer only) | Strong viral hooks, enthusiastic users | Lower | Moderate |
| Double-sided (both get rewarded) | Need to overcome inertia on both sides | Higher | Higher |
Decision rule: If referral rate < 1%, go double-sided. If > 5%, single-sided is more profitable.
Reward Types
| Type | Best For | Examples | Sizing Guideline |
|---|---|---|---|
| Account credit | SaaS, subscription | "$20 credit toward your bill" | 10-20% of monthly plan |
| Discount | E-commerce, usage-based | "1 month free" | 1 month or 15-25% of annual |
| Cash | High LTV, B2C | "$50 for each referral" | < 30% of first payment |
| Feature unlock | Freemium products | "Unlock advanced analytics" | Feature value > cost |
| Status/recognition | Community products | "Ambassador badge" | Zero cost, high perceived value |
| Charity donation | Enterprise, mission-driven | "$25 to a cause you choose" | Similar to cash amount |
Tiered Rewards (Gamification)
For referrers who go beyond 1 referral:
| Tier | Reward | Design Rule |
|---|---|---|
| 1 referral | $20 credit | Easy to reach, immediate gratification |
| 3 referrals | $75 credit + bonus feature | Meaningful step-up, not just 3x |
| 10 referrals | $300 cash + ambassador status | Significant reward, social recognition |
Rules:
- Maximum 3 tiers (more is confusing)
- Each tier should feel meaningfully better, not just marginally
- Show progress toward next tier in the dashboard
Reward Economics
Maximum reward per referral = LTV x Target referral CAC ratio
Example:
Average LTV: $2,000
Target referral CAC: 15% of LTV
Maximum reward: $300
If double-sided:
Referrer reward: $150
Referred reward: $150 (or equivalent credit/discount)---
Trigger Moment Architecture
In-Product Trigger Points
| Location | Trigger Type | Copy Example |
|---|---|---|
| Dashboard widget | Persistent, low-key | "Know someone who'd love [Product]? Give $20, get $20" |
| Post-milestone modal | Celebration moment | "You just hit 1,000 contacts! Share [Product] with a colleague?" |
| Settings/account page | Always available | "Referral Program: Earn $20 for every friend who joins" |
| Success state | After positive outcome | "Great results! Know someone who'd find this useful?" |
| Team invite flow | Natural sharing moment | "Or invite them via referral link and you both get $20" |
Email Trigger Points
| Trigger | Email Content | Timing |
|---|---|---|
| Post-activation (first value delivered) | "Loving [Product]? Share it and earn rewards" | 3-5 days after activation |
| Post-NPS (score 9-10) | "Glad you love us! Here's an easy way to share" | Immediately after NPS |
| Post-renewal | "Thanks for staying with us! Share the love" | Day of renewal |
| Monthly digest | "Your referral status: [N] referrals, $[X] earned" | Monthly |
---
Share Mechanics
Share Channel Priority
| Channel | B2C Priority | B2B Priority | Implementation |
|---|---|---|---|
| Email invite | High | Highest | Pre-filled email with referral link |
| Copy link | High | High | One-click copy with confirmation |
| Twitter/X | High | Medium | Pre-filled tweet with referral link |
| Low | High | Pre-filled post with referral link | |
| High | Low | Deep link to WhatsApp with message | |
| Slack/Teams | Low | High | Integration or copyable message |
| SMS | Medium (mobile) | Low | Pre-filled text message |
Share Message Templates
Email (B2B):
Subject: I think you'd like [Product]
Hey [Name],
I've been using [Product] for [task/workflow] and it's saved me [specific benefit].
Thought you might find it useful too.
Here's my referral link -- you'll get [referred benefit] when you sign up:
[Referral Link]
[Referrer Name]Social (B2C):
Been using [Product] for [timeframe] and I'm genuinely impressed.
[Specific thing I love about it].
If you want to try it, use my link and we both get [reward]:
[Referral Link]---
Referred User Experience
Referral Landing Page
┌──────────────────────────────────────────┐
│ [Referrer Name] invited you to │
│ [Product] │
│ │
│ [Referrer's photo if available] │
│ │
│ Your reward: [Incentive details] │
│ │
│ [Sign Up and Claim Your Reward] │
│ │
│ What [Product] does: │
│ - Benefit 1 │
│ - Benefit 2 │
│ - Benefit 3 │
│ │
│ "Quote from a customer" │
└──────────────────────────────────────────┘Attribution Rules
| Scenario | Attribution |
|---|---|
| User clicks link and signs up same session | Attributed to referrer |
| User clicks link, returns 3 days later, signs up | Attributed (30-day cookie) |
| User clicks link but signs up via Google search | Attributed if within cookie window |
| User receives two referral links from different people | First click wins (or last click -- choose one rule) |
| Referred user was already a lead in CRM | Exclude from referral program |
---
Viral Coefficient Modeling
K-Factor Calculation
K = i x c
i = average invitations sent per user
c = conversion rate of invitations
Example:
Average user sends 3 invitations
15% of those invitations convert
K = 3 x 0.15 = 0.45
K > 1.0 = viral growth (rare outside social products)
K = 0.3-0.7 = strong referral contribution
K < 0.1 = referral program needs workImproving K-Factor
| Lever | Current | Target | Action |
|---|---|---|---|
| Increase i (invitations sent) | Low awareness | More users see the program | Improve trigger moments and visibility |
| Increase i (invitations sent) | Users see it but do not share | Make sharing easier | Improve share mechanics, better messaging |
| Increase c (conversion rate) | Users share but invites do not convert | Improve referred landing page | Personalize, add incentive, reduce friction |
---
Affiliate Program Framework
Program Structure
| Element | Recommendation |
|---|---|
| Commission model | 20-30% recurring for SaaS, or flat fee per conversion |
| Cookie window | 30 days minimum, 90 days for B2B |
| Payment terms | Monthly, $50 minimum threshold |
| Payment method | PayPal, wire transfer, or affiliate platform payout |
| Tracking platform | PartnerStack, Impact, Rewardful, or custom |
Affiliate Tier System
| Tier | Criteria | Commission | Benefits |
|---|---|---|---|
| Standard | Default | 20% recurring | Basic assets, self-serve |
| Silver | 10+ conversions | 25% recurring | Priority support, custom assets |
| Gold | 25+ conversions | 30% recurring | Dedicated manager, co-marketing |
| Strategic | Custom agreement | Custom | Custom terms, revenue share |
Affiliate Toolkit
Every affiliate needs:
- [ ] Unique tracking link
- [ ] Pre-written email copy (3 variants)
- [ ] Social media copy (Twitter, LinkedIn)
- [ ] Banner ads (3 sizes minimum)
- [ ] Product description sheet (features, benefits, pricing)
- [ ] Comparison table (vs competitors)
- [ ] Landing page optimized for affiliate traffic
Affiliate Recruitment
| Source | Approach | Volume |
|---|---|---|
| Existing customers (top advocates) | Personal outreach | 10-20 initial |
| Complementary SaaS companies | Partnership pitch | 5-10 |
| Industry bloggers/creators | Outreach with product demo | 10-20 |
| Newsletter curators | Sponsorship conversion to affiliate | 5-10 |
| Review sites | Listing with affiliate link | Ongoing |
Recruitment rule: Personalized outreach only. Generic "join our affiliate program" emails convert at < 1%.
---
Optimization Playbook
Diagnose Before Optimizing
| Metric | Benchmark | If Below | Fix |
|---|---|---|---|
| Program awareness | > 40% of active users know it exists | Promote in-app, post-activation emails, dashboard widget | |
| Active referrers | 5-15% of active users | Improve trigger moments, timing, and incentive | |
| Share rate | 20-40% of those who see the prompt | Simplify share flow, improve message copy | |
| Referred conversion rate | 15-25% | Improve referral landing page, add incentive | |
| Reward redemption | > 70% within 30 days | Reduce redemption friction, send reminders |
Optimization Priority
1. Fix awareness first -- If users do not know the program exists, nothing else matters 2. Fix the share flow -- If users know but do not share, the friction is too high 3. Fix the referred experience -- If users share but referrals do not convert, the landing page fails 4. Optimize the incentive -- Only change the reward after the mechanics work
---
Metrics and Benchmarks
Key Metrics
| Metric | Formula | Target |
|---|---|---|
| Referral rate | Referrals sent / Active users | 5-15% |
| Active referrers % | Users who sent 1+ referral / Active users | 5-15% |
| Referral conversion rate | Referred signups / Referrals sent | 15-25% |
| Referral CAC | Total reward cost / Referral-acquired customers | < 50% of other CAC |
| Referral revenue % | Revenue from referred customers / Total revenue | 10-25% |
| K-factor | Invitations per user x Conversion rate | 0.3-0.7 |
| Referred customer LTV | LTV of referred vs non-referred | Referred should be higher |
Revenue Impact Model
Monthly referral revenue = Active users x Referral rate x Conversion rate x ACV / 12
Example:
10,000 active users x 10% referral rate x 20% conversion rate x $600 ACV / 12
= $10,000/month in new referral-driven MRR
Annual impact: $120,000 in new ARR
Reward cost (at $50/referral): 200 referrals x $50 = $10,000
ROI: 12x return on reward investment---
Program Copy Templates
In-App Prompt
Know someone who'd love [Product]?
Give [reward], Get [reward]
Share your unique link and you'll both get [reward] when they sign up.
[Share Now] [Learn More]Referral Dashboard
Your Referral Stats
Referrals Sent: [N]
Friends Joined: [N]
Rewards Earned: $[X]
[Share Your Link]
Your link: [referral-url] [Copy]
Progress to next reward:
[Progress bar: 2 of 3 referrals for Silver tier]Referral Email (Post-Activation)
Subject: Share [Product] and earn [reward]
Hi [Name],
Glad you're enjoying [Product]!
Share your personal referral link with colleagues, and you'll both get [reward]:
[Referral Link]
So far, you've earned $[X] from [N] referrals.
[Share Now]---
Output Artifacts
| Artifact | Format | Description |
|---|---|---|
| Referral Program Design | Full spec | Loop design, incentive structure, trigger moments, share mechanics |
| Incentive ROI Model | Revenue calculation | Reward sizing against LTV/CAC with multiple scenarios |
| Program Copy Set | Complete copy | In-app prompts, emails, share messages, landing page |
| Affiliate Program Spec | Structure + toolkit | Commission model, tiers, recruitment list, partner assets |
| K-Factor Model | Calculation + improvement plan | Current K, target K, lever-by-lever improvement plan |
| Optimization Audit | Metric scorecard | Current metrics vs benchmarks with prioritized fixes |
| Dashboard Specification | UI design | Referral stats, link sharing, progress tracking |
---
Tool Reference
1. referral_economics_calculator.py
Calculates referral program economics including reward sizing, K-factor, referral CAC, ROI projections, and break-even analysis. Models double-sided vs single-sided reward structures.
python scripts/referral_economics_calculator.py program.json --format text
python scripts/referral_economics_calculator.py program.json --format json| Flag | Type | Description |
|---|---|---|
program.json | positional | Path to JSON file with program economics data |
--format | optional | Output format: text (default) or json |
2. referral_funnel_analyzer.py
Analyzes the 4-stage referral loop (trigger, share, convert, reward) with stage-over-stage conversion, identifies the weakest stage, and provides prioritized improvement recommendations.
python scripts/referral_funnel_analyzer.py funnel.json --format text
python scripts/referral_funnel_analyzer.py funnel.json --format json| Flag | Type | Description |
|---|---|---|
funnel.json | positional | Path to JSON file with referral funnel metrics |
--format | optional | Output format: text (default) or json |
3. affiliate_commission_modeler.py
Models affiliate program commission structures across tier levels. Calculates per-tier economics, lifetime partner value, and compares commission models (flat fee vs recurring percentage).
python scripts/affiliate_commission_modeler.py affiliate.json --format text
python scripts/affiliate_commission_modeler.py affiliate.json --format json| Flag | Type | Description |
|---|---|---|
affiliate.json | positional | Path to JSON file with affiliate program data |
--format | optional | Output format: text (default) or json |
---
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| Program awareness below 40% of active users | Referral program is buried in settings or only mentioned in email footers | Add persistent dashboard widget, post-activation prompt, and post-NPS trigger; desktop sharing now outperforms mobile (2026 data) |
| Users see prompt but share rate is below 20% | Share flow has too much friction or pre-filled message is not compelling | Add one-click copy link, native share sheet on mobile, pre-filled first-person message; ensure multiple channels (email, Slack, social) |
| Referrals sent but conversion rate below 15% | Referral landing page lacks personalization or incentive is not prominent | Add referrer name/photo, display incentive above fold, reduce signup friction; mobile-referred users convert 2-3x (2026 data) |
| K-factor below 0.1 | Fundamental program design issue -- either low awareness, high friction, or weak incentive | Diagnose in sequence: fix awareness first, then share flow, then landing page, then incentive (optimize mechanics before rewards) |
| Reward redemption below 70% | Reward delivery is delayed or redemption process is complicated | Auto-apply credits immediately, send instant notification, make redemption one-click; show running total in dashboard |
| Referred customers churn faster than organic | Referral incentive attracts low-intent users or onboarding for referred users is inadequate | Shift from cash/discount rewards to product-value rewards (feature unlock, extended trial); add referred-user onboarding path |
| Affiliate partners not producing conversions | Partners lack proper toolkit or audience mismatch | Provide pre-written copy, banner assets, comparison tables, and dedicated landing pages; audit partner audience fit |
---
Success Criteria
- K-factor reaches 0.3-0.7 range within 90 days of program launch (strong referral contribution without requiring virality)
- Referral CAC is below 50% of other acquisition channel CAC
- Active referrer percentage reaches 5-15% of active users
- Referral-sourced revenue contributes 10-25% of total new revenue within 6 months
- Referred customer LTV exceeds non-referred customer LTV (typical: 16-25% higher per industry data)
- Reward redemption rate exceeds 70% within 30 days of earning
- Double-sided program achieves 2x+ conversion rate compared to single-sided (validate within first 1,000 referrals)
---
Scope & Limitations
In scope: Customer referral program design (4-stage loop), incentive structure (single-sided, double-sided, tiered), trigger moment architecture, share mechanics, referral landing page specifications, viral coefficient modeling, affiliate program framework (commission models, tier systems, recruitment), and systematic optimization playbook.
Out of scope: Referral landing page visual design and CRO (use page-cro), signup flow optimization for referred users (use signup-flow-cro), post-signup onboarding for referred users (use onboarding-cro), churn prevention for referred customers (use churn-prevention), and reward pricing alignment (use pricing-strategy). Scripts operate on local data only -- no integrations with referral platforms (ReferralHero, Viral Loops, PartnerStack, etc.).
Limitations: K-factor benchmarks assume consumer or prosumer SaaS; B2B enterprise referral programs have different dynamics (lower K but higher per-referral value). Affiliate commission benchmarks (20-30% recurring) are SaaS-specific; marketplace and e-commerce commissions follow different models. Attribution windows (30-90 day cookies) face increasing limitations from browser privacy features (Safari ITP, Chrome third-party cookie deprecation). Revenue projections are estimates based on provided conversion rates.
---
Integration Points
- pricing-strategy -- Referral reward sizing must align with pricing margins and LTV; reward should be <30% of first payment
- signup-flow-cro -- Referred user signup flow should pre-fill email, show referrer context, and minimize friction
- onboarding-cro -- Referred users may need different onboarding path (they arrive with context from the referrer)
- churn-prevention -- Monitor referred customer retention separately; high referral churn wastes acquisition spend
- page-cro -- Referral landing page conversion optimization follows page-cro methodology
- popup-cro -- Post-purchase or post-milestone popups are natural referral trigger points
---
Anti-patterns
| Anti-pattern | Failure mode | Fix |
|---|---|---|
| Asking at signup instead of after the aha moment | Referrer has no value experience to share; share rates under 2% | Fire the trigger after activation or milestone — never before value is delivered |
| "Refer a friend" link buried in the account menu | Discovery rate near zero; program appears to "not work" | Surface at trigger moments in-product (modal, banner, post-action), not in settings |
| Single-sided reward where only the referrer benefits | Referred users feel exploited; conversion on referral landing page drops | Use double-sided rewards — both sides get value, aligned with program positioning |
| Reward sized larger than first-payment margin | Program grows but unit economics invert; CAC exceeds LTV | Cap reward at 30% of first payment (or <1 payback period); model before launch with referral_economics_calculator.py |
| Manual reward fulfillment | Delay between referral and reward kills the loop; referrer disengages | Automate reward delivery with in-app notification; trigger within 24 hours of referred user's qualifying event |
| Confusing affiliate program with customer referral | Wrong activation (customers don't behave like affiliates); wrong attribution (affiliates don't behave like advocates) | Decide the program type first using the Referral vs Affiliate Decision table; don't merge |
| Ignoring K-factor, optimizing only for share count | Shares grow but referred conversions don't; false sense of progress | Track K = shares × conversion rate; optimize the weakest stage, not the most visible one |
| Generic monthly "invite friends" email with no trigger | Becomes inbox noise; unsubscribe lift with no conversion lift | Event-triggered emails only — milestone, renewal, support-win, team-growth |
---
Related Skills
- pricing-strategy -- Use when referral reward sizing needs to align with pricing and margin structure.
- signup-flow-cro -- Use for optimizing the signup flow that referred users go through.
- onboarding-cro -- Use for optimizing the post-signup experience for referred users.
- churn-prevention -- Use to ensure referred customers retain at high rates (referral CAC is wasted if they churn).
- page-cro -- Use for optimizing the referral landing page conversion rate.
#!/usr/bin/env python3
"""Affiliate Commission Modeler - Model affiliate commission structures and economics.
Calculates per-tier commission economics, lifetime partner value, and compares
flat fee vs recurring percentage commission models.
Usage:
python affiliate_commission_modeler.py affiliate.json
python affiliate_commission_modeler.py affiliate.json --format json
"""
import argparse
import json
import sys
from typing import Any
def safe_divide(num: float, den: float, default: float = 0.0) -> float:
"""Safely divide."""
return num / den if den != 0 else default
DEFAULT_TIERS = [
{"name": "Standard", "min_conversions": 0, "commission_pct": 20},
{"name": "Silver", "min_conversions": 10, "commission_pct": 25},
{"name": "Gold", "min_conversions": 25, "commission_pct": 30},
]
def model_commissions(data: dict) -> dict:
"""Model affiliate commission economics."""
business = data.get("business", {})
program = data.get("program", {})
partners = data.get("partners", [])
avg_monthly_revenue = business.get("avg_monthly_revenue_per_customer", 0)
avg_customer_lifetime_months = business.get("avg_customer_lifetime_months", 24)
avg_ltv = avg_monthly_revenue * avg_customer_lifetime_months
gross_margin_pct = business.get("gross_margin_pct", 80) / 100
tiers = program.get("tiers", DEFAULT_TIERS)
cookie_window_days = program.get("cookie_window_days", 30)
payment_threshold = program.get("payment_threshold", 50)
commission_type = program.get("commission_type", "recurring") # recurring or flat
flat_fee = program.get("flat_fee_per_conversion", 0)
# Tier analysis
tier_analysis = []
for tier in tiers:
commission_pct = tier.get("commission_pct", 20) / 100
if commission_type == "recurring":
monthly_commission_per_customer = avg_monthly_revenue * commission_pct
lifetime_commission_per_customer = monthly_commission_per_customer * avg_customer_lifetime_months
effective_cac = lifetime_commission_per_customer
else:
monthly_commission_per_customer = 0
lifetime_commission_per_customer = flat_fee
effective_cac = flat_fee
# Margin after commission
if commission_type == "recurring":
margin_after_commission = (avg_monthly_revenue * gross_margin_pct) - monthly_commission_per_customer
margin_after_commission_pct = safe_divide(margin_after_commission, avg_monthly_revenue) * 100
else:
# Flat fee only impacts first month
margin_after_commission = (avg_monthly_revenue * gross_margin_pct) - safe_divide(flat_fee, avg_customer_lifetime_months)
margin_after_commission_pct = safe_divide(margin_after_commission, avg_monthly_revenue) * 100
ltv_after_commission = avg_ltv * gross_margin_pct - lifetime_commission_per_customer
ltv_cac = safe_divide(avg_ltv * gross_margin_pct, effective_cac) if effective_cac > 0 else float('inf')
tier_analysis.append({
"tier_name": tier.get("name", "Unknown"),
"min_conversions": tier.get("min_conversions", 0),
"commission_pct": tier.get("commission_pct", 20),
"monthly_commission_per_customer": round(monthly_commission_per_customer, 2),
"lifetime_commission_per_customer": round(lifetime_commission_per_customer, 2),
"effective_cac": round(effective_cac, 2),
"margin_after_commission_pct": round(margin_after_commission_pct, 1),
"ltv_after_commission": round(ltv_after_commission, 2),
"ltv_cac_ratio": round(ltv_cac, 1) if ltv_cac != float('inf') else "Infinite",
"sustainable": ltv_after_commission > 0,
})
# Partner analysis
partner_analysis = []
total_partner_revenue = 0
total_partner_cost = 0
for partner in partners:
name = partner.get("name", "Unknown")
conversions = partner.get("monthly_conversions", 0)
total_conversions = partner.get("total_conversions", conversions)
# Find applicable tier
applicable_tier = tiers[0]
for tier in tiers:
if total_conversions >= tier.get("min_conversions", 0):
applicable_tier = tier
commission_pct = applicable_tier.get("commission_pct", 20) / 100
if commission_type == "recurring":
monthly_payout = conversions * avg_monthly_revenue * commission_pct
# Also paying on retained customers from previous months
retained_customers = partner.get("active_customers", conversions)
total_monthly_payout = retained_customers * avg_monthly_revenue * commission_pct
else:
monthly_payout = conversions * flat_fee
total_monthly_payout = monthly_payout
monthly_revenue_generated = conversions * avg_monthly_revenue
annual_payout = total_monthly_payout * 12
annual_revenue = monthly_revenue_generated * 12
total_partner_revenue += annual_revenue
total_partner_cost += annual_payout
partner_analysis.append({
"name": name,
"tier": applicable_tier.get("name", "Standard"),
"monthly_conversions": conversions,
"total_conversions": total_conversions,
"monthly_revenue_generated": round(monthly_revenue_generated, 2),
"monthly_payout": round(total_monthly_payout, 2),
"annual_payout": round(annual_payout, 2),
"roi": round(safe_divide(annual_revenue, annual_payout), 1) if annual_payout > 0 else "Infinite",
})
# Model comparison (recurring vs flat)
model_comparison = None
if commission_type == "recurring":
# Compare against flat fee equivalent
# What flat fee gives same total payout as recurring over lifetime?
recurring_lifetime = avg_monthly_revenue * (tiers[0]["commission_pct"] / 100) * avg_customer_lifetime_months
model_comparison = {
"current_model": "Recurring",
"current_lifetime_cost": round(recurring_lifetime, 2),
"equivalent_flat_fee": round(recurring_lifetime, 2),
"note": f"A ${recurring_lifetime:.0f} flat fee equals your standard-tier recurring commission over {avg_customer_lifetime_months} months",
"recurring_advantage": "Aligns partner incentives with retention (they benefit from your retention)",
"flat_advantage": "Lower total cost if customers retain longer than expected; simpler accounting",
}
return {
"summary": {
"commission_type": commission_type,
"tier_count": len(tiers),
"partner_count": len(partners),
"avg_ltv": round(avg_ltv, 2),
"cookie_window_days": cookie_window_days,
"total_annual_partner_revenue": round(total_partner_revenue, 2),
"total_annual_partner_cost": round(total_partner_cost, 2),
"program_roi": round(safe_divide(total_partner_revenue, total_partner_cost), 1) if total_partner_cost > 0 else "N/A",
},
"tier_analysis": tier_analysis,
"partner_analysis": partner_analysis,
"model_comparison": model_comparison,
}
def format_text(result: dict) -> str:
"""Format as human-readable text."""
lines = []
s = result["summary"]
lines.append("=" * 60)
lines.append("AFFILIATE COMMISSION MODEL")
lines.append("=" * 60)
lines.append("")
lines.append(f"Commission Type: {s['commission_type'].title()}")
lines.append(f"Tiers: {s['tier_count']} | Partners: {s['partner_count']}")
lines.append(f"Avg Customer LTV: ${s['avg_ltv']:,.2f}")
lines.append(f"Cookie Window: {s['cookie_window_days']} days")
lines.append(f"Program ROI: {s['program_roi']}x" if isinstance(s['program_roi'], (int, float)) else f"Program ROI: {s['program_roi']}")
lines.append("")
lines.append("-" * 60)
lines.append("TIER ECONOMICS")
lines.append("-" * 60)
for tier in result["tier_analysis"]:
sustainable = "OK" if tier["sustainable"] else "UNSUSTAINABLE"
lines.append(f"\n {tier['tier_name']} ({tier['commission_pct']}% | {tier['min_conversions']}+ conversions)")
lines.append(f" Commission/customer/mo: ${tier['monthly_commission_per_customer']:,.2f}")
lines.append(f" Lifetime commission: ${tier['lifetime_commission_per_customer']:,.2f}")
lines.append(f" Margin after commission: {tier['margin_after_commission_pct']:.1f}%")
ltv_cac = tier['ltv_cac_ratio']
lines.append(f" LTV:CAC: {ltv_cac}:1" if isinstance(ltv_cac, (int, float)) else f" LTV:CAC: {ltv_cac}")
lines.append(f" Status: {sustainable}")
if result["partner_analysis"]:
lines.append("")
lines.append("-" * 60)
lines.append("PARTNER PERFORMANCE")
lines.append("-" * 60)
for p in result["partner_analysis"]:
roi_str = f"{p['roi']}x" if isinstance(p['roi'], (int, float)) else p['roi']
lines.append(f" {p['name']} [{p['tier']}]: {p['monthly_conversions']} conv/mo | ${p['monthly_payout']:,.0f}/mo payout | ROI: {roi_str}")
if result.get("model_comparison"):
mc = result["model_comparison"]
lines.append("")
lines.append("-" * 40)
lines.append("MODEL COMPARISON")
lines.append("-" * 40)
lines.append(f" Current: {mc['current_model']}")
lines.append(f" Lifetime cost/customer: ${mc['current_lifetime_cost']:,.2f}")
lines.append(f" Equivalent flat fee: ${mc['equivalent_flat_fee']:,.2f}")
lines.append(f" Recurring advantage: {mc['recurring_advantage']}")
lines.append(f" Flat advantage: {mc['flat_advantage']}")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Model affiliate commission structures and economics."
)
parser.add_argument(
"input_file",
help="Path to JSON file with affiliate program data",
)
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
sys.exit(1)
result = model_commissions(data)
if args.format == "json":
print(json.dumps(result, indent=2))
else:
print(format_text(result))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Referral Economics Calculator - Model referral program economics and ROI.
Calculates reward sizing, K-factor, referral CAC, ROI projections, and break-even
analysis. Compares double-sided vs single-sided reward structures.
Usage:
python referral_economics_calculator.py program.json
python referral_economics_calculator.py program.json --format json
"""
import argparse
import json
import sys
from typing import Any
def safe_divide(num: float, den: float, default: float = 0.0) -> float:
"""Safely divide."""
return num / den if den != 0 else default
def calculate_k_factor(avg_invitations: float, invitation_conversion_rate: float) -> float:
"""Calculate viral coefficient (K-factor)."""
return avg_invitations * invitation_conversion_rate
def rate_k_factor(k: float) -> str:
"""Rate K-factor against benchmarks."""
if k >= 1.0:
return "Viral (exponential growth)"
elif k >= 0.7:
return "Strong referral contribution"
elif k >= 0.3:
return "Moderate referral contribution"
elif k >= 0.1:
return "Weak -- program needs optimization"
else:
return "Negligible -- fundamental redesign needed"
def model_economics(data: dict) -> dict:
"""Model referral program economics."""
program = data.get("program", {})
business = data.get("business", {})
# Business metrics
avg_ltv = business.get("avg_customer_ltv", 0)
avg_first_payment = business.get("avg_first_payment", 0)
other_cac = business.get("other_channel_cac", 0)
active_users = business.get("active_users", 0)
avg_monthly_revenue = business.get("avg_monthly_revenue_per_customer", 0)
# Program metrics
referrer_reward = program.get("referrer_reward", 0)
referred_reward = program.get("referred_reward", 0)
is_double_sided = referred_reward > 0
reward_type = program.get("reward_type", "credit") # credit, cash, discount, feature
avg_invitations = program.get("avg_invitations_per_user", 0)
invitation_conversion = program.get("invitation_conversion_rate", 0)
active_referrer_pct = program.get("active_referrer_pct", 5) / 100
# K-factor
k_factor = calculate_k_factor(avg_invitations, invitation_conversion)
k_rating = rate_k_factor(k_factor)
# Cost per referral
total_reward_per_referral = referrer_reward + referred_reward
referral_cac = total_reward_per_referral # Assuming 1:1 reward to acquisition
# CAC comparison
cac_savings_pct = safe_divide(other_cac - referral_cac, other_cac) * 100
# LTV:CAC for referrals
ltv_cac_ratio = safe_divide(avg_ltv, referral_cac) if referral_cac > 0 else float('inf')
# Maximum sustainable reward
target_referral_cac_pct = 15 # 15% of LTV
max_reward = avg_ltv * (target_referral_cac_pct / 100)
if is_double_sided:
max_per_side = max_reward / 2
else:
max_per_side = max_reward
# Revenue projections
active_referrers = int(active_users * active_referrer_pct)
monthly_referrals_sent = active_referrers * avg_invitations
monthly_new_customers = int(monthly_referrals_sent * invitation_conversion)
monthly_referral_revenue = monthly_new_customers * avg_monthly_revenue
annual_referral_revenue = monthly_referral_revenue * 12
monthly_reward_cost = monthly_new_customers * total_reward_per_referral
annual_reward_cost = monthly_reward_cost * 12
# ROI
annual_profit = annual_referral_revenue - annual_reward_cost
roi_pct = safe_divide(annual_profit, annual_reward_cost) * 100
# Referral revenue share
total_monthly_revenue = active_users * avg_monthly_revenue if avg_monthly_revenue > 0 else 1
referral_revenue_share = safe_divide(monthly_referral_revenue, total_monthly_revenue) * 100
# Double-sided vs single-sided comparison
comparison = None
if is_double_sided:
# Model what single-sided would look like (assume 40% lower conversion)
single_conversion = invitation_conversion * 0.6
single_new_customers = int(monthly_referrals_sent * single_conversion)
single_cost = single_new_customers * referrer_reward
single_revenue = single_new_customers * avg_monthly_revenue * 12
comparison = {
"double_sided": {
"annual_customers": monthly_new_customers * 12,
"annual_revenue": round(annual_referral_revenue, 2),
"annual_cost": round(annual_reward_cost, 2),
"annual_profit": round(annual_profit, 2),
},
"single_sided_estimate": {
"annual_customers": single_new_customers * 12,
"annual_revenue": round(single_revenue, 2),
"annual_cost": round(single_cost * 12, 2),
"annual_profit": round(single_revenue - single_cost * 12, 2),
"note": "Estimated at 40% lower conversion rate without referred reward",
},
}
return {
"k_factor": {
"value": round(k_factor, 3),
"rating": k_rating,
"avg_invitations": avg_invitations,
"invitation_conversion_rate": invitation_conversion,
},
"unit_economics": {
"referral_cac": round(referral_cac, 2),
"other_channel_cac": other_cac,
"cac_savings_pct": round(cac_savings_pct, 1),
"ltv_cac_ratio": round(ltv_cac_ratio, 1) if ltv_cac_ratio != float('inf') else "Infinite",
"max_sustainable_reward": round(max_reward, 2),
"max_per_side": round(max_per_side, 2),
"current_reward_sustainable": total_reward_per_referral <= max_reward,
},
"projections": {
"active_referrers": active_referrers,
"monthly_referrals_sent": int(monthly_referrals_sent),
"monthly_new_customers": monthly_new_customers,
"monthly_referral_revenue": round(monthly_referral_revenue, 2),
"annual_referral_revenue": round(annual_referral_revenue, 2),
"monthly_reward_cost": round(monthly_reward_cost, 2),
"annual_reward_cost": round(annual_reward_cost, 2),
"annual_profit": round(annual_profit, 2),
"roi_pct": round(roi_pct, 1),
"referral_revenue_share_pct": round(referral_revenue_share, 1),
},
"reward_structure": {
"type": "double_sided" if is_double_sided else "single_sided",
"referrer_reward": referrer_reward,
"referred_reward": referred_reward,
"total_per_referral": total_reward_per_referral,
"reward_type": reward_type,
},
"comparison": comparison,
}
def format_text(result: dict) -> str:
"""Format as human-readable text."""
lines = []
lines.append("=" * 60)
lines.append("REFERRAL PROGRAM ECONOMICS")
lines.append("=" * 60)
lines.append("")
# K-factor
kf = result["k_factor"]
lines.append("-" * 40)
lines.append("VIRAL COEFFICIENT (K-FACTOR)")
lines.append("-" * 40)
lines.append(f" K-factor: {kf['value']}")
lines.append(f" Rating: {kf['rating']}")
lines.append(f" Avg invitations/user: {kf['avg_invitations']}")
lines.append(f" Invitation conversion: {kf['invitation_conversion_rate']*100:.1f}%")
lines.append("")
# Unit economics
ue = result["unit_economics"]
lines.append("-" * 40)
lines.append("UNIT ECONOMICS")
lines.append("-" * 40)
lines.append(f" Referral CAC: ${ue['referral_cac']:>10,.2f}")
lines.append(f" Other Channel CAC: ${ue['other_channel_cac']:>10,.2f}")
lines.append(f" CAC Savings: {ue['cac_savings_pct']:>10.1f}%")
ltv_cac = ue['ltv_cac_ratio']
lines.append(f" LTV:CAC Ratio: {ltv_cac}:1" if isinstance(ltv_cac, (int, float)) else f" LTV:CAC Ratio: {ltv_cac}")
lines.append(f" Max Sustainable Reward: ${ue['max_sustainable_reward']:>9,.2f}")
sustainable = "Yes" if ue["current_reward_sustainable"] else "NO -- reward exceeds 15% of LTV"
lines.append(f" Current Reward OK: {sustainable}")
lines.append("")
# Projections
pr = result["projections"]
lines.append("-" * 40)
lines.append("REVENUE PROJECTIONS")
lines.append("-" * 40)
lines.append(f" Active Referrers: {pr['active_referrers']:>10,}")
lines.append(f" Monthly Referrals: {pr['monthly_referrals_sent']:>10,}")
lines.append(f" Monthly New Customers: {pr['monthly_new_customers']:>10,}")
lines.append(f" Monthly Revenue: ${pr['monthly_referral_revenue']:>10,.2f}")
lines.append(f" Annual Revenue: ${pr['annual_referral_revenue']:>10,.2f}")
lines.append(f" Annual Reward Cost: ${pr['annual_reward_cost']:>10,.2f}")
lines.append(f" Annual Profit: ${pr['annual_profit']:>10,.2f}")
lines.append(f" ROI: {pr['roi_pct']:>10.1f}%")
lines.append(f" Revenue Share: {pr['referral_revenue_share_pct']:>10.1f}% of total")
lines.append("")
# Reward structure
rs = result["reward_structure"]
lines.append("-" * 40)
lines.append("REWARD STRUCTURE")
lines.append("-" * 40)
lines.append(f" Type: {rs['type'].replace('_', ' ').title()}")
lines.append(f" Referrer: ${rs['referrer_reward']:,.2f} ({rs['reward_type']})")
if rs["referred_reward"] > 0:
lines.append(f" Referred: ${rs['referred_reward']:,.2f} ({rs['reward_type']})")
lines.append(f" Total/Referral: ${rs['total_per_referral']:,.2f}")
lines.append("")
# Comparison
if result.get("comparison"):
comp = result["comparison"]
lines.append("-" * 40)
lines.append("DOUBLE vs SINGLE-SIDED COMPARISON")
lines.append("-" * 40)
ds = comp["double_sided"]
ss = comp["single_sided_estimate"]
lines.append(f" {'':20} {'Double':>12} {'Single (est)':>12}")
lines.append(f" {'Customers/yr':20} {ds['annual_customers']:>12,} {ss['annual_customers']:>12,}")
lines.append(f" {'Revenue/yr':20} ${ds['annual_revenue']:>10,.0f} ${ss['annual_revenue']:>10,.0f}")
lines.append(f" {'Cost/yr':20} ${ds['annual_cost']:>10,.0f} ${ss['annual_cost']:>10,.0f}")
lines.append(f" {'Profit/yr':20} ${ds['annual_profit']:>10,.0f} ${ss['annual_profit']:>10,.0f}")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Calculate referral program economics and ROI."
)
parser.add_argument(
"input_file",
help="Path to JSON file with program economics data",
)
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
sys.exit(1)
result = model_economics(data)
if args.format == "json":
print(json.dumps(result, indent=2))
else:
print(format_text(result))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Referral Funnel Analyzer - Analyze the 4-stage referral loop with diagnostics.
Evaluates each stage (trigger, share, convert, reward) against benchmarks, identifies
the weakest stage, and provides prioritized improvement recommendations.
Usage:
python referral_funnel_analyzer.py funnel.json
python referral_funnel_analyzer.py funnel.json --format json
"""
import argparse
import json
import sys
from typing import Any
STAGE_BENCHMARKS = {
"awareness": {"target": 40, "good": 25, "label": "Program Awareness (% of active users who know it exists)"},
"active_referrers": {"target": 15, "good": 5, "label": "Active Referrers (% of aware users who send referrals)"},
"share_rate": {"target": 40, "good": 20, "label": "Share Rate (% of prompted users who share)"},
"referred_conversion": {"target": 25, "good": 15, "label": "Referred Conversion (% of referrals that convert)"},
"reward_redemption": {"target": 90, "good": 70, "label": "Reward Redemption (% redeemed within 30 days)"},
}
STAGE_RECOMMENDATIONS = {
"awareness": [
"Add persistent referral widget to user dashboard",
"Trigger referral prompt after NPS 9-10 responses",
"Send post-activation email with referral link (3-5 days after activation)",
"Add referral CTA to monthly usage digest emails",
"Show referral prompt after milestone achievements",
],
"active_referrers": [
"Improve incentive visibility (show reward prominently in prompt)",
"Use double-sided rewards if currently single-sided",
"Time triggers to high-satisfaction moments (post-milestone, post-support resolution)",
"Test different reward types (credit vs cash vs feature unlock)",
"Add tiered rewards for multiple referrals (gamification)",
],
"share_rate": [
"Add one-click copy link button (most popular share method)",
"Pre-fill share messages in first person (sounds personal, not marketing)",
"Add native share sheet on mobile for frictionless sharing",
"Include multiple share channels (email, Slack, LinkedIn, Twitter)",
"Reduce steps between referral prompt and actual share action",
],
"referred_conversion": [
"Personalize landing page with referrer name and photo",
"Display the incentive above the fold on referral landing page",
"Pre-fill referred user email if available from share mechanism",
"Add SSO/social login to reduce signup friction",
"Ensure 30-day attribution cookie for multi-session conversion",
],
"reward_redemption": [
"Auto-apply account credits immediately (no manual redemption)",
"Send instant notification when referral converts",
"Show cumulative earnings in referral dashboard",
"Send reminder email for unredeemed rewards after 7 days",
"Make redemption one-click (no extra steps or forms)",
],
}
def safe_divide(num: float, den: float, default: float = 0.0) -> float:
"""Safely divide."""
return num / den if den != 0 else default
def rate_stage(value: float, benchmark: dict) -> str:
"""Rate a stage against benchmarks."""
if value >= benchmark["target"]:
return "Excellent"
elif value >= benchmark["good"]:
return "Good"
elif value >= benchmark["good"] * 0.5:
return "Needs Improvement"
else:
return "Critical"
def analyze_funnel(data: dict) -> dict:
"""Analyze referral funnel stages."""
stages = data.get("stages", {})
active_users = data.get("active_users", 0)
stage_analysis = []
weakest_stage = None
weakest_score = 100
for stage_key, benchmark in STAGE_BENCHMARKS.items():
value = stages.get(stage_key)
if value is None:
continue
rating = rate_stage(value, benchmark)
gap_to_target = benchmark["target"] - value
stage_data = {
"stage": stage_key,
"label": benchmark["label"],
"current_value_pct": value,
"target_pct": benchmark["target"],
"good_pct": benchmark["good"],
"gap_to_target_pp": round(gap_to_target, 1),
"rating": rating,
}
# Track weakest stage
normalized_score = safe_divide(value, benchmark["target"]) * 100
if normalized_score < weakest_score:
weakest_score = normalized_score
weakest_stage = stage_key
stage_analysis.append(stage_data)
# Generate recommendations for weakest stages (sorted by gap)
recommendations = []
for stage in sorted(stage_analysis, key=lambda s: -s["gap_to_target_pp"]):
if stage["gap_to_target_pp"] > 0:
recs = STAGE_RECOMMENDATIONS.get(stage["stage"], [])
recommendations.append({
"stage": stage["stage"],
"priority": "Critical" if stage["rating"] == "Critical" else "High" if stage["rating"] == "Needs Improvement" else "Medium",
"gap_pp": stage["gap_to_target_pp"],
"actions": recs[:3], # Top 3 actions
})
# Overall funnel health
avg_gap = sum(s["gap_to_target_pp"] for s in stage_analysis) / len(stage_analysis) if stage_analysis else 0
if avg_gap <= 5:
overall = "Healthy"
elif avg_gap <= 15:
overall = "Needs Optimization"
else:
overall = "Underperforming"
# Impact estimation
impact = None
if active_users > 0 and weakest_stage:
# If we fix the weakest stage to target, what's the downstream impact?
awareness_pct = stages.get("awareness", 40) / 100
referrer_pct = stages.get("active_referrers", 10) / 100
share_rate = stages.get("share_rate", 30) / 100
conversion_rate = stages.get("referred_conversion", 20) / 100
avg_invitations = data.get("avg_invitations_per_referrer", 3)
current_monthly_customers = int(
active_users * awareness_pct * referrer_pct * avg_invitations * conversion_rate
)
# Simulate fixing weakest stage to target
fixed_values = dict(stages)
if weakest_stage in STAGE_BENCHMARKS:
fixed_values[weakest_stage] = STAGE_BENCHMARKS[weakest_stage]["target"]
fixed_awareness = fixed_values.get("awareness", 40) / 100
fixed_referrer = fixed_values.get("active_referrers", 10) / 100
fixed_conversion = fixed_values.get("referred_conversion", 20) / 100
fixed_monthly_customers = int(
active_users * fixed_awareness * fixed_referrer * avg_invitations * fixed_conversion
)
impact = {
"weakest_stage": weakest_stage,
"current_monthly_referred_customers": current_monthly_customers,
"projected_monthly_after_fix": fixed_monthly_customers,
"incremental_customers_per_month": fixed_monthly_customers - current_monthly_customers,
}
return {
"summary": {
"overall_health": overall,
"stages_analyzed": len(stage_analysis),
"weakest_stage": weakest_stage,
"avg_gap_to_target_pp": round(avg_gap, 1),
},
"stage_analysis": stage_analysis,
"recommendations": recommendations,
"impact_estimate": impact,
}
def format_text(result: dict) -> str:
"""Format analysis as human-readable text."""
lines = []
s = result["summary"]
lines.append("=" * 60)
lines.append("REFERRAL FUNNEL ANALYSIS")
lines.append("=" * 60)
lines.append("")
lines.append(f"Overall Health: {s['overall_health']}")
lines.append(f"Weakest Stage: {s['weakest_stage']}")
lines.append(f"Avg Gap to Target: {s['avg_gap_to_target_pp']}pp")
lines.append("")
lines.append("-" * 60)
lines.append("STAGE-BY-STAGE ANALYSIS")
lines.append("-" * 60)
for stage in result["stage_analysis"]:
lines.append(f"\n {stage['label']}")
lines.append(f" Current: {stage['current_value_pct']}% | Target: {stage['target_pct']}% | Gap: {stage['gap_to_target_pp']}pp | {stage['rating']}")
if result["recommendations"]:
lines.append("")
lines.append("-" * 60)
lines.append("PRIORITIZED RECOMMENDATIONS")
lines.append("-" * 60)
for rec in result["recommendations"]:
lines.append(f"\n [{rec['priority']}] {rec['stage']} (gap: {rec['gap_pp']}pp)")
for action in rec["actions"]:
lines.append(f" - {action}")
if result.get("impact_estimate"):
imp = result["impact_estimate"]
lines.append("")
lines.append("-" * 40)
lines.append("IMPACT ESTIMATE")
lines.append("-" * 40)
lines.append(f" If '{imp['weakest_stage']}' reaches target:")
lines.append(f" Current: {imp['current_monthly_referred_customers']:,} customers/month")
lines.append(f" Projected: {imp['projected_monthly_after_fix']:,} customers/month")
lines.append(f" Incremental: +{imp['incremental_customers_per_month']:,} customers/month")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Analyze the 4-stage referral funnel with diagnostics."
)
parser.add_argument(
"input_file",
help="Path to JSON file with referral funnel metrics",
)
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
sys.exit(1)
result = analyze_funnel(data)
if args.format == "json":
print(json.dumps(result, indent=2))
else:
print(format_text(result))
if __name__ == "__main__":
main()
Related skills
FAQ
Should I run a customer referral or affiliate program?
If your customers are enthusiastic and social, start with customer referrals; if they are businesses buying for a team, start with affiliates.
When should I ask users to refer?
At high-signal moments like after the aha moment, a milestone, great support (NPS 9-10) or a renewal, never at signup or in a generic monthly email.