Conversations
Checking your Mavera sessionLoading workspace audiences and API keys…
Checking…Use or share this pageSend the page itself, print it, or open its complete context in your AI workspace.
Focus groups
Moderated panels with code-computed group dynamics.
Endpoint: POST /api/v1/tools/focus_group. Required: audienceId + topic.
The full input schema
| Field | Type | What it does |
|---|---|---|
audienceId (required) | string | The audience the panel is drawn from. |
topic (required) | string | The framing the moderator opens with. |
stimulus | string | The concrete thing they react to — a concept, price, claim, or described creative. Strongly recommended. |
panelSize | integer | How many distinct personas sit on the panel (5–8 is the sweet spot). |
rounds | integer | Passes through the panel. 2+ lets personas react to each other (real dynamics emerge). |
moderatorGuide | string[] | Ordered questions the moderator works through across rounds. |
seed | integer | Reproducible panel draw + responses — fix it to compare two stimuli against the same room. |
freshPanel | boolean | Perturbs the draw by topic so each group recruits different people (like a real multi-group study). Default false = same seed ⇒ same panel (comparable A/B cells). |
modelPanel | boolean | Default true. One frontier call casts the whole panel's identities together under a distinctness contract (no shared backstories, beats, or verbal fingerprints). Measured +7.5 realism points vs template panels. Set false for the fully deterministic template path. |
gradeRealism | boolean | A JUDGE-tier model grades the transcript for synthetic tells after the run; the grade rides the response as realism and feeds the quality ledger. |
promptVersion | "v1" | "v2" |
modelTier | string | Override the model tier (defaults to the conversation tier). |
{
"audienceId": "aud_f1_1",
"topic": "A $29/mo all-in-one finance app for solo founders",
"stimulus": "Bookkeeping, invoicing, and cash-flow forecasting in one place for $29/mo. No setup fees.",
"panelSize": 5,
"rounds": 2,
"moderatorGuide": [
"First reaction — would this fit your world?",
"What's the single biggest thing that would stop you from buying?",
"What would make it a no-brainer?"
],
"seed": 42
}What comes back
{ "ok": true, "data": {
"panel": [
{ "personaId": "aud_f1_1@v1#42#0", "name": "Maya R. — a bootstrapped founder juggling three tools",
"archetype": "Price & cost", "disposition": "enthusiast", "speechStyle": "terse",
"attributes": { "company_size": "smb", "market_status": "in-market" }, "realizedBy": "model" }
],
"transcript": [
{ "round": 1, "personaId": "aud_f1_1@v1#42#0", "name": "Maya R. — a bootstrapped founder juggling three tools",
"content": "At $29 this is a no-brainer for me...", "abstained": false, "respondingTo": null },
{ "round": 2, "personaId": "aud_f1_1@v1#42#1", "name": "Devon K. — an ops lead who's been burned by tool sprawl",
"content": "I'd worry it won't keep up once we're 20 people.", "abstained": false, "respondingTo": null }
],
"dynamics": {
"convergence": [ { "theme": "Price & cost", "share": 0.8 } ],
"polarizing": [ { "theme": "Proof & credibility", "forCount": 2, "againstCount": 3 } ],
"shifts": [ { "personaId": "aud_f1_1@v1#42#1", "fromStance": "Proof & credibility", "toStance": "Price & cost" } ],
"quietParticipants": [ "aud_f1_1@v1#42#3" ]
},
"diversity": {
"crossSpeakerLexicalOverlap": 0.002, "turnLengthVariation": 0.33,
"openerDiversity": 1, "sharedIdiomCount": 0, "lengthRangeRatio": 2.63
},
"honesty": { "synthetic": true, "groundingStrength": "category-modeled" },
"realism": null
} }| Field | Meaning & how to use it |
|---|---|
panel[].realizedBy | "model" = identities cast by the frontier model (default); "code" = deterministic template path. |
dynamics.convergence | Themes the panel agreed on (share across participants). Your strongest, most defensible findings. |
dynamics.polarizing | Themes that split the room. These are your richest follow-ups — feed them to the Insight Miner / branch them. |
dynamics.shifts | Personas whose dominant theme changed between rounds — shows what argument moved them. |
dynamics.quietParticipants | Personas who abstained or said least. Worth a targeted 1:1 chat — silence can hide the real objection. |
diversity | Code-computed panel-diversity telemetry, free on every run. See the quality loop. |
realism | Present when gradeRealism: true: the judge's score, verdict, and evidence-quoted tells. |
All of dynamics and diversity is code-computed from the transcript text — shares, splits, overlaps, and shift detection are counted/scored, not asserted by the model.
From group to insight
# 1. run the group → take data.transcript
# 2. reshape to [{speaker, text}] and mine it for the splits
POST /api/v1/tools/mine_insights { "turns":[...transcript...], "useLlm":true, "llmMode":"identify" }
# 3. take a divergence's branchPrompt and explore it live
POST /api/v1/insights/branch { "audienceId":"aud_f1_1", "branchPrompt":"<from step 2>", "depth":2 }See Mining insights and Branching & flip-tests for the full loop.
Designing a group that produces signal
- Always give a concrete
stimulus. "React to this $29 offer with features X, Y, Z" yields far sharper output than an abstracttopicalone. Personas need something specific to push against. - Use 2+ rounds. Round 1 is first impressions; the real dynamics — agreement forming, dissent hardening, minds changing — happen in round 2+.
- panelSize 5–8. Enough diversity to surface splits, few enough that individual voices stay distinct.
- Write a tight
moderatorGuide. 3–5 escalating questions (reaction → objection → what-would-fix-it) beats one open prompt. - Fix the
seedwhen comparing stimuli (e.g. $29 vs $49) so the only variable is the stimulus, not the panel.
Focus group vs the other modalities
A focus group is the right tool when you want group reaction + dynamics. If you want depth on one person use chat or deep_interview; for a head-to-head argument use persona_debate; for emotional/unspoken drivers use projective_session. See all modalities.