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

# Instagram Reels Analysis Pipeline

> Pull Reels creatives from your ad account, run Video Analysis for hook effectiveness and emotional scoring, then run a Focus Group for qualitative feedback.

### Scenario

Your brand is investing heavily in Reels but you have no framework for why some Reels outperform others. This job pulls Reels creatives from your ad account, runs Video Analysis on each for hook effectiveness and emotional scoring, then runs a Focus Group asking personas about brand recall, hook quality, and purchase intent. The output is a quantitative + qualitative Reels performance framework.

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A["Meta GET adcreatives (Instagram Reels)"] --> B[Download videos] --> C["POST /api/v1/video-analyses"] --> D["POST /api/v1/focus-groups"] --> E[Combined report]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests, time, tempfile

  META = os.environ["META_ACCESS_TOKEN"]
  ACCT = os.environ["META_AD_ACCOUNT_ID"]
  MV = os.environ["MAVERA_API_KEY"]
  GRAPH = "https://graph.facebook.com/v24.0"
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  # 1. Pull Instagram placement ads (Reels)
  ads = requests.get(
      f"{GRAPH}/{ACCT}/ads",
      params={
          "access_token": META,
          "fields": "id,name,creative{id,name,video_id,title,body,instagram_permalink_url},targeting{publisher_platforms}",
          "effective_status": '["ACTIVE","PAUSED"]',
          "limit": 50,
      },
  ).json().get("data", [])

  reels = [a for a in ads if a.get("creative", {}).get("video_id")
           and "instagram" in str(a.get("targeting", {}).get("publisher_platforms", [])).lower()]
  print(f"Instagram Reels creatives: {len(reels)}")

  # 2. Video Analysis on each
  analyses = []
  for reel in reels[:8]:
      vid = reel["creative"]["video_id"]
      video_info = requests.get(f"{GRAPH}/{vid}",
          params={"access_token": META, "fields": "source,length,title"}).json()
      if not video_info.get("source"):
          continue

      vid_resp = requests.get(video_info["source"], stream=True)
      tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
      for chunk in vid_resp.iter_content(8192):
          tmp.write(chunk)
      tmp.close()

      with open(tmp.name, "rb") as f:
          asset = requests.post(f"{MB}/assets",
              headers={"Authorization": f"Bearer {MV}"},
              files={"file": (f"reel_{vid}.mp4", f, "video/mp4")}).json()
      os.unlink(tmp.name)

      analysis = requests.post(f"{MB}/video-analyses", headers=MH,
          json={"asset_id": asset["id"], "name": f"Reel: {reel.get('name', vid)}"}).json()

      for _ in range(30):
          time.sleep(10)
          status = requests.get(f"{MB}/video-analyses/{analysis['id']}",
              headers={"Authorization": f"Bearer {MV}"}).json()
          if status.get("status") in ("completed", "failed"):
              break

      if status.get("status") == "completed":
          analyses.append({
              "name": reel.get("name", vid),
              "video_id": vid,
              "duration": video_info.get("length"),
              "body": reel["creative"].get("body", "")[:150],
              "scores": status.get("scores", {}),
              "analysis_id": analysis["id"],
          })
      time.sleep(1)

  # 3. Focus Group on hook, recall, purchase intent
  reel_descriptions = "\n\n".join(
      f"Reel {i+1}: \"{a['name']}\" ({a['duration']}s)\n"
      f"Copy: {a['body']}\n"
      f"Emotional score: {a['scores'].get('emotional','?')}, "
      f"Hook strength: {a['scores'].get('attention_curve',['?'])[0] if isinstance(a['scores'].get('attention_curve'), list) else '?'}"
      for i, a in enumerate(analyses)
  )

  PERSONA_IDS = os.environ.get("PERSONA_IDS", "").split(",")
  if not PERSONA_IDS[0]:
      personas = requests.get(f"{MB}/personas",
          headers={"Authorization": f"Bearer {MV}"}).json()
      PERSONA_IDS = [p["id"] for p in (personas if isinstance(personas, list) else [])[:4]]

  fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
      "name": "Instagram Reels Analysis",
      "persona_ids": PERSONA_IDS,
      "questions": [
          f"Based on these Reels descriptions, which hook would stop your scroll? Why?\n\n{reel_descriptions}",
          "Rate your brand recall after seeing each Reel (1-10). Which brand/product sticks?",
          "Which Reel would make you most likely to purchase or visit a website? Why?",
          "What makes a Reel hook effective for you? First 3 seconds — what grabs attention?",
          "Would you share any of these Reels? Which one and why?",
      ],
      "context": "You are evaluating Instagram Reels ads for effectiveness.",
      "responses_per_persona": 2,
  }).json()

  for _ in range(24):
      time.sleep(5)
      fg_data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
      if fg_data.get("status") == "completed":
          break

  # 4. Combined report
  print("=== Instagram Reels Analysis Report ===\n")
  print("--- Video Analysis Scores ---")
  for a in analyses:
      s = a["scores"]
      print(f"  {a['name']}: emotional={s.get('emotional','?')} cognitive={s.get('cognitive','?')} behavioral={s.get('behavioral','?')}")

  print("\n--- Focus Group Insights ---")
  for resp in fg_data.get("responses", [])[:12]:
      print(f"  [{resp.get('persona_id','?')[:12]}] {resp.get('question','')[:50]}...")
      print(f"    → {resp.get('answer','')[:200]}\n")
  ```

  ```javascript JavaScript theme={"dark"}
  const META = process.env.META_ACCESS_TOKEN;
  const ACCT = process.env.META_AD_ACCOUNT_ID;
  const MV = process.env.MAVERA_API_KEY;
  const GRAPH = "https://graph.facebook.com/v24.0";
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  // 1. Pull Instagram placement ads
  const ads = await fetch(
    `${GRAPH}/${ACCT}/ads?access_token=${META}&fields=id,name,creative{id,name,video_id,title,body,instagram_permalink_url},targeting{publisher_platforms}&effective_status=["ACTIVE","PAUSED"]&limit=50`
  ).then(r => r.json()).then(d => d.data || []);

  const reels = ads.filter(a => a.creative?.video_id
    && JSON.stringify(a.targeting?.publisher_platforms || []).toLowerCase().includes("instagram"));
  console.log(`Instagram Reels: ${reels.length}`);

  // 2. Video Analysis
  const analyses = [];
  for (const reel of reels.slice(0, 8)) {
    const vid = reel.creative.video_id;
    const videoInfo = await fetch(
      `${GRAPH}/${vid}?access_token=${META}&fields=source,length,title`
    ).then(r => r.json());
    if (!videoInfo.source) continue;

    const vidBuffer = Buffer.from(await fetch(videoInfo.source).then(r => r.arrayBuffer()));
    const form = new FormData();
    form.append("file", new Blob([vidBuffer], { type: "video/mp4" }), `reel_${vid}.mp4`);
    const asset = await fetch(`${MB}/assets`, {
      method: "POST", headers: { Authorization: `Bearer ${MV}` }, body: form,
    }).then(r => r.json());

    const analysis = await fetch(`${MB}/video-analyses`, {
      method: "POST", headers: MH,
      body: JSON.stringify({ asset_id: asset.id, name: `Reel: ${reel.name || vid}` }),
    }).then(r => r.json());

    let status;
    for (let i = 0; i < 30; i++) {
      await new Promise(r => setTimeout(r, 10000));
      status = await fetch(`${MB}/video-analyses/${analysis.id}`,
        { headers: { Authorization: `Bearer ${MV}` } }).then(r => r.json());
      if (status.status === "completed" || status.status === "failed") break;
    }

    if (status?.status === "completed") {
      analyses.push({
        name: reel.name || vid, video_id: vid, duration: videoInfo.length,
        body: (reel.creative.body || "").slice(0, 150),
        scores: status.scores || {}, analysis_id: analysis.id,
      });
    }
    await new Promise(r => setTimeout(r, 1000));
  }

  // 3. Focus Group
  const reelDescs = analyses.map((a, i) =>
    `Reel ${i+1}: "${a.name}" (${a.duration}s)\nCopy: ${a.body}\nEmotional: ${a.scores.emotional ?? "?"}`
  ).join("\n\n");

  let personaIds = (process.env.PERSONA_IDS || "").split(",").filter(Boolean);
  if (!personaIds.length) {
    const personas = await fetch(`${MB}/personas`, { headers: MH }).then(r => r.json());
    personaIds = (Array.isArray(personas) ? personas : []).slice(0, 4).map(p => p.id);
  }

  const fg = await fetch(`${MB}/focus-groups`, {
    method: "POST", headers: MH,
    body: JSON.stringify({
      name: "Instagram Reels Analysis", persona_ids: personaIds,
      questions: [
        `Which hook would stop your scroll?\n\n${reelDescs}`,
        "Rate brand recall 1-10 for each Reel.",
        "Which Reel would most likely drive you to purchase?",
        "What makes a Reel hook effective in the first 3 seconds?",
        "Would you share any of these? Which and why?",
      ],
      context: "Evaluating Instagram Reels ads.", responses_per_persona: 2,
    }),
  }).then(r => r.json());

  let fgData;
  for (let i = 0; i < 24; i++) {
    await new Promise(r => setTimeout(r, 5000));
    fgData = await fetch(`${MB}/focus-groups/${fg.id}`, { headers: MH }).then(r => r.json());
    if (fgData.status === "completed") break;
  }

  console.log("=== Reels Analysis Report ===\n--- Scores ---");
  analyses.forEach(a => {
    const s = a.scores;
    console.log(`  ${a.name}: emotional=${s.emotional ?? "?"} cognitive=${s.cognitive ?? "?"} behavioral=${s.behavioral ?? "?"}`);
  });
  console.log("\n--- Focus Group ---");
  (fgData.responses || []).slice(0, 12).forEach(r => {
    console.log(`  [${(r.persona_id || "?").slice(0, 12)}] ${(r.question || "").slice(0, 50)}...`);
    console.log(`    → ${(r.answer || "").slice(0, 200)}\n`);
  });
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
=== Instagram Reels Analysis Report ===

--- Video Analysis Scores ---
  Brand Story Reel: emotional=8.7 cognitive=5.2 behavioral=6.1
  Product Demo Reel: emotional=5.4 cognitive=8.3 behavioral=7.9
  UGC Testimonial Reel: emotional=9.1 cognitive=6.8 behavioral=8.5
  Behind-the-Scenes Reel: emotional=7.3 cognitive=4.1 behavioral=3.8

--- Focus Group Insights ---
  [per_meta_f25] Which hook would stop your scroll?
    → The UGC Testimonial — it looks like a real person, not an ad. The first frame
    showing someone's genuine reaction is more authentic than polished brand content.

  [per_meta_m35] Which Reel would drive you to purchase?
    → Product Demo. I need to see how it actually works. The testimonial builds trust
    but the demo answers "does this solve my specific problem?"

  [per_meta_f18] Would you share any of these?
    → Behind-the-Scenes — I share content that makes me look "in the know." BTS gives
    me insider knowledge I can share with friends who are into the space.
```

### Error Handling

<AccordionGroup>
  <Accordion title="Filtering Reels vs Feed video">The API doesn't have a `placement=reels` filter on creatives. Use `targeting.publisher_platforms` or filter by aspect ratio (9:16 for Reels, 1:1 or 16:9 for Feed).</Accordion>
  <Accordion title="Large video files">Reels over 60s can be 100MB+. Set `stream=True` when downloading and check available disk space on your server.</Accordion>
  <Accordion title="Combining Video Analysis + Focus Group">Run Video Analysis first, then feed scores into the Focus Group context. This gives personas quantitative data to react to, producing richer qualitative feedback.</Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="All Meta Ads Jobs" icon="meta" href="/integrations/meta-ads">
    Browse all Meta Ads integration jobs
  </Card>

  <Card title="Video Analysis" icon="video" href="/features/video-analysis">
    Full guide to Mavera Video Analysis
  </Card>
</CardGroup>
