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.

Scenario

A viewer who watches more than 80% of your product video is a high-intent lead — they’ve invested 3+ minutes evaluating your solution. This job pulls viewer-level stats from Wistia, filters for viewers who completed 80%+ of any video, matches them to CRM data by email, then uses Mavera Generate to create personalized follow-up emails for each viewer based on which video they watched, how far they got, and their CRM context. The result is a batch of ready-to-send sales emails triggered by viewing behavior — the most intent-rich signal your marketing funnel produces.

Architecture

Code

import os, requests, time

WS = os.environ["WISTIA_API_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
WS_BASE = "https://api.wistia.com"
MV_BASE = "https://app.mavera.io/api/v1"
WS_H = {"Authorization": f"Bearer {WS}", "Accept": "application/json"}
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

TARGET_MEDIA_IDS = ["abc123def4", "xyz789ghi0", "mno456pqr1"]
WATCH_THRESHOLD = 0.80

# Simulated CRM data (replace with your CRM API call)
CRM_DATA = {
    "jane@acme.com": {"name": "Jane Chen", "company": "Acme Corp", "role": "VP Marketing", "deal_stage": "Evaluation", "industry": "SaaS"},
    "mike@globex.com": {"name": "Mike Ross", "company": "Globex Inc", "role": "Director of Growth", "deal_stage": "Awareness", "industry": "Fintech"},
    "sarah@initech.com": {"name": "Sarah Kim", "company": "Initech", "role": "CMO", "deal_stage": "Consideration", "industry": "Healthcare"},
}

qualified_viewers = []

for media_id in TARGET_MEDIA_IDS:
    # 1. Get media details
    media = requests.get(
        f"{WS_BASE}/v1/medias/{media_id}.json", headers=WS_H
    ).json()
    media_name = media.get("name", media_id)
    media_duration = media.get("duration", 0)

    # 2. Get visitor-level stats for this media
    visitors_resp = requests.get(
        f"{WS_BASE}/v1/stats/medias/{media_id}/visitors.json",
        headers=WS_H, params={"per_page": 100},
    ).json()

    for visitor in visitors_resp if isinstance(visitors_resp, list) else []:
        percent_watched = visitor.get("percent_viewed", 0)
        email = visitor.get("visitor_identity", {}).get("email", "")

        if percent_watched < WATCH_THRESHOLD or not email:
            continue

        crm = CRM_DATA.get(email, {})
        qualified_viewers.append({
            "email": email,
            "name": crm.get("name", email.split("@")[0].title()),
            "company": crm.get("company", "Unknown"),
            "role": crm.get("role", "Unknown"),
            "deal_stage": crm.get("deal_stage", "Unknown"),
            "industry": crm.get("industry", "Unknown"),
            "video_watched": media_name,
            "percent_watched": round(percent_watched * 100, 1),
            "video_duration": media_duration,
            "last_viewed": visitor.get("last_event_at", ""),
        })
    time.sleep(0.3)

print(f"Qualified viewers (>{WATCH_THRESHOLD*100:.0f}% watched): {len(qualified_viewers)}")

# 3. Generate personalized follow-up for each viewer
emails = []
for viewer in qualified_viewers:
    follow_up = requests.post(f"{MV_BASE}/generate", headers=MV_H, json={
        "prompt": f"""Write a personalized sales follow-up email for this viewer.

VIEWER CONTEXT:
- Name: {viewer['name']}
- Company: {viewer['company']}
- Role: {viewer['role']}
- Industry: {viewer['industry']}
- Deal Stage: {viewer['deal_stage']}
- Video Watched: "{viewer['video_watched']}" ({viewer['percent_watched']}% completed)
- Video Duration: {viewer['video_duration']}s

RULES:
1. Reference the specific video they watched — show you know what they saw
2. Tailor the value proposition to their role and industry
3. Match the follow-up intensity to their deal stage:
   - Awareness: Light touch, offer more content
   - Consideration: Share case study from their industry
   - Evaluation: Offer a personalized demo or pilot
4. Keep it under 150 words
5. One clear CTA — not multiple asks
6. Sound human, not automated. No "I noticed you watched..." (creepy)
7. Subject line should create curiosity, not summarize the email""",
    }).json()

    emails.append({
        **viewer,
        "email_content": follow_up.get("content", ""),
    })
    time.sleep(0.5)

# 4. Output
print("\nLEAD-QUALIFIED VIEWER → PERSONALIZED FOLLOW-UP")
print("=" * 60)
for e in emails:
    print(f"\n{'─' * 60}")
    print(f"TO: {e['name']} <{e['email']}> | {e['role']} @ {e['company']}")
    print(f"SIGNAL: Watched \"{e['video_watched']}\" ({e['percent_watched']}%) | Stage: {e['deal_stage']}")
    print(f"\n{e['email_content'][:600]}")

Example Output

Qualified viewers (>80% watched): 3

LEAD-QUALIFIED VIEWER → PERSONALIZED FOLLOW-UP
============================================================

──────────────────────────────────────────────────────────────
TO: Jane Chen <jane@acme.com> | VP Marketing @ Acme Corp
SIGNAL: Watched "Product Demo — Enterprise Dashboard" (94.2%) | Stage: Evaluation

Subject: The reporting gap your team is probably fighting right now

Hi Jane,

Your marketing team at Acme is probably spending Monday mornings the same
way most SaaS marketing teams do — pulling data from 6 dashboards into a
slide deck that's outdated by Tuesday.

The enterprise dashboard you saw handles the consolidation automatically,
but the real unlock for a VP-level view is the anomaly alerts. Instead of
your team flagging a campaign underperforming on Thursday, the system
catches it Monday at 6 AM.

I can set up a 20-minute walkthrough using your actual campaign data —
no slides, just your numbers in the dashboard.

Worth a look?

──────────────────────────────────────────────────────────────
TO: Mike Ross <mike@globex.com> | Director of Growth @ Globex Inc
SIGNAL: Watched "How-To: Getting Started" (82.1%) | Stage: Awareness

Subject: A fintech growth playbook you haven't seen yet

Hey Mike,

Most growth teams in fintech are optimizing the same three channels.
The teams pulling ahead are the ones who figured out that reporting
speed IS a growth lever — when you catch a winning experiment 3 days
earlier, you compound faster.

We put together a case study from a fintech company your size that
cut their experiment cycle from 14 days to 5. Happy to send it over
if that's relevant to what you're building at Globex.

Just reply "send it" and I'll drop it in your inbox.

──────────────────────────────────────────────────────────────
TO: Sarah Kim <sarah@initech.com> | CMO @ Initech
SIGNAL: Watched "ROI Calculator Walkthrough" (88.7%) | Stage: Consideration

Subject: Your Initech numbers in the calculator

Sarah,

The ROI calculator gives you a general estimate, but the healthcare
benchmarks are different — compliance reporting alone shifts the savings
by 30-40% for most health-tech companies.

I can run the calculator with Initech's actual data (team size, reporting
frequency, compliance requirements) and send you a one-page summary your
CFO would actually read.

Takes 15 minutes. Want me to set it up?

Error Handling

Email-based viewer matching depends on Wistia’s Turnstile email gate being enabled. Without it, viewers are anonymous. Enable Turnstile on high-intent videos (demos, pricing, case studies) to capture emails.
The example uses a static CRM lookup. In production, replace CRM_DATA with your CRM’s API (Salesforce, HubSpot, Pipedrive) to enrich viewer data with deal stage, company size, and activity history.

What’s Next

Wistia Integration

Back to Wistia integration overview

Wistia Embeds → Brand Voice Source

Build a brand voice profile from spoken content

Viewer-Level Persona Mapping

Map viewers to psychographic personas

Generate API

Full reference for POST /api/v1/generate