> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mavera.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Feature Adoption → Messaging Priorities

> Pull feature usage metrics from Mixpanel, identify underused features, run awareness focus groups, and generate feature adoption campaigns

### Scenario

Your product has 10 features, but only 3 are widely adopted. You pull feature usage metrics from Mixpanel, identify underused features with high retention correlation, then run a Focus Group asking "Are you aware of {feature}?" (dichotomous yes/no + open-ended follow-up) and generate feature awareness campaigns for the gaps.

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A[Mixpanel event counts per feature] --> B[Rank by adoption rate + retention correlation] --> C["POST /api/v1/focus-groups"] --> D["POST /api/v1/generations (campaigns)"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests, time, json

  MP_SA = os.environ["MIXPANEL_SERVICE_ACCOUNT"]
  MP_SECRET = os.environ["MIXPANEL_SECRET"]
  MP_PROJECT = os.environ["MIXPANEL_PROJECT_ID"]
  MV = os.environ["MAVERA_API_KEY"]
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  FEATURES = {
      "Dashboard View": "Main dashboard with analytics overview",
      "Report Create": "Custom report builder",
      "Alert Set": "Automated alerts and notifications",
      "API Call": "Programmatic API access",
      "Export Data": "CSV/Excel data export",
      "Team Invite": "Add team members to workspace",
      "Integration Connect": "Connect third-party tools",
      "Template Use": "Pre-built report templates",
      "Scheduled Report": "Automated recurring reports",
      "Custom Widget": "Build custom dashboard widgets",
  }

  r = requests.post(
      "https://mixpanel.com/api/query/insights",
      auth=(MP_SA, MP_SECRET),
      json={
          "project_id": MP_PROJECT,
          "bookmark_id": None,
          "params": {
              "type": "unique",
              "events": [{"event": name} for name in FEATURES.keys()],
              "from_date": "2026-02-15",
              "to_date": "2026-03-17",
          },
      },
  )
  if r.status_code == 429:
      time.sleep(60)
  r.raise_for_status()
  insights = r.json()

  total_users_r = requests.post(
      "https://mixpanel.com/api/query/insights",
      auth=(MP_SA, MP_SECRET),
      json={
          "project_id": MP_PROJECT,
          "params": {"type": "unique", "events": [{"event": "Login"}],
                     "from_date": "2026-02-15", "to_date": "2026-03-17"},
      },
  )
  total_users_data = total_users_r.json()
  total_users = 5000

  feature_adoption = []
  series = insights.get("series", {})
  for feature_name, desc in FEATURES.items():
      values = series.get(feature_name, {})
      unique_users = sum(values.values()) if isinstance(values, dict) else 0
      adoption_rate = unique_users / max(total_users, 1)
      feature_adoption.append({
          "feature": feature_name,
          "description": desc,
          "unique_users": unique_users,
          "adoption_rate": adoption_rate,
      })

  feature_adoption.sort(key=lambda f: f["adoption_rate"])

  underused = [f for f in feature_adoption if f["adoption_rate"] < 0.3]
  well_adopted = [f for f in feature_adoption if f["adoption_rate"] >= 0.5]

  adoption_table = "\n".join(
      f"- {f['feature']}: {f['unique_users']} users ({f['adoption_rate']:.0%} adoption) — {f['description']}"
      for f in feature_adoption
  )

  PERSONA_IDS = os.environ.get("FEATURE_PERSONA_IDS", "").split(",")
  if not PERSONA_IDS[0]:
      for name, desc in [
          ("Active Free User", "Uses the product daily on a free plan. Hasn't upgraded because they don't know what they're missing."),
          ("New Pro User", "Recently upgraded. Using 2-3 features but hasn't explored the full platform."),
          ("Power User Champion", "Uses most features. Internal advocate. Wants to get more from the tool."),
      ]:
          p = requests.post(f"{MB}/personas", headers=MH, json={"name": name, "description": desc}).json()
          PERSONA_IDS.append(p["id"])
          time.sleep(0.3)

  underused_list = ", ".join(f["feature"] for f in underused[:5])

  fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
      "name": "Feature Awareness & Adoption",
      "persona_ids": [pid for pid in PERSONA_IDS if pid],
      "questions": [
          f"Are you aware of these features: {underused_list}? For each, answer Yes or No, then explain why you do or don't use it.",
          "If you discovered a feature that could save you 2 hours per week, how would you want to learn about it? (in-app tooltip, email, video tutorial, peer recommendation, or other?)",
          f"Rank these underused features by how useful they WOULD be if you knew about them: {underused_list}. Explain your #1.",
          "What's the biggest gap in this product — a feature you wish existed?",
      ],
      "context": f"""Feature adoption data for our product (last 30 days):

  {adoption_table}

  Well-adopted (>50%): {', '.join(f['feature'] for f in well_adopted)}
  Underused (<30%): {underused_list}

  Total active users: ~{total_users}""",
      "responses_per_persona": 2,
  }).json()

  for _ in range(24):
      time.sleep(5)
      data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
      if data.get("status") == "completed":
          break

  print("--- Focus Group Results ---\n")
  for resp in data.get("responses", []):
      print(f"[{resp.get('persona_id','?')}] {resp.get('question','')[:70]}")
      print(f"  → {resp.get('answer','')[:250]}\n")

  print("\n--- Generating Feature Campaigns ---\n")
  for feature in underused[:3]:
      gen = requests.post(f"{MB}/generations", headers=MH, json={
          "prompt": (
              f"Create a feature awareness campaign for '{feature['feature']}' ({feature['description']}). "
              f"Current adoption: {feature['adoption_rate']:.0%} of users. "
              f"Generate:\n"
              f"1. In-app banner copy (max 20 words + CTA)\n"
              f"2. Email subject line + 50-word body\n"
              f"3. Tooltip text (max 15 words)\n"
              f"4. 30-second video script outline\n"
              f"Focus on the user benefit, not the feature name."
          ),
      }).json()

      print(f"Feature: {feature['feature']} ({feature['adoption_rate']:.0%} adoption)")
      print(gen.get("output", gen.get("content", ""))[:500])
      print()
  ```

  ```javascript JavaScript theme={"dark"}
  const MP_SA = process.env.MIXPANEL_SERVICE_ACCOUNT;
  const MP_SECRET = process.env.MIXPANEL_SECRET;
  const MP_PROJECT = process.env.MIXPANEL_PROJECT_ID;
  const MV = process.env.MAVERA_API_KEY;
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
  const mpAuth = "Basic " + Buffer.from(`${MP_SA}:${MP_SECRET}`).toString("base64");

  const FEATURES = {
    "Dashboard View": "Main dashboard with analytics overview",
    "Report Create": "Custom report builder",
    "Alert Set": "Automated alerts and notifications",
    "API Call": "Programmatic API access",
    "Export Data": "CSV/Excel data export",
    "Team Invite": "Add team members",
    "Integration Connect": "Connect third-party tools",
    "Template Use": "Pre-built report templates",
    "Scheduled Report": "Automated recurring reports",
    "Custom Widget": "Custom dashboard widgets",
  };

  const insights = await fetch("https://mixpanel.com/api/query/insights", {
    method: "POST",
    headers: { Authorization: mpAuth, "Content-Type": "application/json" },
    body: JSON.stringify({
      project_id: MP_PROJECT,
      params: {
        type: "unique",
        events: Object.keys(FEATURES).map((event) => ({ event })),
        from_date: "2026-02-15", to_date: "2026-03-17",
      },
    }),
  }).then((r) => r.json());

  const totalUsers = 5000;
  const series = insights.series || {};

  const featureAdoption = Object.entries(FEATURES).map(([name, desc]) => {
    const vals = series[name] || {};
    const uniqueUsers = Object.values(vals).reduce((s, v) => s + v, 0);
    return { feature: name, description: desc, uniqueUsers, adoptionRate: uniqueUsers / totalUsers };
  }).sort((a, b) => a.adoptionRate - b.adoptionRate);

  const underused = featureAdoption.filter((f) => f.adoptionRate < 0.3);
  const adoptionTable = featureAdoption.map((f) =>
    `- ${f.feature}: ${f.uniqueUsers} users (${(f.adoptionRate * 100).toFixed(0)}%) — ${f.description}`
  ).join("\n");

  const personaIds = [];
  for (const [name, desc] of [
    ["Active Free User", "Daily free user. Doesn't know what they're missing."],
    ["New Pro User", "Recently upgraded. Using 2-3 features."],
    ["Power User Champion", "Uses most features. Internal advocate."],
  ]) {
    const p = await fetch(`${MB}/personas`, { method: "POST", headers: MH,
      body: JSON.stringify({ name, description: desc }) }).then((r) => r.json());
    personaIds.push(p.id);
    await new Promise((r) => setTimeout(r, 300));
  }

  const underusedList = underused.slice(0, 5).map((f) => f.feature).join(", ");

  const fg = await fetch(`${MB}/focus-groups`, { method: "POST", headers: MH,
    body: JSON.stringify({
      name: "Feature Awareness",
      persona_ids: personaIds,
      questions: [
        `Are you aware of: ${underusedList}? Yes/No for each, then explain.`,
        "How would you want to learn about a feature saving 2hr/week?",
        `Rank by usefulness: ${underusedList}. Explain #1.`,
        "What feature gap exists in this product?",
      ],
      context: `Feature adoption (30d):\n${adoptionTable}\n\nTotal: ~${totalUsers}`,
      responses_per_persona: 2,
    }),
  }).then((r) => r.json());

  let data;
  for (let i = 0; i < 24; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    data = await fetch(`${MB}/focus-groups/${fg.id}`, { headers: MH }).then((r) => r.json());
    if (data.status === "completed") break;
  }

  console.log("--- Focus Group Results ---\n");
  for (const resp of data.responses || []) {
    console.log(`[${resp.persona_id}] ${(resp.question || "").slice(0, 70)}`);
    console.log(`  → ${(resp.answer || "").slice(0, 250)}\n`);
  }

  console.log("\n--- Feature Campaigns ---\n");
  for (const feature of underused.slice(0, 3)) {
    const gen = await fetch(`${MB}/generations`, { method: "POST", headers: MH,
      body: JSON.stringify({
        prompt: `Feature awareness campaign for '${feature.feature}' (${feature.description}). Adoption: ${(feature.adoptionRate * 100).toFixed(0)}%. Generate: 1) In-app banner 2) Email subject+body 3) Tooltip 4) 30s video script.`,
      }),
    }).then((r) => r.json());
    console.log(`${feature.feature} (${(feature.adoptionRate * 100).toFixed(0)}% adoption)`);
    console.log((gen.output || gen.content || "").slice(0, 500));
    console.log();
  }
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
--- Focus Group Results ---

[Active Free User] Are you aware of: Alert Set, API Call, Custom Widget?
  → Alert Set: No — I didn't know I could get notified. I check the
    dashboard manually every morning. If I could get a Slack ping when
    a metric drops, that changes my workflow entirely.
    API Call: No — I'm not a developer.
    Custom Widget: No — what does it do?

[New Pro User] Rank by usefulness
  → #1: Scheduled Report. I build the same report every Monday. If I
    could automate it, I'd save 45 minutes/week and look more organized
    to my manager. That alone justifies the Pro upgrade.

--- Feature Campaigns ---

Scheduled Report (12% adoption)
1. Banner: "Stop rebuilding Monday's report. Automate it in 30 seconds." [Set Up →]
2. Email: Subject: "You rebuilt this report 4 times last month"
   Body: We noticed you create similar reports weekly. Scheduled Reports
   delivers them to your inbox automatically — same filters, same format,
   zero effort. Set it up in 30 seconds.
3. Tooltip: "Run this report automatically every week"
4. Video: Open on frustrated user rebuilding report → show 3-click
   setup → reveal report landing in inbox → "45 minutes back, every week."
```

### Error Handling

<AccordionGroup>
  <Accordion title="Insights API query format">The Insights API requires specific `params` structure with `type` (unique, general, average), `events`, and date range. Test queries in Mixpanel's Insights UI first, then export the API call from the UI's "API" button.</Accordion>
  <Accordion title="Feature event naming">Features must correspond to tracked Mixpanel events. If your events are named differently (e.g. `report.created` instead of `Report Create`), update the `FEATURES` dict to match your event names exactly.</Accordion>
  <Accordion title="Focus Group + Generate sequencing">This job chains two Mavera calls — Focus Group then Generate. Budget 2–4 minutes total. The Focus Group must complete before generating campaigns, since the results inform messaging strategy.</Accordion>
</AccordionGroup>

***

## What's Next

<CardGroup cols={2}>
  <Card title="Mixpanel Integration" icon="chart-bar" href="/integrations/mixpanel">
    Back to Mixpanel integration overview
  </Card>

  <Card title="Event-Based Persona Enrichment" icon="bolt" href="/integrations/mixpanel/event-persona-enrichment">
    Enrich personas with raw event patterns
  </Card>

  <Card title="Focus Groups API" icon="comments" href="/api-reference/focus-groups">
    Full reference for POST /api/v1/focus-groups
  </Card>

  <Card title="Generate API" icon="wand-magic-sparkles" href="/api-reference/generations">
    Full reference for POST /api/v1/generations
  </Card>
</CardGroup>
