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

# Positioning Workshop

> Create 5 ICP personas, test 3 positioning statements with Ranking and Semantic Differential questions, and validate positioning with persona-weighted scoring

## Mavera Surfaces Used

| Surface                                          | Role                                                                             |
| ------------------------------------------------ | -------------------------------------------------------------------------------- |
| **Personas** (`POST /personas`, `GET /personas`) | Create and retrieve 5 ICP-specific personas                                      |
| **Focus Groups** (`POST /focus-groups`)          | Run positioning test with Ranking + Semantic Differential + Open-Ended questions |
| **Chat + `response_format`**                     | Synthesize focus group results into a final positioning recommendation           |

<Info>
  Traditional positioning workshops take days and cost \$10K+. This playbook produces persona-validated positioning in under an hour with no external tooling — just Mavera's Personas and Focus Groups APIs.
</Info>

***

## What Value Does Mavera Add?

| Value                 | How                                                                                                                     |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **Insurance**         | Test positioning with 5 distinct ICP segments before committing. Catch blind spots that internal teams miss.            |
| **Opening new doors** | Run positioning sprints weekly during product pivots — cost and speed make rapid iteration practical.                   |
| **Saving time**       | A full positioning workshop (persona creation → focus group → recommendation) runs in \~30 minutes instead of 2–3 days. |

***

## When to Use This

* You're defining or refreshing your positioning statement and want audience validation before committing.
* You have 2–5 candidate positioning statements and need to pick a winner — fast.
* You want to test how different ICP segments interpret the same positioning.
* You're preparing for a rebrand, product launch, or funding round and need data-backed positioning.

***

## What You Need

| Requirement                        | Details                                                                                                                      |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **Mavera API key**                 | Starts with `mvra_live_`. Get one at [Developer Settings](https://app.mavera.io/settings/developer).                         |
| **Workspace ID**                   | From your dashboard URL (`ws_...`).                                                                                          |
| **3 positioning statements**       | Candidate statements to test (follow the template: *For \[audience], \[product] is the \[category] that \[differentiator]*). |
| **ICP definition**                 | Enough detail to create 5 representative personas (title, industry, pain points, budget authority).                          |
| **Credits**                        | \~200–500 total. See [Credits Estimate](#credits-estimate).                                                                  |
| **Python 3.8+** or **Node.js 18+** | `requests` / `openai` for Python; native `fetch` for Node.                                                                   |

```
MAVERA_API_KEY=mvra_live_your_key_here
MAVERA_WORKSPACE_ID=ws_your_workspace_id
```

***

## The Workshop Framework

```mermaid theme={"dark"}
flowchart LR
    A["Create 5 ICP Personas"] --> B["Run Focus Group"]
    B --> C["Synthesize Recommendation"]
```

### Question Types

| Question                                                            | Type                      | What It Measures                             |
| ------------------------------------------------------------------- | ------------------------- | -------------------------------------------- |
| "Rank these 3 positioning statements from most to least compelling" | **Ranking**               | Overall preference order across all personas |
| "Rate Statement A on: Generic ←→ Differentiated"                    | **Semantic Differential** | Perception on a bipolar scale                |
| "Rate Statement A on: Confusing ←→ Clear"                           | **Semantic Differential** | Comprehension                                |
| "Rate Statement A on: Forgettable ←→ Memorable"                     | **Semantic Differential** | Stickiness                                   |
| "What would make the top-ranked statement stronger?"                | **Open-Ended**            | Qualitative improvement suggestions          |

***

## The Flow

<Steps>
  <Step title="Define your 3 positioning statements">
    Use the standard template: *For \[audience], \[product] is the \[category] that \[differentiator].* Having exactly 3 keeps the ranking question manageable for respondents.
  </Step>

  <Step title="Create 5 ICP personas">
    Build personas representing distinct segments of your ideal customer profile. Vary by seniority, function, company size, and pain point so each perspective is unique.
  </Step>

  <Step title="Run the Focus Group">
    30 respondents across the 5 personas (6 per persona). Questions: 1 Ranking, 3 Semantic Differentials, 1 Open-Ended.
  </Step>

  <Step title="Poll for completion">
    Focus Groups with 30 respondents and 5 questions typically complete in 3-8 minutes.
  </Step>

  <Step title="Analyze results">
    Extract ranking distribution, semantic differential averages, and open-ended themes.
  </Step>

  <Step title="Synthesize recommendation">
    Use Chat with structured output to produce a final positioning recommendation with segment-level detail.
  </Step>
</Steps>

***

## Code: Full Positioning Workshop

### Setup and Positioning Statements

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

  MAVERA_API_KEY = os.environ["MAVERA_API_KEY"]
  WORKSPACE_ID = os.environ["MAVERA_WORKSPACE_ID"]
  BASE = "https://app.mavera.io/api/v1"
  HEADERS = {
      "Authorization": f"Bearer {MAVERA_API_KEY}",
      "Content-Type": "application/json",
  }
  mavera = OpenAI(api_key=MAVERA_API_KEY, base_url=BASE)

  POSITIONING_STATEMENTS = [
      {
          "label": "A",
          "statement": (
              "For growth-stage B2B companies, Acme is the market intelligence platform "
              "that replaces guesswork with persona-validated data — so you ship messaging "
              "that resonates on the first try."
          ),
      },
      {
          "label": "B",
          "statement": (
              "For marketing leaders, Acme is the AI research assistant that simulates "
              "your target audience — giving you focus group insights in minutes, "
              "not months."
          ),
      },
      {
          "label": "C",
          "statement": (
              "For product marketers, Acme is the positioning engine that tests your "
              "messaging against synthetic buyers — so every campaign launches with "
              "confidence backed by data."
          ),
      },
  ]

  ICP_PERSONAS = [
      {
          "name": "VP of Marketing — Growth-Stage SaaS",
          "description": (
              "VP Marketing at a Series B SaaS company (50-200 employees). "
              "Owns positioning, messaging, and demand gen. Budget: $500K-$2M/year. "
              "Pain: can't afford agency research but needs data-backed messaging. "
              "Evaluates tools on speed-to-insight and ROI."
          ),
      },
      {
          "name": "Head of Product Marketing — Enterprise",
          "description": (
              "Head of PMM at a $50M+ ARR enterprise software company. "
              "Manages positioning for multiple product lines. "
              "Pain: positioning workshops take weeks and results are subjective. "
              "Needs quantitative validation for executive buy-in."
          ),
      },
      {
          "name": "CMO — Mid-Market B2B",
          "description": (
              "CMO at a mid-market B2B company (200-1000 employees). "
              "Reports to CEO, presents to board. Budget: $2M-$10M/year. "
              "Pain: marketing is perceived as a cost center, needs measurable impact. "
              "Values tools that produce board-ready outputs."
          ),
      },
      {
          "name": "Content Marketing Manager",
          "description": (
              "Content marketing manager at a B2B startup. "
              "Produces blog posts, whitepapers, and social content daily. "
              "Pain: writes copy without knowing if it resonates with the buyer. "
              "Wants fast feedback loops, not quarterly brand studies."
          ),
      },
      {
          "name": "Founder / CEO — Early Stage",
          "description": (
              "Technical founder at a pre-Series A startup (5-20 employees). "
              "Wears the marketing hat. Budget: $50K-$200K/year total. "
              "Pain: can't hire a brand strategist yet but needs sharp positioning "
              "for investor decks and landing pages. Values simplicity and speed."
          ),
      },
  ]
  ```

  ```javascript JavaScript theme={"dark"}
  import OpenAI from "openai";

  const MAVERA_API_KEY = process.env.MAVERA_API_KEY;
  const WORKSPACE_ID = process.env.MAVERA_WORKSPACE_ID;
  const BASE = "https://app.mavera.io/api/v1";
  const HEADERS = {
    Authorization: `Bearer ${MAVERA_API_KEY}`,
    "Content-Type": "application/json",
  };
  const mavera = new OpenAI({ apiKey: MAVERA_API_KEY, baseURL: BASE });

  const POSITIONING_STATEMENTS = [
    {
      label: "A",
      statement:
        "For growth-stage B2B companies, Acme is the market intelligence platform " +
        "that replaces guesswork with persona-validated data — so you ship messaging " +
        "that resonates on the first try.",
    },
    {
      label: "B",
      statement:
        "For marketing leaders, Acme is the AI research assistant that simulates " +
        "your target audience — giving you focus group insights in minutes, not months.",
    },
    {
      label: "C",
      statement:
        "For product marketers, Acme is the positioning engine that tests your " +
        "messaging against synthetic buyers — so every campaign launches with " +
        "confidence backed by data.",
    },
  ];

  const ICP_PERSONAS = [
    {
      name: "VP of Marketing — Growth-Stage SaaS",
      description:
        "VP Marketing at a Series B SaaS company (50-200 employees). " +
        "Owns positioning, messaging, and demand gen. Budget: $500K-$2M/year. " +
        "Pain: can't afford agency research but needs data-backed messaging.",
    },
    {
      name: "Head of Product Marketing — Enterprise",
      description:
        "Head of PMM at a $50M+ ARR enterprise software company. " +
        "Manages positioning for multiple product lines. " +
        "Pain: positioning workshops take weeks and results are subjective.",
    },
    {
      name: "CMO — Mid-Market B2B",
      description:
        "CMO at a mid-market B2B company (200-1000 employees). " +
        "Reports to CEO, presents to board. Budget: $2M-$10M/year. " +
        "Values tools that produce board-ready outputs.",
    },
    {
      name: "Content Marketing Manager",
      description:
        "Content marketing manager at a B2B startup. " +
        "Produces blog posts, whitepapers, and social content daily. " +
        "Wants fast feedback loops, not quarterly brand studies.",
    },
    {
      name: "Founder / CEO — Early Stage",
      description:
        "Technical founder at a pre-Series A startup (5-20 employees). " +
        "Wears the marketing hat. Budget: $50K-$200K/year total. " +
        "Values simplicity and speed.",
    },
  ];
  ```
</CodeGroup>

***

### Stage 1 — Create Personas

<CodeGroup>
  ```python Python theme={"dark"}
  def create_personas() -> list[str]:
      """Create 5 ICP personas and return their IDs."""
      persona_ids = []

      for persona in ICP_PERSONAS:
          resp = requests.post(
              f"{BASE}/personas",
              headers=HEADERS,
              json={
                  "name": persona["name"],
                  "description": persona["description"],
                  "workspace_id": WORKSPACE_ID,
              },
          ).json()

          if "error" in resp:
              raise Exception(f"Failed to create persona '{persona['name']}': {resp['error']['message']}")

          persona_ids.append(resp["id"])
          print(f"✓ Created persona: {persona['name']} ({resp['id']})")

      return persona_ids
  ```

  ```javascript JavaScript theme={"dark"}
  async function createPersonas() {
    const personaIds = [];

    for (const persona of ICP_PERSONAS) {
      const resp = await fetch(`${BASE}/personas`, {
        method: "POST",
        headers: HEADERS,
        body: JSON.stringify({
          name: persona.name,
          description: persona.description,
          workspace_id: WORKSPACE_ID,
        }),
      }).then((r) => r.json());

      if (resp.error)
        throw new Error(`Failed to create persona '${persona.name}': ${resp.error.message}`);

      personaIds.push(resp.id);
      console.log(`✓ Created persona: ${persona.name} (${resp.id})`);
    }

    return personaIds;
  }
  ```
</CodeGroup>

<Tip>
  If you already have personas from a previous session, skip creation and pass their IDs directly. Use `GET /personas` to list existing ones.
</Tip>

***

### Stage 2 — Run the Focus Group

The focus group uses 5 questions: 1 Ranking, 3 Semantic Differentials (one per statement), and 1 Open-Ended.

<CodeGroup>
  ```python Python theme={"dark"}
  def build_statements_block() -> str:
      """Format positioning statements for inclusion in questions."""
      return "\n".join(
          f"Statement {s['label']}: \"{s['statement']}\""
          for s in POSITIONING_STATEMENTS
      )


  def run_positioning_focus_group(persona_ids: list[str]) -> dict:
      """Run the positioning workshop focus group."""
      statements_block = build_statements_block()

      payload = {
          "name": "Positioning Workshop — 3 Statements × 5 Personas",
          "sample_size": 30,
          "persona_ids": persona_ids,
          "workspace_id": WORKSPACE_ID,
          "questions": [
              {
                  "question": (
                      "Read these 3 positioning statements carefully, then rank them "
                      "from most compelling (1st) to least compelling (3rd).\n\n"
                      f"{statements_block}"
                  ),
                  "type": "RANKING",
                  "options": [
                      f"Statement {s['label']}" for s in POSITIONING_STATEMENTS
                  ],
                  "order": 1,
              },
              {
                  "question": (
                      f"Rate Statement A on this scale:\n\n"
                      f"\"{POSITIONING_STATEMENTS[0]['statement']}\""
                  ),
                  "type": "SEMANTIC_DIFFERENTIAL",
                  "left_anchor": "Generic / could be anyone",
                  "right_anchor": "Differentiated / clearly unique",
                  "scale": 7,
                  "order": 2,
              },
              {
                  "question": (
                      f"Rate Statement B on this scale:\n\n"
                      f"\"{POSITIONING_STATEMENTS[1]['statement']}\""
                  ),
                  "type": "SEMANTIC_DIFFERENTIAL",
                  "left_anchor": "Confusing / hard to understand",
                  "right_anchor": "Clear / instantly understood",
                  "scale": 7,
                  "order": 3,
              },
              {
                  "question": (
                      f"Rate Statement C on this scale:\n\n"
                      f"\"{POSITIONING_STATEMENTS[2]['statement']}\""
                  ),
                  "type": "SEMANTIC_DIFFERENTIAL",
                  "left_anchor": "Forgettable / bland",
                  "right_anchor": "Memorable / would stick with me",
                  "scale": 7,
                  "order": 4,
              },
              {
                  "question": (
                      "You ranked the statements above. For the one you ranked #1:\n"
                      "- What specifically makes it compelling?\n"
                      "- What would make it even stronger?\n"
                      "- Is there anything misleading or unclear?"
                  ),
                  "type": "OPEN_ENDED",
                  "order": 5,
              },
          ],
      }

      resp = requests.post(
          f"{BASE}/focus-groups",
          headers=HEADERS,
          json=payload,
      ).json()

      if "error" in resp:
          raise Exception(resp["error"]["message"])

      print(f"✓ Focus group created: {resp['id']}")
      print(f"  Sample size: {payload['sample_size']}")
      print(f"  Personas: {len(persona_ids)}")
      print(f"  Questions: {len(payload['questions'])}")
      return resp


  def poll_focus_group(fg_id: str, timeout_min: int = 15) -> dict:
      """Poll until the focus group completes."""
      start = time.time()
      for attempt in range(timeout_min * 6):
          resp = requests.get(
              f"{BASE}/focus-groups/{fg_id}",
              headers=HEADERS,
          ).json()

          if "error" in resp:
              raise Exception(resp["error"]["message"])

          status = resp.get("status", "UNKNOWN")
          elapsed = int(time.time() - start)

          if status == "COMPLETED":
              print(f"✓ Focus group completed in {elapsed}s")
              return resp

          if status == "FAILED":
              raise Exception(f"Focus group failed: {resp.get('error', 'Unknown error')}")

          print(f"  Polling... status={status} ({elapsed}s elapsed)")
          time.sleep(10)

      raise TimeoutError(f"Focus group {fg_id} did not complete in {timeout_min} min")
  ```

  ```javascript JavaScript theme={"dark"}
  function buildStatementsBlock() {
    return POSITIONING_STATEMENTS.map(
      (s) => `Statement ${s.label}: "${s.statement}"`
    ).join("\n");
  }

  async function runPositioningFocusGroup(personaIds) {
    const statementsBlock = buildStatementsBlock();

    const payload = {
      name: "Positioning Workshop — 3 Statements × 5 Personas",
      sample_size: 30,
      persona_ids: personaIds,
      workspace_id: WORKSPACE_ID,
      questions: [
        {
          question:
            "Read these 3 positioning statements carefully, then rank them " +
            "from most compelling (1st) to least compelling (3rd).\n\n" +
            statementsBlock,
          type: "RANKING",
          options: POSITIONING_STATEMENTS.map((s) => `Statement ${s.label}`),
          order: 1,
        },
        {
          question: `Rate Statement A on this scale:\n\n"${POSITIONING_STATEMENTS[0].statement}"`,
          type: "SEMANTIC_DIFFERENTIAL",
          left_anchor: "Generic / could be anyone",
          right_anchor: "Differentiated / clearly unique",
          scale: 7,
          order: 2,
        },
        {
          question: `Rate Statement B on this scale:\n\n"${POSITIONING_STATEMENTS[1].statement}"`,
          type: "SEMANTIC_DIFFERENTIAL",
          left_anchor: "Confusing / hard to understand",
          right_anchor: "Clear / instantly understood",
          scale: 7,
          order: 3,
        },
        {
          question: `Rate Statement C on this scale:\n\n"${POSITIONING_STATEMENTS[2].statement}"`,
          type: "SEMANTIC_DIFFERENTIAL",
          left_anchor: "Forgettable / bland",
          right_anchor: "Memorable / would stick with me",
          scale: 7,
          order: 4,
        },
        {
          question:
            "You ranked the statements above. For the one you ranked #1:\n" +
            "- What specifically makes it compelling?\n" +
            "- What would make it even stronger?\n" +
            "- Is there anything misleading or unclear?",
          type: "OPEN_ENDED",
          order: 5,
        },
      ],
    };

    const resp = await fetch(`${BASE}/focus-groups`, {
      method: "POST",
      headers: HEADERS,
      body: JSON.stringify(payload),
    }).then((r) => r.json());

    if (resp.error) throw new Error(resp.error.message);
    console.log(`✓ Focus group created: ${resp.id}`);
    return resp;
  }

  async function pollFocusGroup(fgId, timeoutMin = 15) {
    const start = Date.now();
    for (let i = 0; i < timeoutMin * 6; i++) {
      const resp = await fetch(`${BASE}/focus-groups/${fgId}`, {
        headers: HEADERS,
      }).then((r) => r.json());

      if (resp.error) throw new Error(resp.error.message);
      if (resp.status === "COMPLETED") {
        console.log(`✓ Focus group completed in ${Math.round((Date.now() - start) / 1000)}s`);
        return resp;
      }
      if (resp.status === "FAILED")
        throw new Error(`Focus group failed: ${resp.error || "Unknown"}`);

      await new Promise((r) => setTimeout(r, 10000));
    }
    throw new Error(`Focus group ${fgId} timed out`);
  }
  ```
</CodeGroup>

***

### Stage 3 — Analyze Results

Extract ranking distributions, semantic differential averages, and open-ended themes.

<CodeGroup>
  ```python Python theme={"dark"}
  def analyze_results(fg_results: dict) -> dict:
      """Parse focus group results into a structured analysis."""
      analysis = {
          "ranking": {},
          "semantic_differentials": {},
          "open_ended_themes": [],
          "per_persona": {},
      }

      for result in fg_results.get("results", []):
          q_type = result.get("type")
          question = result.get("question", "")

          if q_type == "RANKING":
              analysis["ranking"] = {
                  "distribution": result.get("ranking_distribution", {}),
                  "summary": result.get("summary", ""),
              }

          elif q_type == "SEMANTIC_DIFFERENTIAL":
              label = "Unknown"
              for s in POSITIONING_STATEMENTS:
                  if f"Statement {s['label']}" in question:
                      label = s["label"]
                      break

              analysis["semantic_differentials"][label] = {
                  "mean": result.get("mean_score", 0),
                  "left_anchor": result.get("left_anchor", ""),
                  "right_anchor": result.get("right_anchor", ""),
                  "distribution": result.get("score_distribution", {}),
                  "summary": result.get("summary", ""),
              }

          elif q_type == "OPEN_ENDED":
              analysis["open_ended_themes"] = result.get("themes", [])
              analysis["open_ended_responses"] = result.get("responses", [])

      # Per-persona breakdown (if available)
      for result in fg_results.get("results", []):
          for persona_result in result.get("per_persona", []):
              pid = persona_result.get("persona_id", "unknown")
              if pid not in analysis["per_persona"]:
                  analysis["per_persona"][pid] = {}
              analysis["per_persona"][pid][result.get("question", "")[:50]] = persona_result

      return analysis


  def print_analysis(analysis: dict):
      """Print a human-readable summary."""
      print("\n" + "=" * 60)
      print("POSITIONING WORKSHOP RESULTS")
      print("=" * 60)

      print("\n--- Ranking Distribution ---")
      ranking = analysis["ranking"]
      if ranking.get("distribution"):
          for option, counts in ranking["distribution"].items():
              print(f"  {option}: {counts}")
      if ranking.get("summary"):
          print(f"  Summary: {ranking['summary']}")

      print("\n--- Semantic Differentials ---")
      for label, data in analysis["semantic_differentials"].items():
          print(f"  Statement {label}: {data['mean']:.1f}/7 "
                f"({data['left_anchor']} ←→ {data['right_anchor']})")

      print("\n--- Open-Ended Themes ---")
      for theme in analysis.get("open_ended_themes", []):
          print(f"  • {theme}")
  ```

  ```javascript JavaScript theme={"dark"}
  function analyzeResults(fgResults) {
    const analysis = {
      ranking: {},
      semantic_differentials: {},
      open_ended_themes: [],
      per_persona: {},
    };

    for (const result of fgResults.results || []) {
      if (result.type === "RANKING") {
        analysis.ranking = {
          distribution: result.ranking_distribution || {},
          summary: result.summary || "",
        };
      } else if (result.type === "SEMANTIC_DIFFERENTIAL") {
        let label = "Unknown";
        for (const s of POSITIONING_STATEMENTS) {
          if (result.question?.includes(`Statement ${s.label}`)) {
            label = s.label;
            break;
          }
        }
        analysis.semantic_differentials[label] = {
          mean: result.mean_score || 0,
          left_anchor: result.left_anchor || "",
          right_anchor: result.right_anchor || "",
          distribution: result.score_distribution || {},
          summary: result.summary || "",
        };
      } else if (result.type === "OPEN_ENDED") {
        analysis.open_ended_themes = result.themes || [];
      }
    }

    return analysis;
  }

  function printAnalysis(analysis) {
    console.log("\n--- Ranking Distribution ---");
    for (const [option, counts] of Object.entries(analysis.ranking.distribution || {})) {
      console.log(`  ${option}: ${JSON.stringify(counts)}`);
    }

    console.log("\n--- Semantic Differentials ---");
    for (const [label, data] of Object.entries(analysis.semantic_differentials)) {
      console.log(`  Statement ${label}: ${data.mean.toFixed(1)}/7`);
    }

    console.log("\n--- Open-Ended Themes ---");
    for (const theme of analysis.open_ended_themes) {
      console.log(`  • ${theme}`);
    }
  }
  ```
</CodeGroup>

***

### Stage 4 — Synthesize Recommendation

<CodeGroup>
  ```python Python theme={"dark"}
  RECOMMENDATION_SCHEMA = {"type": "json_schema", "json_schema": {
      "name": "positioning_recommendation", "strict": True,
      "schema": {
          "type": "object",
          "properties": {
              "winning_statement": {"type": "string", "description": "A, B, or C"},
              "confidence": {"type": "string", "description": "High, Medium, or Low"},
              "ranking_summary": {"type": "string"},
              "differentiation_winner": {"type": "string", "description": "Which statement scored highest on differentiation"},
              "clarity_winner": {"type": "string", "description": "Which statement scored highest on clarity"},
              "memorability_winner": {"type": "string", "description": "Which statement scored highest on memorability"},
              "segment_insights": {
                  "type": "array",
                  "items": {
                      "type": "object",
                      "properties": {
                          "segment": {"type": "string"},
                          "preferred_statement": {"type": "string"},
                          "reasoning": {"type": "string"},
                      },
                      "required": ["segment", "preferred_statement", "reasoning"],
                  },
              },
              "revision_suggestions": {
                  "type": "array",
                  "items": {"type": "string"},
                  "description": "Specific edits to strengthen the winning statement",
              },
              "final_recommendation": {"type": "string", "description": "2-3 sentence final recommendation"},
          },
          "required": [
              "winning_statement", "confidence", "ranking_summary",
              "differentiation_winner", "clarity_winner", "memorability_winner",
              "segment_insights", "revision_suggestions", "final_recommendation",
          ],
      },
  }}


  def synthesize_recommendation(analysis: dict) -> dict:
      """Use Chat to produce a structured positioning recommendation."""
      prompt = (
          "You are a positioning strategist. Analyze these focus group results "
          "and produce a positioning recommendation.\n\n"
          "## Positioning Statements Tested\n"
      )
      for s in POSITIONING_STATEMENTS:
          prompt += f"Statement {s['label']}: \"{s['statement']}\"\n"

      prompt += f"\n## Ranking Results\n{json.dumps(analysis['ranking'], indent=2)}\n"
      prompt += f"\n## Semantic Differential Scores\n{json.dumps(analysis['semantic_differentials'], indent=2)}\n"
      prompt += f"\n## Open-Ended Themes\n{json.dumps(analysis.get('open_ended_themes', []), indent=2)}\n"
      prompt += "\nProduce a recommendation with segment-level insights and specific revision suggestions."

      resp = mavera.responses.create(
          model="mavera-1",
          input=[{"role": "user", "content": prompt}],
          extra_body={"response_format": RECOMMENDATION_SCHEMA},
      )

      return json.loads(resp.output[0].content[0].text)
  ```

  ```javascript JavaScript theme={"dark"}
  const RECOMMENDATION_SCHEMA = { type: "json_schema", json_schema: {
    name: "positioning_recommendation", strict: true,
    schema: {
      type: "object",
      properties: {
        winning_statement: { type: "string" },
        confidence: { type: "string" },
        ranking_summary: { type: "string" },
        differentiation_winner: { type: "string" },
        clarity_winner: { type: "string" },
        memorability_winner: { type: "string" },
        segment_insights: {
          type: "array",
          items: {
            type: "object",
            properties: {
              segment: { type: "string" },
              preferred_statement: { type: "string" },
              reasoning: { type: "string" },
            },
            required: ["segment", "preferred_statement", "reasoning"],
          },
        },
        revision_suggestions: { type: "array", items: { type: "string" } },
        final_recommendation: { type: "string" },
      },
      required: [
        "winning_statement", "confidence", "ranking_summary",
        "differentiation_winner", "clarity_winner", "memorability_winner",
        "segment_insights", "revision_suggestions", "final_recommendation",
      ],
    },
  }};

  async function synthesizeRecommendation(analysis) {
    let prompt =
      "You are a positioning strategist. Analyze these focus group results " +
      "and produce a positioning recommendation.\n\n" +
      "## Positioning Statements Tested\n";

    for (const s of POSITIONING_STATEMENTS) {
      prompt += `Statement ${s.label}: "${s.statement}"\n`;
    }

    prompt += `\n## Ranking Results\n${JSON.stringify(analysis.ranking, null, 2)}\n`;
    prompt += `\n## Semantic Differential Scores\n${JSON.stringify(analysis.semantic_differentials, null, 2)}\n`;
    prompt += `\n## Open-Ended Themes\n${JSON.stringify(analysis.open_ended_themes || [], null, 2)}\n`;
    prompt += "\nProduce a recommendation with segment-level insights and specific revision suggestions.";

    const resp = await mavera.responses.create({
      model: "mavera-1",
      input: [{ role: "user", content: prompt }],
      response_format: RECOMMENDATION_SCHEMA,
    });

    return JSON.parse(resp.output[0].content[0].text);
  }
  ```
</CodeGroup>

***

### Running the Full Workshop

<CodeGroup>
  ```python Python theme={"dark"}
  def run_workshop():
      print("=" * 60)
      print("POSITIONING WORKSHOP")
      print("=" * 60)

      # Stage 1: Create personas
      print("\n--- Stage 1: Creating ICP Personas ---")
      persona_ids = create_personas()

      # Stage 2: Run focus group
      print("\n--- Stage 2: Running Focus Group ---")
      fg = run_positioning_focus_group(persona_ids)
      fg_results = poll_focus_group(fg["id"])

      # Stage 3: Analyze
      print("\n--- Stage 3: Analyzing Results ---")
      analysis = analyze_results(fg_results)
      print_analysis(analysis)

      # Stage 4: Synthesize
      print("\n--- Stage 4: Synthesizing Recommendation ---")
      recommendation = synthesize_recommendation(analysis)

      print(f"\nWinner: Statement {recommendation['winning_statement']}")
      print(f"Confidence: {recommendation['confidence']}")
      print(f"\n{recommendation['final_recommendation']}")

      if recommendation.get("revision_suggestions"):
          print("\nRevision suggestions:")
          for s in recommendation["revision_suggestions"]:
              print(f"  • {s}")

      # Save outputs
      with open("positioning_results.json", "w") as f:
          json.dump({
              "analysis": analysis,
              "recommendation": recommendation,
              "statements": POSITIONING_STATEMENTS,
          }, f, indent=2)

      print("\n✓ Saved positioning_results.json")
      return recommendation


  if __name__ == "__main__":
      run_workshop()
  ```

  ```javascript JavaScript theme={"dark"}
  import fs from "fs";

  async function runWorkshop() {
    console.log("POSITIONING WORKSHOP");

    // Stage 1: Create personas
    console.log("\n--- Stage 1: Creating ICP Personas ---");
    const personaIds = await createPersonas();

    // Stage 2: Run focus group
    console.log("\n--- Stage 2: Running Focus Group ---");
    const fg = await runPositioningFocusGroup(personaIds);
    const fgResults = await pollFocusGroup(fg.id);

    // Stage 3: Analyze
    console.log("\n--- Stage 3: Analyzing Results ---");
    const analysis = analyzeResults(fgResults);
    printAnalysis(analysis);

    // Stage 4: Synthesize
    console.log("\n--- Stage 4: Synthesizing Recommendation ---");
    const recommendation = await synthesizeRecommendation(analysis);

    console.log(`\nWinner: Statement ${recommendation.winning_statement}`);
    console.log(`Confidence: ${recommendation.confidence}`);
    console.log(`\n${recommendation.final_recommendation}`);

    fs.writeFileSync(
      "positioning_results.json",
      JSON.stringify({ analysis, recommendation, statements: POSITIONING_STATEMENTS }, null, 2)
    );
    console.log("\n✓ Saved positioning_results.json");
    return recommendation;
  }

  runWorkshop();
  ```
</CodeGroup>

***

## Example Output

```json theme={"dark"}
{
  "winning_statement": "A",
  "confidence": "High",
  "ranking_summary": "Statement A ranked #1 by 19 of 30 respondents. Statement B ranked #2 by most, with Statement C trailing. VP-level personas strongly preferred A; content marketers leaned toward B.",
  "differentiation_winner": "A",
  "clarity_winner": "B",
  "memorability_winner": "A",
  "segment_insights": [
    {
      "segment": "VP of Marketing",
      "preferred_statement": "A",
      "reasoning": "Resonated with 'replaces guesswork with data' — directly addresses their accountability pressure."
    },
    {
      "segment": "Content Marketing Manager",
      "preferred_statement": "B",
      "reasoning": "Preferred the speed emphasis ('minutes, not months') — maps to their daily workflow pain."
    },
    {
      "segment": "Founder / CEO",
      "preferred_statement": "A",
      "reasoning": "Valued 'resonates on the first try' — limited budget means they can't afford messaging misses."
    }
  ],
  "revision_suggestions": [
    "Add a speed element from Statement B ('in minutes') to Statement A's value prop",
    "Replace 'market intelligence platform' with a more specific category name",
    "Test whether 'persona-validated data' is understood by less technical buyers"
  ],
  "final_recommendation": "Ship Statement A as your primary positioning, with the speed language from B incorporated. Statement A wins on differentiation and memorability across 4 of 5 segments. Run a follow-up test after incorporating the revision suggestions."
}
```

***

## Variations

<AccordionGroup>
  <Accordion title="Test more than 3 statements">
    For 4–6 statements, split into two focus groups of 3. Head-to-head the winners in a final round:

    ```python theme={"dark"}
    # Round 1: Statements A-C
    fg1 = run_positioning_focus_group(persona_ids)  # with statements A, B, C
    # Round 2: Statements D-F
    fg2 = run_positioning_focus_group(persona_ids)  # with statements D, E, F
    # Final: Winners from each round
    fg_final = run_positioning_focus_group(persona_ids)  # winner of fg1 vs winner of fg2
    ```
  </Accordion>

  <Accordion title="Add competitive positioning context">
    Include competitor positioning in the open-ended question so personas can compare:

    ```python theme={"dark"}
    {
        "question": (
            "Here's how 3 competitors position themselves:\n"
            f"- Competitor 1: '{comp1_positioning}'\n"
            f"- Competitor 2: '{comp2_positioning}'\n\n"
            "Does Statement A stand out against these? What's missing?"
        ),
        "type": "OPEN_ENDED",
        "order": 6,
    }
    ```
  </Accordion>

  <Accordion title="Weighted persona scoring">
    If your VP persona matters 3× more than a Content Manager, weight the ranking:

    ```python theme={"dark"}
    WEIGHTS = {
        vp_marketing_id: 3.0,
        head_pmm_id: 2.0,
        cmo_id: 3.0,
        content_manager_id: 1.0,
        founder_id: 2.0,
    }
    ```
  </Accordion>

  <Accordion title="Iterate: refine and re-test">
    After getting revision suggestions, update the winning statement and run another workshop:

    ```python theme={"dark"}
    POSITIONING_STATEMENTS[0]["statement"] = revised_statement_a
    # Re-run with same personas
    fg2 = run_positioning_focus_group(persona_ids)
    ```

    Track scores across rounds to see the improvement trajectory.
  </Accordion>
</AccordionGroup>

***

## Credits Estimate

| Stage                                   | Typical Cost          | Notes                        |
| --------------------------------------- | --------------------- | ---------------------------- |
| Create 5 personas                       | 0                     | Persona creation is free     |
| Focus Group (N=30, 5 questions)         | 150–300 credits       | Sample size × question count |
| Synthesize recommendation (1 chat call) | 5–15 credits          | Single structured output     |
| **Total**                               | **\~155–315 credits** |                              |

<Tip>
  Start with N=15 (3 per persona) for a quick directional read at half the cost. Scale to N=30+ for statistically meaningful results you'd put in a board deck.
</Tip>

***

## See Also

<CardGroup cols={2}>
  <Card title="Focus Groups" icon="users" href="/features/focus-groups">
    All 12 question types including Ranking and Semantic Differential
  </Card>

  <Card title="Personas" icon="user" href="/features/personas">
    Create, list, and manage personas
  </Card>

  <Card title="Market Entry Research" icon="compass" href="/playbooks/market-entry-research">
    Research the market before testing positioning
  </Card>

  <Card title="Pricing Research" icon="tags" href="/playbooks/pricing-research">
    Test pricing alongside positioning
  </Card>

  <Card title="Brand Perception Audit" icon="chart-pie" href="/playbooks/brand-perception-audit">
    Measure how your brand is currently perceived
  </Card>

  <Card title="Message Testing Matrix" icon="table-cells" href="/playbooks/message-testing-matrix">
    5 messages × 5 personas for granular message testing
  </Card>
</CardGroup>
