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

# Research Report → Focus Group Questions

> Extract key findings and controversial claims from industry research reports, auto-generate Focus Group questions that test whether target personas agree with the conclusions — turning static research into validated, audience-specific intelligence

## Scenario

Take industry research reports and use Claude to extract key findings, controversial claims, and actionable insights. Then auto-generate Focus Group questions that test whether your target personas would agree with or act on the report's conclusions — turning static research into validated, audience-specific intelligence.

**Flow:** Research report → Anthropic `POST /v1/messages` (extract findings) → Mavera `POST /personas` → Mavera `POST /focus-groups` (auto-generated questions) → Validated research

## Code

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

  MV = os.environ["MAVERA_API_KEY"]
  MV_BASE = "https://app.mavera.io/api/v1"
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
  client = anthropic.Anthropic()

  with open("gartner_martech_2025.txt") as f:
      report_text = f.read()
  print(f"Report loaded: {len(report_text):,} chars (~{len(report_text)//4:,} tokens)")

  # 1. Claude extracts findings and generates questions
  extraction = client.messages.create(
      model="claude-opus-4-6-20250725",
      max_tokens=4096,
      input=[{
          "role": "user",
          "content": "Research analyst. Read this report and:\n\n"
              "A) Extract TOP 8 FINDINGS ranked by how controversial or actionable they are.\n"
              "Per finding: claim (1 sentence), evidence cited, confidence, counterargument.\n\n"
              "B) For each finding, generate 2 FOCUS GROUP QUESTIONS that test practitioner agreement.\n"
              "Questions should be specific, neutral, and grounded in experience.\n\n"
              "Return JSON: [{finding, evidence, confidence, counterargument, questions: [q1, q2]}]\n\n"
              f"REPORT:\n{report_text}"
      }],
  )
  raw = extraction.content[0].text
  print(f"Extraction — {extraction.usage.input_tokens:,} input tokens")

  try:
      findings = json.loads(raw[raw.index("["):raw.rindex("]") + 1])
  except (ValueError, json.JSONDecodeError):
      findings = [{"finding": raw[:500], "questions": ["Does this match your experience?"]}]
  print(f"{len(findings)} findings, {sum(len(f.get('questions',[])) for f in findings)} questions")

  # 2. Create target personas
  TARGET_PERSONAS = [
      {"name": "VP Marketing, Enterprise SaaS", "desc": "15 years B2B marketing. $5M budget. Team of 20. Skeptical of vendor claims. Data-driven."},
      {"name": "Marketing Ops Manager", "desc": "8 years experience. Manages tech stack day-to-day. Cares about integration and automation."},
      {"name": "CMO, Growth-Stage Startup", "desc": "Series B. $1.5M budget. 6-person team. Needs efficiency over features."},
  ]
  persona_ids = []
  for tp in TARGET_PERSONAS:
      p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
          "name": tp["name"], "description": tp["desc"],
      }).json()
      persona_ids.append(p["id"])
      time.sleep(0.3)

  # 3. Collect questions and run Focus Group
  all_questions = [q for f in findings[:6] for q in f.get("questions", [])[:2]]
  fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
      "name": "Research Validation: Gartner MarTech 2025",
      "persona_ids": persona_ids,
      "questions": all_questions[:10],
      "responses_per_persona": 2,
  }).json()

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

  # 4. Map responses to findings
  print(f"\n{'='*60}\nRESEARCH VALIDATION RESULTS\n{'='*60}")
  for i, f in enumerate(findings[:6]):
      print(f"\nFinding {i+1}: {f.get('finding','')[:120]}")
      print(f"Confidence: {f.get('confidence','N/A')}")
      for resp in data.get("responses", []):
          if resp.get("question","") in f.get("questions", []):
              idx = persona_ids.index(resp["persona_id"]) if resp.get("persona_id") in persona_ids else -1
              name = TARGET_PERSONAS[idx]["name"] if 0 <= idx < len(TARGET_PERSONAS) else "Unknown"
              print(f"  [{name}]: {resp.get('answer','')[:200]}")
  ```

  ```javascript JavaScript theme={"dark"}
  import Anthropic from "@anthropic-ai/sdk";
  import fs from "fs";

  const MV = process.env.MAVERA_API_KEY;
  const MV_BASE = "https://app.mavera.io/api/v1";
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
  const client = new Anthropic();

  const reportText = fs.readFileSync("gartner_martech_2025.txt", "utf-8");

  const extraction = await client.messages.create({
    model: "claude-opus-4-6-20250725", max_tokens: 4096,
    input: [{ role: "user",
      content: `Research analyst. Extract TOP 8 FINDINGS ranked by controversy.\n`
        + `Per finding: claim, evidence, confidence, counterargument.\n`
        + `Generate 2 focus group questions per finding (specific, neutral, experience-based).\n`
        + `Return JSON: [{finding, evidence, confidence, counterargument, questions: [q1, q2]}]\n\nREPORT:\n${reportText}` }],
  });
  let findings;
  try { findings = JSON.parse(extraction.content[0].text.slice(
    extraction.content[0].text.indexOf("["), extraction.content[0].text.lastIndexOf("]") + 1)); }
  catch { findings = [{ finding: "Parse error", questions: ["Does this match your experience?"] }]; }

  const TARGET_PERSONAS = [
    { name: "VP Marketing, Enterprise SaaS", desc: "$5M budget. Skeptical of vendor claims." },
    { name: "Marketing Ops Manager", desc: "Manages stack daily. Integration and automation." },
    { name: "CMO, Growth-Stage Startup", desc: "Series B. $1.5M budget. Needs efficiency." },
  ];
  const personaIds = [];
  for (const tp of TARGET_PERSONAS) {
    const p = await fetch(`${MV_BASE}/personas`, { method: "POST", headers: MV_H,
      body: JSON.stringify({ name: tp.name, description: tp.desc }) }).then(r => r.json());
    personaIds.push(p.id);
    await new Promise(r => setTimeout(r, 300));
  }

  const allQuestions = findings.slice(0, 6).flatMap(f => (f.questions || []).slice(0, 2));
  const fg = await fetch(`${MV_BASE}/focus-groups`, { method: "POST", headers: MV_H,
    body: JSON.stringify({ name: "Research Validation", persona_ids: personaIds,
      questions: allQuestions.slice(0, 10), responses_per_persona: 2 }) }).then(r => r.json());

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

  console.log(`\nRESEARCH VALIDATION RESULTS`);
  for (let i = 0; i < Math.min(6, findings.length); i++) {
    const f = findings[i];
    console.log(`\nFinding ${i + 1}: ${(f.finding || "").slice(0, 120)}`);
    for (const resp of data.responses || [])
      if ((f.questions || []).includes(resp.question)) {
        const idx = personaIds.indexOf(resp.persona_id);
        console.log(`  [${idx >= 0 ? TARGET_PERSONAS[idx].name : "Unknown"}]: ${(resp.answer || "").slice(0, 200)}`);
      }
  }
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
Report loaded: 142,830 chars (~35,707 tokens)
8 findings, 16 questions — Focus group: 3 personas

RESEARCH VALIDATION RESULTS
============================================================
Finding 1: "By 2027, 75% of enterprise marketers will consolidate
martech from 10+ tools to 3-5 platforms." (Confidence: High)

  [VP Marketing]: Still at 8 tools after 2 years of consolidating.
  Every "platform" has gaps we fill with point solutions.

  [Marketing Ops]: I'm the one migrating 3 years of Marketo workflows.
  The timeline is aggressive.

  [CMO, Startup]: Started with 3, already at 7. Need speed, not consolidation.

Finding 2: "AI-generated content = 30% of marketing output by 2026."
  [VP Marketing]: 20% for first drafts, 0% published-as-is. Depends
  on what "AI-generated" means — if AI-assisted, we're past it.
```

## Error Handling

<AccordionGroup>
  <Accordion title="Long reports">A 150-page report is \~35K tokens — well within limits. For 500+ page reports, use Claude Opus 4.6 with its 1M window. Analysis quality improves with full context versus chunked processing.</Accordion>
  <Accordion title="Question quality">If generated questions feel generic, add constraints: "Questions must reference specific data points" and "Start with 'In your experience...' or 'At your organization...'"</Accordion>
  <Accordion title="Response mapping">The response-to-finding mapping relies on exact question string matching. If Mavera modifies question text, fall back to index-based mapping using question order.</Accordion>
</AccordionGroup>
