> ## 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.

# Competitor Review Mining

> Mine G2 competitor reviews for positioning opportunities using Mave Agent analysis

## Scenario

G2 has thousands of reviews about your competitors — what their users love, hate, and wish for. This is competitive intelligence gold. You pull competitor reviews from G2, aggregate the sentiment data, and send it to Mave Agent for analysis. The output identifies positioning opportunities: where competitors are weak and you can win.

**Flow:** G2 `GET /survey-responses` (competitor product) → Aggregate love/hate/recommend → Mavera `POST /mave/chat` → Positioning opportunities

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["G2 GET /survey-responses (competitor)"] --> B["Aggregate sentiment by theme"]
    B --> C["POST /api/v1/mave/chat"]
    C --> D["Competitive positioning report"]
```

## Code

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

  G2 = os.environ["G2_API_KEY"]
  MV = os.environ["MAVERA_API_KEY"]
  G2_BASE = "https://data.g2.com/api/v1"
  G2_H = {"Authorization": f"Token token={G2}", "Content-Type": "application/vnd.api+json"}
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  COMPETITORS = [
      {"name": "CompetitorA", "product_id": "competitor-a-product-id"},
      {"name": "CompetitorB", "product_id": "competitor-b-product-id"},
  ]

  all_intel = []
  for comp in COMPETITORS:
      reviews = []
      page = 1
      while len(reviews) < 100:
          r = requests.get(f"{G2_BASE}/survey-responses",
              headers=G2_H,
              params={
                  "filter[product_id]": comp["product_id"],
                  "page[size]": 50,
                  "page[number]": page,
              })
          if r.status_code == 429:
              time.sleep(1)
              continue
          r.raise_for_status()
          data = r.json().get("data", [])
          if not data:
              break
          reviews.extend(data)
          page += 1
          time.sleep(0.1)

      loves, hates, recs = [], [], []
      stars = []
      for rev in reviews:
          attrs = rev.get("attributes", {})
          stars.append(attrs.get("star_rating", 0))
          for key, val in attrs.get("comment_answers", {}).items():
              text = val if isinstance(val, str) else val.get("text", "")
              k = key.lower()
              if "love" in k or "best" in k:
                  loves.append(text[:200])
              elif "dislike" in k or "hate" in k:
                  hates.append(text[:200])
              elif "recommend" in k:
                  recs.append(text[:200])

      avg = sum(stars) / len(stars) if stars else 0
      all_intel.append({
          "name": comp["name"],
          "review_count": len(reviews),
          "avg_rating": round(avg, 1),
          "top_loves": loves[:10],
          "top_hates": hates[:10],
          "recommendations": recs[:5],
      })

  # Build analysis prompt
  intel_block = ""
  for ci in all_intel:
      intel_block += f"\n## {ci['name']} ({ci['review_count']} reviews, avg {ci['avg_rating']}/5)\n"
      intel_block += f"LOVE:\n" + "\n".join(f"- {l}" for l in ci["top_loves"][:5]) + "\n"
      intel_block += f"HATE:\n" + "\n".join(f"- {h}" for h in ci["top_hates"][:5]) + "\n"
      intel_block += f"RECOMMENDATIONS:\n" + "\n".join(f"- {r}" for r in ci["recommendations"][:3]) + "\n"

  analysis = requests.post("https://app.mavera.io/api/v1/mave/chat",
      headers=MV_H,
      json={"message": f"""Analyze these G2 competitor reviews and identify positioning opportunities for us.

  {intel_block}

  Produce:
  1. Each competitor's core strengths (where they're hard to beat)
  2. Each competitor's vulnerabilities (where their users are frustrated)
  3. Positioning opportunities (where we can win based on their weaknesses)
  4. Messaging angles (specific claims we can make that competitors can't)
  5. Feature gaps (what their users want that we could build/highlight)
  6. Risk areas (where competitors are improving — watch list)"""}).json()

  print("=== Competitive Intelligence from G2 ===")
  print(analysis.get("content", "")[:2000])
  ```

  ```javascript JavaScript theme={"dark"}
  const G2 = process.env.G2_API_KEY;
  const MV = process.env.MAVERA_API_KEY;
  const G2_BASE = "https://data.g2.com/api/v1";
  const G2_H = { Authorization: `Token token=${G2}`, "Content-Type": "application/vnd.api+json" };
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const COMPETITORS = [
    { name: "CompetitorA", productId: "competitor-a-product-id" },
    { name: "CompetitorB", productId: "competitor-b-product-id" },
  ];

  const allIntel = [];
  for (const comp of COMPETITORS) {
    const reviews = [];
    let page = 1;
    while (reviews.length < 100) {
      const res = await fetch(
        `${G2_BASE}/survey-responses?filter[product_id]=${comp.productId}&page[size]=50&page[number]=${page}`,
        { headers: G2_H }
      );
      if (res.status === 429) { await new Promise((r) => setTimeout(r, 1000)); continue; }
      if (!res.ok) throw new Error(`G2 ${res.status}`);
      const data = (await res.json()).data || [];
      if (!data.length) break;
      reviews.push(...data);
      page++;
      await new Promise((r) => setTimeout(r, 100));
    }

    const loves = [], hates = [], recs = [], stars = [];
    for (const rev of reviews) {
      const attrs = rev.attributes || {};
      stars.push(attrs.star_rating || 0);
      for (const [key, val] of Object.entries(attrs.comment_answers || {})) {
        const text = typeof val === "string" ? val : val?.text || "";
        const k = key.toLowerCase();
        if (k.includes("love") || k.includes("best")) loves.push(text.slice(0, 200));
        else if (k.includes("dislike") || k.includes("hate")) hates.push(text.slice(0, 200));
        else if (k.includes("recommend")) recs.push(text.slice(0, 200));
      }
    }

    allIntel.push({
      name: comp.name, count: reviews.length,
      avg: stars.length ? +(stars.reduce((s, v) => s + v, 0) / stars.length).toFixed(1) : 0,
      loves: loves.slice(0, 10), hates: hates.slice(0, 10), recs: recs.slice(0, 5),
    });
  }

  const intelBlock = allIntel.map((ci) =>
    `## ${ci.name} (${ci.count} reviews, avg ${ci.avg}/5)\nLOVE:\n${ci.loves.slice(0, 5).map((l) => `- ${l}`).join("\n")}\nHATE:\n${ci.hates.slice(0, 5).map((h) => `- ${h}`).join("\n")}\nRECS:\n${ci.recs.slice(0, 3).map((r) => `- ${r}`).join("\n")}`
  ).join("\n\n");

  const analysis = await fetch("https://app.mavera.io/api/v1/mave/chat", {
    method: "POST", headers: MV_H,
    body: JSON.stringify({
      message: `Analyze G2 competitor reviews:\n\n${intelBlock}\n\nProduce: 1) Strengths 2) Vulnerabilities 3) Positioning opportunities 4) Messaging angles 5) Feature gaps 6) Risk watch list`,
    }),
  }).then((r) => r.json());

  console.log("=== Competitive Intelligence ===");
  console.log((analysis.content || "").slice(0, 2000));
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
=== Competitive Intelligence from G2 ===

## CompetitorA (87 reviews, avg 4.1/5)
### Strengths (hard to beat)
- Exceptional onboarding experience (mentioned 34x)
- Strong Slack community for support

### Vulnerabilities (user frustration)
- "Reporting is stuck in 2019" — no custom dashboards (mentioned 19x)
- "API is an afterthought" — limited endpoints, poor docs (12x)
- No SSO on mid-tier plans (8x)

## Positioning Opportunities
1. **Lead with reporting**: CompetitorA's #1 complaint is our strength. Claim: "Custom dashboards in 5 minutes, not 5 sprints."
2. **Developer-first messaging**: Their API frustration creates an opening. Claim: "Full REST API with 200+ endpoints. Documentation that engineers actually like."
3. **Security as differentiator**: SSO gap at mid-tier is a compliance dealbreaker. Claim: "SSO included on every plan."

## Risk Watch
- CompetitorA recently hired a Head of API — expect improvements in 6-12 months.
```

## Error Handling

<AccordionGroup>
  <Accordion title="Competitor product IDs">G2 product IDs aren't always obvious. Find them via `GET /products?filter[name]=CompetitorName` or from the G2 product page URL slug.</Accordion>
  <Accordion title="Review access permissions">You can only access reviews for products in your G2 category. Cross-category competitor reviews require a G2 Market Intelligence subscription.</Accordion>
</AccordionGroup>
