> ## 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.

# Competitor Ad Analysis Showdown

> Search competitor YouTube ads, run Video Analysis on each, and produce a ranked competitive creative intelligence report

## 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

```mermaid theme={"dark"}
flowchart LR
    A["YouTube search.list (competitor brand + ad)"] --> B[Download video URLs] --> C["Mavera POST /assets"] --> D["POST /video-analysis"] --> E["POST /mave/chat (comparative ranking)"] --> F[Competitive showdown report]
```

## Code

<CodeGroup>
  ```python Python theme={"dark"}
  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])
  ```

  ```javascript JavaScript theme={"dark"}
  const YT = process.env.YOUTUBE_API_KEY;
  const MV = process.env.MAVERA_API_KEY;
  const YT_BASE = "https://www.googleapis.com/youtube/v3";
  const MV_BASE = "https://app.mavera.io/api/v1";
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const COMPETITORS = ["Nike", "Adidas", "Puma"];
  const allAnalyses = [];

  for (const brand of COMPETITORS) {
    // 1. Search for competitor ads (100 quota units)
    const search = await fetch(
      `${YT_BASE}/search?key=${YT}&q=${encodeURIComponent(`${brand} official ad 2026`)}` +
      `&type=video&part=snippet&maxResults=3&order=viewCount&videoDuration=short`
    ).then(r => r.json());

    if (search.error) {
      console.error(`YouTube error for ${brand}: ${search.error.message}`);
      continue;
    }

    for (const item of search.items || []) {
      const videoId = item.id.videoId;
      const title = item.snippet.title;

      // 2. Video details (1 quota unit)
      const details = await fetch(
        `${YT_BASE}/videos?key=${YT}&id=${videoId}&part=snippet,contentDetails,statistics`
      ).then(r => r.json());
      const viewCount = parseInt(details.items?.[0]?.statistics?.viewCount || "0", 10);

      // 3. Upload to Mavera
      const upload = await fetch(`${MV_BASE}/assets`, {
        method: "POST", headers: MV_H,
        body: JSON.stringify({
          url: `https://www.youtube.com/watch?v=${videoId}`,
          name: `${brand} — ${title.slice(0, 50)}`,
          type: "video",
        }),
      }).then(r => r.json());

      // 4. Video Analysis
      const analysis = await fetch(`${MV_BASE}/video-analysis`, {
        method: "POST", headers: MV_H,
        body: JSON.stringify({
          asset_id: upload.id,
          analysis_types: [
            "message_clarity", "emotional_impact", "brand_attribution",
            "hook_score", "cognitive_load", "pacing",
          ],
          metadata: { brand, video_id: videoId, views: viewCount },
        }),
      }).then(r => r.json());

      // 5. Poll
      let status;
      for (let i = 0; i < 30; i++) {
        await new Promise(r => setTimeout(r, 3000));
        status = await fetch(
          `${MV_BASE}/video-analysis/${analysis.id}`, { headers: MV_H }
        ).then(r => r.json());
        if (status.status === "completed") break;
      }

      const results = status.results || {};
      allAnalyses.push({
        brand, title: title.slice(0, 50), videoId, views: viewCount,
        messageClarity: results.message_clarity?.score || 0,
        emotionalImpact: results.emotional_impact?.score || 0,
        brandAttribution: results.brand_attribution?.score || 0,
        hookScore: results.hook_score?.score || 0,
      });
      await new Promise(r => setTimeout(r, 1000));
    }
  }

  // 6. Comparative ranking via Mave
  const scoresBlock = allAnalyses.map(a =>
    `- ${a.brand}: "${a.title}" — clarity ${a.messageClarity}/100, ` +
    `emotion ${a.emotionalImpact}/100, attribution ${a.brandAttribution}/100, ` +
    `hook ${a.hookScore}/100, views ${a.views.toLocaleString()}`
  ).join("\n");

  const ranking = await fetch(`${MV_BASE}/mave/chat`, {
    method: "POST", headers: MV_H,
    body: JSON.stringify({
      message: `Rank these competitor YouTube ads in a showdown.\n\n${scoresBlock}\n\nFor each brand: 1) Overall rank 2) Biggest strength 3) Most exploitable weakness 4) How to beat them. End with: who is the biggest creative threat?`,
    }),
  }).then(r => r.json());

  console.log("COMPETITOR AD ANALYSIS SHOWDOWN");
  console.log("=".repeat(60));
  allAnalyses
    .sort((a, b) => b.emotionalImpact - a.emotionalImpact)
    .forEach(a =>
      console.log(`  ${a.brand.padEnd(12)} ${a.title.slice(0, 35).padEnd(38)} ` +
        `Clarity:${String(a.messageClarity).padStart(3)}  Emotion:${String(a.emotionalImpact).padStart(3)}  ` +
        `Hook:${String(a.hookScore).padStart(3)}`)
    );
  console.log("\n" + (ranking.content || "").slice(0, 1500));
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
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

<AccordionGroup>
  <Accordion title="Quota exhaustion on search.list">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.</Accordion>
  <Accordion title="Video unavailable for analysis">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`.</Accordion>
  <Accordion title="Regional content differences">YouTube search results vary by region. Add `regionCode=US` (or your target market) to `search.list` for consistent results across runs.</Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="YouTube Integration" icon="arrow-left" href="/integrations/youtube" />

  <Card title="Video Analysis" icon="video" href="/api-reference/video-analysis" />
</CardGroup>
