import os, requests, time
from collections import defaultdict
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"}
# 1. Fetch all visitors with engagement data (paginated)
all_visitors = []
page = 1
while True:
resp = requests.get(f"{WS_BASE}/v1/stats/visitors.json", headers=WS_H, params={
"per_page": 100, "page": page,
})
if resp.status_code == 429:
time.sleep(2)
continue
resp.raise_for_status()
visitors = resp.json()
if not visitors:
break
all_visitors.extend(visitors)
page += 1
time.sleep(0.2)
print(f"Total visitors: {len(all_visitors)}")
# 2. Enrich each visitor with per-event details
enriched = []
for visitor in all_visitors[:200]:
visitor_key = visitor.get("visitor_key", "")
events = visitor.get("events", [])
total_watched = 0
total_available = 0
video_count = 0
locations = set()
for event in events:
pct = event.get("percent_viewed", 0)
total_watched += pct
total_available += 1
video_count += 1
avg_percent = total_watched / max(video_count, 1)
enriched.append({
"visitor_key": visitor_key,
"email": visitor.get("visitor_identity", {}).get("email", "anonymous"),
"name": visitor.get("visitor_identity", {}).get("name", ""),
"location": visitor.get("visitor_identity", {}).get("location", "unknown"),
"video_count": video_count,
"avg_percent_watched": round(avg_percent, 1),
"total_visits": visitor.get("total_visits", 0),
"last_active": visitor.get("last_active_at", ""),
})
# 3. Cluster viewers by behavior
clusters = defaultdict(list)
for v in enriched:
if v["video_count"] >= 5 and v["avg_percent_watched"] >= 75:
clusters["binge_watchers"].append(v)
elif v["video_count"] >= 3 and v["avg_percent_watched"] >= 50:
clusters["engaged_explorers"].append(v)
elif v["video_count"] == 1 and v["avg_percent_watched"] < 30:
clusters["bouncers"].append(v)
elif v["video_count"] >= 2 and v["avg_percent_watched"] < 50:
clusters["skimmers"].append(v)
else:
clusters["casual_viewers"].append(v)
print(f"\nClusters:")
for name, members in clusters.items():
print(f" {name}: {len(members)} viewers")
# 4. Create Mavera personas for each cluster
persona_map = {}
cluster_descriptions = {
"binge_watchers": "Watches 5+ videos, completes 75%+ of each. Deeply engaged, likely in active evaluation or already a customer seeking mastery. High intent signal.",
"engaged_explorers": "Watches 3-4 videos at 50-75% completion. Browsing with purpose — comparing options or building understanding. Mid-funnel prospect.",
"bouncers": "Watched 1 video, left before 30%. Either the content missed their intent, or they arrived by accident. Lowest engagement tier.",
"skimmers": "Watches 2+ videos but under 50% each. Scanning for specific information — not consuming narrative content. Wants answers, not stories.",
"casual_viewers": "Moderate engagement that doesn't fit other clusters. May be returning after time away or following a specific recommendation.",
}
for cluster_name, description in cluster_descriptions.items():
if cluster_name not in clusters:
continue
sample = clusters[cluster_name][:5]
sample_text = "\n".join(
f" - {s['email']}: {s['video_count']} videos, {s['avg_percent_watched']}% avg, {s['total_visits']} visits"
for s in sample
)
persona = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
"name": cluster_name.replace("_", " ").title(),
"description": f"{description}\n\nSample viewers:\n{sample_text}",
}).json()
persona_map[cluster_name] = persona["id"]
time.sleep(0.3)
# 5. Analyze via Mave with persona context
cluster_block = "\n\n".join(
f"CLUSTER: {name.replace('_', ' ').title()} ({len(members)} viewers)\n"
f" Avg videos watched: {sum(m['video_count'] for m in members) / len(members):.1f}\n"
f" Avg completion: {sum(m['avg_percent_watched'] for m in members) / len(members):.1f}%\n"
f" Avg total visits: {sum(m['total_visits'] for m in members) / len(members):.1f}\n"
f" Identified (with email): {sum(1 for m in members if m['email'] != 'anonymous')}"
for name, members in clusters.items() if members
)
analysis = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
"message": f"""Map these viewer clusters to marketing personas and suggest outreach strategies.
VIEWER CLUSTERS:
{cluster_block}
Total viewers analyzed: {len(enriched)}
For each cluster:
1. **Persona Profile**: Name, motivation, likely job title/role, what they're looking for
2. **Content Affinity**: What video types/topics would resonate most with this persona?
3. **Outreach Strategy**: Best channel (email, retargeting, sales call) and message angle
4. **Conversion Probability**: Estimate likelihood this cluster converts to customer (high/medium/low)
5. **Content Gaps**: What video content are we missing that this persona would need?
End with: Which cluster represents the highest-value opportunity and what single action would convert them?""",
}).json()
print("\nVIEWER-LEVEL PERSONA MAPPING")
print("=" * 60)
for name, members in clusters.items():
avg_pct = sum(m["avg_percent_watched"] for m in members) / len(members) if members else 0
identified = sum(1 for m in members if m["email"] != "anonymous")
print(f" {name.replace('_', ' ').title():<22} {len(members):>4} viewers "
f"Avg:{avg_pct:>5.1f}% Identified:{identified:>3}")
print("\n" + analysis.get("content", "")[:2000])