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

Your competitors are running YouTube ads and you only see surface-level view counts. This job searches for competitor ads by brand name, downloads the top results, uploads each to Mavera Assets, and runs Video Analysis to extract message clarity, emotional impact, and brand attribution. Mave then ranks all competitors in a single showdown. The result is a competitive creative intelligence report that tells you exactly where each competitor’s video messaging succeeds or fails — and where your ads can exploit the gaps.

Architecture

Code

import os, requests, time, tempfile

YT = os.environ["YOUTUBE_API_KEY"]
MV = os.environ["MAVERA_API_KEY"]
YT_BASE = "https://www.googleapis.com/youtube/v3"
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

COMPETITORS = ["Nike", "Adidas", "Puma"]

all_analyses = []

for brand in COMPETITORS:
    # 1. Search for competitor ads (100 quota units per call)
    search = requests.get(f"{YT_BASE}/search", params={
        "key": YT, "q": f"{brand} official ad 2026",
        "type": "video", "part": "snippet",
        "maxResults": 3, "order": "viewCount",
        "videoDuration": "short",
    }).json()

    if "error" in search:
        print(f"YouTube API error for {brand}: {search['error']['message']}")
        continue

    for item in search.get("items", []):
        video_id = item["id"]["videoId"]
        title = item["snippet"]["title"]

        # 2. Get video details for download URL (1 quota unit)
        details = requests.get(f"{YT_BASE}/videos", params={
            "key": YT, "id": video_id,
            "part": "snippet,contentDetails,statistics",
        }).json()
        video_info = (details.get("items") or [{}])[0]
        view_count = int(video_info.get("statistics", {}).get("viewCount", 0))

        # 3. Upload video URL to Mavera for analysis
        upload = requests.post(f"{MV_BASE}/assets", headers=MV_H, json={
            "url": f"https://www.youtube.com/watch?v={video_id}",
            "name": f"{brand}{title[:50]}",
            "type": "video",
        }).json()

        # 4. Run Video Analysis
        analysis = requests.post(f"{MV_BASE}/video-analysis", headers=MV_H, json={
            "asset_id": upload["id"],
            "analysis_types": [
                "message_clarity", "emotional_impact", "brand_attribution",
                "hook_score", "cognitive_load", "pacing",
            ],
            "metadata": {"brand": brand, "video_id": video_id, "views": view_count},
        }).json()

        # 5. Poll for completion
        status = {}
        for _ in range(30):
            time.sleep(3)
            status = requests.get(
                f"{MV_BASE}/video-analysis/{analysis['id']}", headers=MV_H
            ).json()
            if status.get("status") == "completed":
                break

        results = status.get("results", {})
        all_analyses.append({
            "brand": brand, "title": title[:50], "video_id": video_id,
            "views": view_count,
            "message_clarity": results.get("message_clarity", {}).get("score", 0),
            "emotional_impact": results.get("emotional_impact", {}).get("score", 0),
            "brand_attribution": results.get("brand_attribution", {}).get("score", 0),
            "hook_score": results.get("hook_score", {}).get("score", 0),
        })
        time.sleep(1)

# 6. Send all scores to Mave for comparative ranking
scores_block = "\n".join(
    f"- {a['brand']}: \"{a['title']}\" — clarity {a['message_clarity']}/100, "
    f"emotion {a['emotional_impact']}/100, attribution {a['brand_attribution']}/100, "
    f"hook {a['hook_score']}/100, views {a['views']:,}"
    for a in all_analyses
)

ranking = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
    "message": f"""Rank these competitor YouTube ads in a competitive showdown.

SCORES:
{scores_block}

For each brand:
1. Overall rank and composite score
2. Biggest creative strength
3. Most exploitable weakness
4. How our brand could beat them (specific creative recommendation)

End with: which competitor is the biggest creative threat and why.""",
}).json()

print("COMPETITOR AD ANALYSIS SHOWDOWN")
print("=" * 60)
for a in sorted(all_analyses, key=lambda x: -x["emotional_impact"]):
    print(f"  {a['brand']:<12} {a['title'][:35]:<38} "
          f"Clarity:{a['message_clarity']:>3}  Emotion:{a['emotional_impact']:>3}  "
          f"Hook:{a['hook_score']:>3}")
print("\n" + ranking.get("content", "")[:1500])

Example Output

COMPETITOR AD ANALYSIS SHOWDOWN
============================================================
  Nike         Just Do It — Summer 2026 Campai   Clarity: 91  Emotion: 94  Hook: 88
  Adidas       Impossible Is Nothing — Athletes   Clarity: 82  Emotion: 79  Hook: 72
  Puma         Forever Faster — Track & Field      Clarity: 68  Emotion: 71  Hook: 65

## Competitive Ranking

### #1 Nike (Composite: 91/100)
- Strength: Emotional storytelling peaks in first 2 seconds with athlete close-up
- Weakness: Brand logo doesn't appear until 18s — late attribution
- Beat them: Front-load your brand mark in first 3s while matching emotional intensity

### #2 Adidas (Composite: 78/100)
- Strength: Clear product-benefit messaging throughout
- Weakness: Hook score 72 — opens with wide establishing shot that loses mobile viewers
- Beat them: Use face-first hooks; Adidas consistently opens with landscape

### #3 Puma (Composite: 68/100)
- Strength: Distinctive color palette creates visual brand consistency
- Weakness: Message clarity 68 — tries to convey 3 messages in 30s
- Beat them: Single-message focus outperforms; Puma spreads too thin

BIGGEST THREAT: Nike — highest emotional impact (94) drives sharing behavior.
Their weakness (late attribution) means viewers remember the emotion but
sometimes forget the brand. Exploit this with emotion + immediate branding.

Error Handling

Each search.list call costs 100 quota units. Three competitors × 1 search = 300 units (3% of daily 10,000). For 10+ competitors, spread searches across hours or use multiple API keys.
Some videos have embedding/download restrictions. If the Mavera asset upload returns an error, skip the video and log the failure. Unlisted videos are not returned by search.list.
YouTube search results vary by region. Add regionCode=US (or your target market) to search.list for consistent results across runs.

YouTube Integration

Video Analysis