Skip to main content

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.

The Scenario

You have five different ways to describe your product and five distinct audience segments. Which message works best for which audience? You build a message-testing matrix: every message gets evaluated by every persona, producing a quantitative fit score for each cell. The output is a heat map of message-persona fit that tells you exactly which message to use for which audience.
Mavera-only workflow. No survey platforms, no panel vendors, no statistical software. Just Mavera’s Personas and Focus Groups surfaces.

When to Use This

  • Pre-launch messaging finalization — pick the winning variant per audience segment.
  • Channel-specific copy — different channels reach different personas.
  • Website personalization — serve the right headline to the right visitor segment.
  • Sales enablement — give each rep the message that resonates with their territory.

Architecture

Mavera SurfaceRole in Pipeline
Personas (POST /personas)Create 5 distinct audience segments
Focus Groups (POST /focus-groups)Test each message with each persona (25 combinations)

What You Need

RequirementDetails
Mavera API keyStarts with mvra_live_. Get one at Developer Settings.
Python 3.8+ or Node.js 18+requests for Python; native fetch for Node.
Credits~375–650 total. See Credits Estimate.
MAVERA_API_KEY=mvra_live_your_key_here

Step 1 — Define 5 Message Variants

Each message takes a different angle: value, speed, trust, emotion, or technical.
import os, time, json, requests

API_KEY = os.environ["MAVERA_API_KEY"]
BASE = "https://app.mavera.io/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

MESSAGES = {
    "value": {"label": "Value-First", "headline": "Cut Research Costs by 80%",
     "body": "Traditional audience research costs $15K–$50K per study. Mavera delivers the same insights for a fraction, in minutes."},
    "speed": {"label": "Speed-First", "headline": "From Question to Insight in 10 Minutes",
     "body": "Stop waiting weeks. Mavera's AI personas deliver focus group-quality feedback before your next standup."},
    "trust": {"label": "Trust & Credibility", "headline": "Research You Can Bet Your Campaign On",
     "body": "Personas built on data from millions of real consumers. 87% predictive accuracy. Trusted by 200+ marketing teams."},
    "emotion": {"label": "Emotional", "headline": "Never Launch Blind Again",
     "body": "That sinking feeling when a campaign underperforms? It starts with skipping research. Mavera makes it so fast, there's no excuse."},
    "technical": {"label": "Technical", "headline": "API-First Audience Intelligence",
     "body": "OpenAI-compatible Chat, Focus Groups with 12 question types, Video Analysis, Brand Voice extraction. One API key, unlimited surfaces."},
}

Step 2 — Create 5 Personas

PERSONA_DEFS = [
    {"name": "Startup CMO", "role": "CMO, Series B startup (50 people, $8M ARR)",
     "description": "Built the team from scratch. Budget-conscious but growth-aggressive. Measures everything by pipeline impact.",
     "traits": ["growth-focused", "budget-aware", "hands-on", "speed-oriented"]},
    {"name": "Enterprise Brand Mgr", "role": "Senior Brand Manager, Fortune 500 CPG",
     "description": "Manages $200M brand. Uses Nielsen, Kantar, Ipsos. Needs bulletproof methodology for internal buy-in.",
     "traits": ["process-driven", "methodology-focused", "risk-averse", "data-rigorous"]},
    {"name": "Agency Strategist", "role": "VP Strategy, creative agency with 40 clients",
     "description": "Strategic frameworks across all accounts. Differentiates in pitches. Needs tools that scale across clients.",
     "traits": ["multi-client thinker", "pitch-oriented", "insight-driven", "scalability-focused"]},
    {"name": "Product Marketer", "role": "PMM, mid-stage SaaS company",
     "description": "Owns positioning and launch for 3 product lines. Validates messaging before launch. Enables sales with battlecards.",
     "traits": ["cross-functional", "launch-focused", "sales-enablement-oriented", "messaging-obsessed"]},
    {"name": "Solo Consultant", "role": "Independent marketing consultant, 5–8 clients",
     "description": "One-person operation. Uses research to justify recs. Every dollar comes from margin. Needs tools that make one person look like a team.",
     "traits": ["price-sensitive", "time-constrained", "credibility-seeking", "simplicity-driven"]},
]

def create_persona(p):
    resp = requests.post(f"{BASE}/personas", headers=HEADERS, json={
        "name": p["name"], "role": p["role"], "description": p["description"], "traits": p["traits"]})
    resp.raise_for_status()
    data = resp.json()
    print(f"  Created: {data['name']}{data['id']}")
    return data["id"]

persona_map = {p["name"]: create_persona(p) for p in PERSONA_DEFS}

Step 3 — Run the 5×5 Matrix

Create all 25 Focus Groups, then poll for completion. Mavera processes them concurrently.
def build_questions(msg):
    block = f"**{msg['headline']}**\n\n{msg['body']}"
    return [
        {"question": f"Rate how compelling this is to you (0-10):\n\n{block}", "type": "NPS", "order": 1},
        {"question": "How would you describe this product to a colleague?", "type": "OPEN_ENDED", "order": 2},
        {"question": "Strongest element?", "type": "MULTIPLE_CHOICE",
         "options": ["Headline", "Value proposition", "Proof points", "Tone/voice", "Nothing stood out"], "order": 3},
        {"question": "Biggest gap or weakness?", "type": "OPEN_ENDED", "order": 4},
        {"question": "Would this make you want to learn more?", "type": "MULTIPLE_CHOICE",
         "options": ["Yes — click immediately", "Probably — with right CTA", "Unlikely — not relevant", "No — off-putting"], "order": 5},
    ]

def poll_fg(fg_id, timeout_min=10):
    for _ 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"])
        if resp["status"] == "COMPLETED": return resp
        time.sleep(10)
    raise TimeoutError(f"Focus Group {fg_id} timed out")

print("Creating 25 Focus Groups...")
matrix_jobs = {}
for mk, msg in MESSAGES.items():
    for pname, pid in persona_map.items():
        key = f"{mk}|{pname}"
        resp = requests.post(f"{BASE}/focus-groups", headers=HEADERS, json={
            "name": f"Matrix: {msg['label']} × {pname}",
            "persona_ids": [pid], "sample_size": 5, "questions": build_questions(msg),
        })
        resp.raise_for_status()
        matrix_jobs[key] = resp.json()["id"]

print(f"{len(matrix_jobs)} Focus Groups created. Polling...")
matrix_results = {k: poll_fg(fid) for k, fid in matrix_jobs.items()}
print("All 25 complete.")
25 Focus Groups take 5–15 minutes total. They run concurrently — the bottleneck is the slowest individual group.

Step 4 — Build and Display the Fit Matrix

def build_and_print_matrix(results):
    msg_keys = list(MESSAGES.keys())
    p_names = list(persona_map.keys())

    matrix = {}
    for mk in msg_keys:
        matrix[mk] = {}
        for pn in p_names:
            cell = results.get(f"{mk}|{pn}", {})
            nps = None
            for qr in cell.get("results", []):
                if qr["type"] == "NPS":
                    nps = qr.get("nps_score")
                    break
            matrix[mk][pn] = nps

    print("\n" + "=" * 90)
    print("MESSAGE-PERSONA FIT MATRIX (NPS Scores)")
    print("=" * 90)

    header = f"{'Message':<18}" + "".join(f" {pn:>14}" for pn in p_names) + f" {'AVG':>8}"
    print(header)
    print("─" * 90)

    best = (None, -100)
    for mk in msg_keys:
        label = MESSAGES[mk]["label"]
        scores = [matrix[mk].get(pn) for pn in p_names if matrix[mk].get(pn) is not None]
        avg = sum(scores) / len(scores) if scores else 0
        row = f"{label:<18}" + "".join(
            f" {matrix[mk].get(pn, 'N/A'):>14}" for pn in p_names) + f" {avg:>7.1f}"
        print(row)
        if avg > best[1]: best = (mk, avg)

    print("─" * 90)
    print(f"\n  Best overall: {MESSAGES[best[0]]['label']} (avg NPS: {best[1]:.1f})")
    for pn in p_names:
        bm = max(msg_keys, key=lambda mk: matrix[mk].get(pn, -100) or -100)
        print(f"  Best for {pn}: {MESSAGES[bm]['label']} (NPS: {matrix[bm].get(pn)})")

    return matrix

matrix = build_and_print_matrix(matrix_results)

Example Output

MESSAGE-PERSONA FIT MATRIX (NPS Scores)
══════════════════════════════════════════════════════════════════════════════════════
Message            Startup CMO  Enterprise BM  Agency Strat  Product Mktr  Solo Conslt      AVG
──────────────────────────────────────────────────────────────────────────────────────
Value-First                 72             35            58            55           82     60.4
Speed-First                 85             28            65            70           75     64.6
Trust & Credibility         40             78            55            48           30     50.2
Emotional                   68             22            70            62           55     55.4
Technical                   55             45            38            80           20     47.6
──────────────────────────────────────────────────────────────────────────────────────

  Best overall: Speed-First (avg NPS: 64.6)
  Best for Startup CMO: Speed-First (NPS: 85)
  Best for Enterprise Brand Mgr: Trust & Credibility (NPS: 78)
  Best for Agency Strategist: Emotional (NPS: 70)
  Best for Product Marketer: Technical (NPS: 80)
  Best for Solo Consultant: Value-First (NPS: 82)

Variations

import csv
with open("matrix.csv", "w", newline="") as f:
    w = csv.writer(f)
    w.writerow(["Message", "Persona", "NPS"])
    for mk in MESSAGES:
        for pn in persona_map:
            w.writerow([MESSAGES[mk]["label"], pn, matrix[mk].get(pn, "N/A")])
Bump sample_size from 5 to 25 for more stable NPS. Credits scale linearly.
new_msg = {"label": "Social Proof", "headline": "Join 500+ Teams", "body": "..."}
for pn, pid in persona_map.items():
    resp = requests.post(f"{BASE}/focus-groups", headers=HEADERS, json={
        "name": f"Matrix: Social Proof × {pn}", "persona_ids": [pid],
        "sample_size": 5, "questions": build_questions(new_msg)})
worst = min(matrix, key=lambda mk: sum((matrix[mk].get(pn) or 0) for pn in persona_map))
gen_resp = requests.post(f"{BASE}/generations", headers=HEADERS, json={
    "app": "ad_copy", "inputs": {"original": json.dumps(MESSAGES[worst]),
        "feedback": "Underperformed across all persona segments. Improve."}}).json()
print(f"Improved: {gen_resp.get('content', '')[:200]}")
import matplotlib.pyplot as plt
import numpy as np
data = np.array([[matrix[mk].get(pn, 0) or 0 for pn in persona_map] for mk in MESSAGES])
fig, ax = plt.subplots(figsize=(10, 5))
ax.imshow(data, cmap="RdYlGn", aspect="auto", vmin=-100, vmax=100)
ax.set_xticks(range(len(persona_map))); ax.set_xticklabels(persona_map.keys(), rotation=45, ha="right")
ax.set_yticks(range(len(MESSAGES))); ax.set_yticklabels([m["label"] for m in MESSAGES.values()])
plt.colorbar(ax.images[0], label="NPS"); plt.tight_layout(); plt.savefig("heatmap.png", dpi=150)

Credits Estimate

OperationTypical CostNotes
Persona creation (×5)0–25One-time; reuse across runs
Focus Groups (×25, 5 respondents, 5 questions)375–625~15–25 per group
Total~375–650
Start with sample_size: 5 for directional signal. Increase to 15–25 only for top-performing cells where you need higher confidence.

What’s Next

Industry Panel Simulation

Deep-dive a single message with 10 buying-committee personas

Persona Debate

Pit opposing personas against each other for pricing insights

Generational Content Testing

Test across age demographics instead of role-based segments

A/B Copy Production

Generate production-ready copy from matrix winners

Persona Selection Guide

Choose the right persona types for your research goal

Credits & Budget

Pre-flight checks and usage tracking