Back to catalog

monetization-analyzer

Analyze game concepts for monetization potential, willingness-to-pay, viral mechanics, and revenue generation. Ranks concepts by total monetization score and identifies top revenue opportunities.

  • Category: discovered
  • Tags: github, community
  • Version: 1.0.0
  • Author: walid
  • Downloads: 0
  • GitHub stars: 1
  • Updated: 2025-11-21

Download the latest version (v1.0.0) from this page.

SKILL.md

---
name: monetization-analyzer
description: Analyze game concepts for monetization potential, willingness-to-pay, viral mechanics, and revenue generation. Ranks concepts by total monetization score and identifies top revenue opportunities.
---

# Monetization Analyzer Skill

## Purpose

This skill evaluates game concepts to identify the most monetizable opportunities based on:
- **Willingness-to-Pay (WTP)** analysis from market data
- **Viral potential** and organic growth mechanics
- **Revenue model optimization** (premium, F2P, subscription, hybrid)
- **Market demand** and addressable market size
- **Competitive pricing** positioning
- **Lifetime Value (LTV)** projections

**Output**: Ranked list of top 3 most monetizable game concepts with detailed financial projections and go-to-market recommendations.

## When to Use This Skill

Use this skill when you have:
- ✅ Multiple game concepts to evaluate for investment prioritization
- ✅ Market analysis data showing pricing sentiment and willingness-to-pay signals
- ✅ Need to identify which concepts have highest revenue potential
- ✅ Want to optimize monetization models before development
- ✅ Require financial projections for pitch decks or funding proposals
- ✅ Need to validate business model assumptions with market data

## Prerequisites

### Required Input Files

1. **Market Analysis Report** (from `market-analyst` skill)
   - Location: `/docs/market-analysis-*.md`
   - Must include: Sentiment data on pricing, monetization pain points, willingness-to-pay signals
   - Example: `market-analysis-fps-games-2025-10-26.md`

2. **Game Concepts Document** (from brainstorming/design)
   - Location: `/docs/*-game-concepts-*.md` or `/docs/plans/*-design.md`
   - Must include: Price points, target personas, distribution channels, competitors
   - Example: `fps-game-concepts-market-driven-2025-10-26.md`

### Optional Input Files

3. **Competitor Financial Data** (if available)
   - Revenue reports, player counts, ARPU data
   - Enhances accuracy of projections

## Core Workflow

### Phase 1: Data Extraction and Normalization

**1. Load Market Analysis**

Extract willingness-to-pay signals:

```javascript
WTP_Signals = {
  price_sentiment: {
    "$0 (F2P)": {positive: X%, negative: Y%, mentions: N},
    "$10-20": {positive: X%, negative: Y%, mentions: N},
    "$20-30": {positive: X%, negative: Y%, mentions: N},
    "$60-70": {positive: X%, negative: Y%, mentions: N},
    "$70 + MTX": {positive: X%, negative: Y%, mentions: N}
  },
  monetization_pain_points: [
    {issue: "Premium + battle pass", severity: "CRITICAL", mentions: N},
    {issue: "Loot boxes", severity: "HIGH", mentions: N}
  ],
  value_propositions: [
    {model: "F2P cosmetic-only", sentiment: X%, examples: []},
    {model: "Budget indie ($15-25)", sentiment: X%, examples: []}
  ]
}
```

**2. Load Game Concepts**

Extract monetization-relevant data for each concept:

```javascript
GameConcept = {
  name: string,
  price_point: number | "F2P",
  monetization_model: string,
  target_audience: {
    primary_persona: {},
    market_size_estimate: number,
    spending_behavior: string
  },
  competitors: [{name, price, model, performance}],
  distribution_channels: [{platform, percentage, rationale}],
  lifecycle_commitment: string,
  development_cost_estimate: number
}
```

### Phase 2: Willingness-to-Pay Analysis

**3. Calculate WTP Score (0-100)**

```javascript
function calculateWTP(concept, marketData) {
  const score = {
    price_sentiment_alignment: 0,    // Does price match positive sentiment tier?
    value_perception: 0,              // Content/$ ratio vs. market expectations
    monetization_model_fit: 0,        // Model aligns with audience preferences?
    competitive_positioning: 0,       // Price competitive advantage?
    pain_point_avoidance: 0          // Avoids monetization red flags?
  };

  // Price Sentiment Alignment (0-30 points)
  const priceТier = getPriceTier(concept.price_point);
  const sentiment = marketData.price_sentiment[priceTier];
  score.price_sentiment_alignment = (sentiment.positive / 100) * 30;

  // Value Perception (0-25 points)
  const contentHours = estimateContentHours(concept);
  const pricePerHour = concept.price_point / contentHours;
  const marketAvgPricePerHour = calculateMarketAverage();

  if (pricePerHour < marketAvgPricePerHour * 0.8) {
    score.value_perception = 25; // Excellent value
  } else if (pricePerHour < marketAvgPricePerHour) {
    score.value_perception = 18; // Good value
  } else if (pricePerHour < marketAvgPricePerHour * 1.2) {
    score.value_perception = 10; // Fair value
  } else {
    score.value_perception = 0; // Poor value
  }

  // Monetization Model Fit (0-20 points)
  const modelSentiment = marketData.value_propositions.find(
    vp => vp.model === concept.monetization_model
  );
  score.monetization_model_fit = (modelSentiment.sentiment / 100) * 20;

  // Competitive Positioning (0-15 points)
  const competitorPrices = concept.competitors.map(c => c.price);
  const avgCompetitorPrice = average(competitorPrices);

  if (concept.price_point < avgCompetitorPrice * 0.7) {
    score.competitive_positioning = 15; // Undercut leaders
  } else if (concept.price_point < avgCompetitorPrice) {
    score.competitive_positioning = 10; // Competitive pricing
  } else {
    score.competitive_positioning = 5; // Premium positioning
  }

  // Pain Point Avoidance (0-10 points)
  const painPoints = marketData.monetization_pain_points;
  let violations = 0;

  painPoints.forEach(pp => {
    if (conceptViolatesPainPoint(concept, pp)) {
      violations += (pp.severity === "CRITICAL") ? 5 : 2;
    }
  });

  score.pain_point_avoidance = Math.max(0, 10 - violations);

  return {
    total: Object.values(score).reduce((a, b) => a + b, 0),
    breakdown: score,
    confidence: calculateConfidence(marketData.sample_size)
  };
}
```

**WTP Score Interpretation:**
- **90-100**: Exceptional WTP, price optimization perfect
- **75-89**: Strong WTP, minor adjustments possible
- **60-74**: Moderate WTP, consider price/model changes
- **Below 60**: Weak WTP, major repositioning needed

### Phase 3: Viral Potential Analysis

**4. Calculate Viral Score (0-100)**

```javascript
function calculateViralPotential(concept, marketData) {
  const score = {
    shareability: 0,           // Content naturally creates shareable moments?
    accessibility: 0,          // Low barrier to entry?
    network_effects: 0,        // Benefits from friend invites?
    streamer_appeal: 0,        // Twitch/YouTube friendly?
    novelty_factor: 0,         // Unique enough to generate buzz?
    social_features: 0         // Built for social play/sharing?
  };

  // Shareability (0-20 points)
  const shareableGenres = ["party game", "asymmetric", "sports hybrid", "roguelike"];
  if (shareableGenres.some(g => concept.genre.includes(g))) {
    score.shareability = 20;
  } else if (concept.genre.includes("competitive") || concept.genre.includes("co-op")) {
    score.shareability = 12;
  } else {
    score.shareability = 5; // Single-player, narrative
  }

  // Accessibility (0-20 points)
  if (concept.price_point === "F2P") {
    score.accessibility = 20; // Zero barrier
  } else if (concept.price_point <= 15) {
    score.accessibility = 15; // Impulse purchase
  } else if (concept.price_point <= 25) {
    score.accessibility = 10; // Reasonable
  } else {
    score.accessibility = 5; // Higher barrier
  }

  // Network Effects (0-20 points)
  if (concept.monetization_model.includes("F2P") || concept.monetization_model.includes("viral")) {
    score.network_effects = 20;
  } else if (concept.description.includes("co-op") || concept.description.includes("multiplayer")) {
    score.network_effects = 12;
  } else {
    score.network_effects = 0;
  }

  // Streamer Appeal (0-15 points)
  const streamerFriendly = [
    concept.genre.includes("asymmetric"),
    concept.genre.includes("roguelike"),
    concept.genre.includes("party"),
    concept.description.includes("viral moments"),
    concept.description.includes("spectator")
  ];
  score.streamer_appeal = streamerFriendly.filter(Boolean).length * 3;

  // Novelty Factor (0-15 points)
  const noveltyIndicators = marketData.novelty_successes || [];
  if (noveltyIndicators.some(n => concept.description.includes(n.innovation))) {
    score.novelty_factor = 15;
  } else if (concept.description.includes("unique") || concept.description.includes("first")) {
    score.novelty_factor = 10;
  } else {
    score.novelty_factor = 5;
  }

  // Social Features (0-10 points)
  const socialKeywords = ["co-op", "multiplayer", "friend", "clan", "team", "squad"];
  const socialCount = socialKeywords.filter(kw =>
    concept.description.toLowerCase().includes(kw)
  ).length;
  score.social_features = Math.min(10, socialCount * 2);

  return {
    total: Object.values(score).reduce((a, b) => a + b, 0),
    breakdown: score,
    viral_coefficient: estimateViralCoefficient(score.total)
  };
}

function estimateViralCoefficient(viralScore) {
  // Viral coefficient: How many new users does each user bring?
  // K > 1 = exponential growth, K < 1 = paid acquisition needed
  if (viralScore >= 85) return 1.5;      // Exceptional viral growth
  if (viralScore >= 70) return 1.2;      // Strong organic growth
  if (viralScore >= 55) return 0.8;      // Some viral mechanics
  if (viralScore >= 40) return 0.4;      // Minimal viral spread
  return 0.2;                             // Requires paid marketing
}
```

**Viral Score Interpretation:**
- **85-100**: Viral hit potential (K > 1.2), minimal marketing spend
- **70-84**: Strong organic growth (K ~1.0), word-of-mouth driven
- **55-69**: Moderate virality (K ~0.8), some paid marketing needed
- **40-54**: Low virality (K ~0.4), heavy marketing investment required
- **Below 40**: No viral mechanics (K ~0.2), paid acquisition only

### Phase 4: Revenue Projection Modeling

**5. Calculate Revenue Potential (Year 1-3 Projections)**

```javascript
function projectRevenue(concept, wtpScore, viralScore, marketData) {
  const model = concept.monetization_model;

  // Addressable Market Size
  const TAM = estimateTotalAddressableMarket(concept, marketData);
  const SAM = TAM * 0.15; // Serviceable addressable (15% of TAM realistic)
  const SOM = SAM * getMarketShareEstimate(viralScore, concept.competitors.length);

  // Player Acquisition Model
  const year1Players = calculateYear1Players(concept, viralScore, SOM);
  const year2Players = year1Players * getRetentionMultiplier(concept.lifecycle_commitment);
  const year3Players = year2Players * getGrowthMultiplier(viralScore);

  // Revenue Calculations
  if (model.includes("F2P")) {
    return projectF2PRevenue(year1Players, year2Players, year3Players, concept);
  } else if (model.includes("premium") || typeof concept.price_point === "number") {
    return projectPremiumRevenue(year1Players, year2Players, year3Players, concept);
  } else {
    return projectHybridRevenue(year1Players, year2Players, year3Players, concept);
  }
}

function projectF2PRevenue(y1Players, y2Players, y3Players, concept) {
  // F2P Model: Base * Conversion Rate * ARPPU
  const conversionRate = 0.03; // Industry avg: 3-5% pay
  const ARPPU = estimateARPPU(concept); // Average revenue per paying user

  const y1Revenue = y1Players * conversionRate * ARPPU;
  const y2Revenue = y2Players * (conversionRate * 1.1) * (ARPPU * 1.15); // Improve over time
  const y3Revenue = y3Players * (conversionRate * 1.15) * (ARPPU * 1.25);

  return {
    year1: {players: y1Players, revenue: y1Revenue, ARPU: y1Revenue / y1Players},
    year2: {players: y2Players, revenue: y2Revenue, ARPU: y2Revenue / y2Players},
    year3: {players: y3Players, revenue: y3Revenue, ARPU: y3Revenue / y3Players},
    total_3yr: y1Revenue + y2Revenue + y3Revenue,
    LTV: (y1Revenue + y2Revenue + y3Revenue) / y1Players
  };
}

function projectPremiumRevenue(y1Players, y2Players, y3Players, concept) {
  // Premium Model: Units Sold * Price + Optional DLC
  const basePrice = concept.price_point;
  const dlcAttachRate = 0.25; // 25% buy DLC
  const avgDLCSpend = basePrice * 0.6; // DLC ~60% of base price

  const y1Revenue = (y1Players * basePrice) + (y1Players * dlcAttachRate * avgDLCSpend * 0.5);
  const y2Revenue = (y2Players * 0.3 * basePrice) + (y2Players * 0.3 * dlcAttachRate * avgDLCSpend);
  const y3Revenue = (y3Players * 0.1 * basePrice) + (y3Players * 0.1 * dlcAttachRate * avgDLCSpend);

  return {
    year1: {players: y1Players, revenue: y1Revenue, ARPU: basePrice},
    year2: {players: y2Players * 0.3, revenue: y2Revenue, ARPU: basePrice},
    year3: {players: y3Players * 0.1, revenue: y3Revenue, ARPU: basePrice},
    total_3yr: y1Revenue + y2Revenue + y3Revenue,
    LTV: basePrice + (dlcAttachRate * avgDLCSpend)
  };
}

function estimateARPPU(concept) {
  // Average Revenue Per Paying User (F2P)
  if (concept.genre.includes("competitive")) return 45; // Esports skin buyers spend more
  if (concept.genre.includes("party")) return 20; // Casual spenders
  if (concept.genre.includes("co-op")) return 30; // Mid-tier
  return 25; // Default
}

function estimateTotalAddressableMarket(concept, marketData) {
  // Use market analysis data + platform data
  const steamActivePlayers = 120000000; // ~120M monthly active on Steam
  const genreMultiplier = getGenreMarketShare(concept.genre);
  return steamActivePlayers * genreMultiplier;
}

function getMarketShareEstimate(viralScore, competitorCount) {
  // Viral potential + competitive landscape determines realistic share
  let baseShare = 0.01; // 1% of SAM baseline

  if (viralScore >= 85) baseShare *= 3;      // Viral hit
  else if (viralScore >= 70) baseShare *= 2; // Strong growth
  else if (viralScore >= 55) baseShare *= 1.5;

  // Competitive penalty
  if (competitorCount > 5) baseShare *= 0.7;
  else if (competitorCount > 3) baseShare *= 0.85;

  return baseShare;
}
```

**6. Calculate Development ROI**

```javascript
function calculateROI(concept, revenueProjection) {
  const devCost = concept.development_cost_estimate || estimateDevCost(concept);
  const marketingCost = estimateMarketingCost(concept, revenueProjection.year1.players);
  const totalInvestment = devCost + marketingCost;

  const grossRevenue = revenueProjection.total_3yr;
  const platformFees = grossRevenue * 0.30; // Steam/console take 30%
  const netRevenue = grossRevenue - platformFees;
  const netProfit = netRevenue - totalInvestment;

  return {
    investment: totalInvestment,
    gross_revenue: grossRevenue,
    net_revenue: netRevenue,
    net_profit: netProfit,
    ROI_percentage: (netProfit / totalInvestment) * 100,
    payback_period_months: calculatePaybackPeriod(totalInvestment, revenueProjection),
    break_even_units: totalInvestment / (concept.price_point || 25)
  };
}

function estimateDevCost(concept) {
  // Based on scope, team size, timeline
  if (concept.description.includes("solo") || concept.description.includes("small team")) {
    return 150000; // $150K
  } else if (concept.description.includes("128-player") || concept.description.includes("large-scale")) {
    return 8000000; // $8M
  } else {
    return 1200000; // $1.2M (AA indie default)
  }
}

function estimateMarketingCost(concept, year1Players) {
  // Cost per acquisition based on viral coefficient
  const viralCoef = concept.viral_coefficient || 0.5;

  if (viralCoef >= 1.2) {
    // Viral growth, minimal paid marketing
    return year1Players * 0.50; // $0.50 CPA (mostly organic)
  } else if (viralCoef >= 0.8) {
    return year1Players * 2; // $2 CPA
  } else {
    return year1Players * 5; // $5 CPA (heavy paid)
  }
}
```

### Phase 5: Monetization Optimization Recommendations

**7. Analyze Monetization Model Fit**

```javascript
function analyzeMonetizationModel(concept, wtpScore, viralScore, marketData) {
  const currentModel = concept.monetization_model;
  const alternativeModels = [];

  // Test F2P vs. Premium
  if (currentModel.includes("premium") && viralScore >= 70) {
    alternativeModels.push({
      model: "F2P with cosmetic monetization",
      rationale: `High viral score (${viralScore}) suggests F2P could 5-10x player base`,
      projected_revenue_delta: "+40-80%",
      risk: "ARPPU uncertainty, requires cosmetic art pipeline"
    });
  }

  // Test pricing tiers
  if (typeof concept.price_point === "number") {
    const sentiment = marketData.price_sentiment;
    const currentTier = getPriceTier(concept.price_point);

    Object.keys(sentiment).forEach(tier => {
      if (tier !== currentTier && sentiment[tier].positive > sentiment[currentTier].positive + 10) {
        alternativeModels.push({
          model: `Price adjustment to ${tier}`,
          rationale: `${tier} has ${sentiment[tier].positive}% positive vs. current ${sentiment[currentTier].positive}%`,
          projected_revenue_delta: estimatePriceChangeDelta(concept, tier),
          risk: "Value perception vs. content ratio"
        });
      }
    });
  }

  // Test monetization add-ons
  if (!currentModel.includes("DLC") && concept.lifecycle_commitment.includes("2-3 year")) {
    alternativeModels.push({
      model: "Add expansion DLC model",
      rationale: "Long lifecycle supports premium content drops",
      projected_revenue_delta: "+15-25%",
      risk: "Community expectations for free updates"
    });
  }

  return {
    current_model: currentModel,
    current_model_score: scoreMonetizationModel(currentModel, wtpScore, viralScore),
    alternatives: alternativeModels.sort((a, b) =>
      parseFloat(b.projected_revenue_delta) - parseFloat(a.projected_revenue_delta)
    )
  };
}
```

### Phase 6: Composite Monetization Score & Ranking

**8. Calculate Total Monetization Score (0-100)**

```javascript
function calculateMonetizationScore(concept, wtpScore, viralScore, revenueProjection, roi) {
  const score = {
    willingness_to_pay: wtpScore.total * 0.25,          // 25% weight
    viral_potential: viralScore.total * 0.20,           // 20% weight
    revenue_potential: normalizeRevenue(revenueProjection.total_3yr) * 0.30, // 30% weight
    roi_efficiency: normalizeROI(roi.ROI_percentage) * 0.15,  // 15% weight
    time_to_profit: normalizePaybackPeriod(roi.payback_period_months) * 0.10 // 10% weight
  };

  return {
    total: Object.values(score).reduce((a, b) => a + b, 0),
    breakdown: score,
    tier: getMonetizationTier(Object.values(score).reduce((a, b) => a + b, 0))
  };
}

function normalizeRevenue(revenue) {
  // Normalize to 0-100 scale (assuming $50M = 100)
  return Math.min(100, (revenue / 50000000) * 100);
}

function normalizeROI(roiPercentage) {
  // Normalize to 0-100 scale (500% ROI = 100)
  return Math.min(100, (roiPercentage / 500) * 100);
}

function normalizePaybackPeriod(months) {
  // Shorter = better (6 months = 100, 36 months = 0)
  return Math.max(0, 100 - ((months - 6) / 30) * 100);
}

function getMonetizationTier(score) {
  if (score >= 90) return "S-TIER: Blockbuster potential";
  if (score >= 80) return "A-TIER: Strong monetization";
  if (score >= 70) return "B-TIER: Solid revenue opportunity";
  if (score >= 60) return "C-TIER: Moderate monetization";
  return "D-TIER: Weak monetization";
}
```

**9. Rank and Select Top 3**

```javascript
function rankConcepts(concepts, scores) {
  const ranked = concepts.map((concept, i) => ({
    concept: concept,
    scores: scores[i],
    monetization_score: scores[i].total,
    recommendation: generateRecommendation(concept, scores[i])
  })).sort((a, b) => b.monetization_score - a.monetization_score);

  return {
    top3: ranked.slice(0, 3),
    all_ranked: ranked,
    summary: generateRankingSummary(ranked)
  };
}

function generateRecommendation(concept, scores) {
  const strengths = [];
  const weaknesses = [];
  const actions = [];

  // Analyze strengths
  if (scores.breakdown.willingness_to_pay >= 20) strengths.push("Strong price/value fit");
  if (scores.breakdown.viral_potential >= 16) s