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

# Campaign Analytics → Content Brief

> Pull LinkedIn Campaign Manager analytics by industry, function, and seniority, then generate segment-specific content briefs with Mave Agent.

### Scenario

LinkedIn Campaign Manager reports performance by industry, job function, and seniority — but this data lives in spreadsheets. This job pulls analytics pivoted by these dimensions, identifies the top-performing segments (highest CTR and engagement), then uses Mave to write content briefs tailored to each winning segment. Instead of guessing what content to create, you let real campaign data tell you.

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A["LinkedIn GET /adAnalytics (industry/function/seniority)"] --> B["Rank segments by CTR"]
    B --> C["Mavera POST /mave/chat"]
    C --> D["Content briefs per top segment"]
```

### Code

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

  LI = os.environ["LINKEDIN_ACCESS_TOKEN"]
  MV = os.environ["MAVERA_API_KEY"]
  LI_BASE = "https://api.linkedin.com/rest"
  MV_BASE = "https://app.mavera.io/api/v1"
  LI_H = {"Authorization": f"Bearer {LI}", "LinkedIn-Version": "202401", "X-Restli-Protocol-Version": "2.0.0"}
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  CAMPAIGN_URN = "urn:li:sponsoredCampaign:200000001"

  # 1. Pull analytics pivoted by industry
  pivots = ["MEMBER_INDUSTRY", "MEMBER_JOB_FUNCTION", "MEMBER_SENIORITY"]
  all_segments = []

  for pivot in pivots:
      r = requests.get(f"{LI_BASE}/adAnalytics",
          headers=LI_H,
          params={
              "q": "analytics",
              "pivot": pivot,
              "dateRange.start.year": 2025, "dateRange.start.month": 1, "dateRange.start.day": 1,
              "dateRange.end.year": 2025, "dateRange.end.month": 12, "dateRange.end.day": 31,
              "timeGranularity": "ALL",
              "campaigns[0]": CAMPAIGN_URN,
              "fields": "impressions,clicks,costInLocalCurrency,externalWebsiteConversions",
          })
      if r.status_code == 429:
          time.sleep(int(r.headers.get("Retry-After", 60)))
          continue
      r.raise_for_status()

      for el in r.json().get("elements", []):
          impressions = el.get("impressions", 0)
          clicks = el.get("clicks", 0)
          if impressions < 100:
              continue
          ctr = clicks / impressions if impressions else 0
          conversions = el.get("externalWebsiteConversions", 0)
          all_segments.append({
              "pivot": pivot,
              "value": el.get("pivotValue", "Unknown"),
              "impressions": impressions,
              "clicks": clicks,
              "ctr": round(ctr * 100, 2),
              "conversions": conversions,
              "spend": el.get("costInLocalCurrency", 0),
          })
      time.sleep(0.5)

  # 2. Rank by CTR, take top segments
  top = sorted(all_segments, key=lambda x: -x["ctr"])[:6]

  # 3. Generate content briefs via Mave
  for seg in top:
      brief = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
          "message": f"""Write a content brief for this high-performing LinkedIn audience segment.

  SEGMENT: {seg['value']} ({seg['pivot'].replace('MEMBER_', '').replace('_', ' ').title()})
  PERFORMANCE: {seg['impressions']:,} impressions | {seg['clicks']:,} clicks | CTR: {seg['ctr']}% | {seg['conversions']} conversions | ${seg['spend']:,.2f} spend

  Produce:
  1. Why this segment responds (hypotheses based on role/industry/seniority)
  2. Content brief: topic, angle, format (whitepaper / blog / video / carousel)
  3. Headline options (3)
  4. Key messages and proof points to include
  5. Distribution strategy (organic LinkedIn + paid amplification)
  6. Recommended content length and CTA"""
      }).json()

      print(f"\n{'='*50}")
      print(f"SEGMENT: {seg['value']} | CTR: {seg['ctr']}% | Clicks: {seg['clicks']:,}")
      print(f"{'='*50}")
      print(brief.get("content", "")[:600])
  ```

  ```javascript JavaScript theme={"dark"}
  const LI = process.env.LINKEDIN_ACCESS_TOKEN;
  const MV = process.env.MAVERA_API_KEY;
  const LI_BASE = "https://api.linkedin.com/rest";
  const MV_BASE = "https://app.mavera.io/api/v1";
  const LI_H = { Authorization: `Bearer ${LI}`, "LinkedIn-Version": "202401", "X-Restli-Protocol-Version": "2.0.0" };
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const CAMPAIGN_URN = "urn:li:sponsoredCampaign:200000001";

  // 1. Pull analytics pivoted by industry/function/seniority
  const pivots = ["MEMBER_INDUSTRY", "MEMBER_JOB_FUNCTION", "MEMBER_SENIORITY"];
  const allSegments = [];

  for (const pivot of pivots) {
    const params = new URLSearchParams({
      q: "analytics", pivot,
      "dateRange.start.year": "2025", "dateRange.start.month": "1", "dateRange.start.day": "1",
      "dateRange.end.year": "2025", "dateRange.end.month": "12", "dateRange.end.day": "31",
      timeGranularity: "ALL",
      "campaigns[0]": CAMPAIGN_URN,
      fields: "impressions,clicks,costInLocalCurrency,externalWebsiteConversions",
    });
    const res = await fetch(`${LI_BASE}/adAnalytics?${params}`, { headers: LI_H });
    if (res.status === 429) {
      await new Promise(r => setTimeout(r, parseInt(res.headers.get("Retry-After") || "60", 10) * 1000));
      continue;
    }
    if (!res.ok) throw new Error(`LinkedIn ${res.status}`);

    for (const el of (await res.json()).elements || []) {
      const impressions = el.impressions || 0;
      const clicks = el.clicks || 0;
      if (impressions < 100) continue;
      allSegments.push({
        pivot, value: el.pivotValue || "Unknown",
        impressions, clicks,
        ctr: parseFloat(((clicks / impressions) * 100).toFixed(2)),
        conversions: el.externalWebsiteConversions || 0,
        spend: el.costInLocalCurrency || 0,
      });
    }
    await new Promise(r => setTimeout(r, 500));
  }

  // 2. Rank by CTR
  const top = allSegments.sort((a, b) => b.ctr - a.ctr).slice(0, 6);

  // 3. Content briefs via Mave
  for (const seg of top) {
    const brief = await fetch(`${MV_BASE}/mave/chat`, {
      method: "POST", headers: MV_H,
      body: JSON.stringify({
        message: `Write a content brief for this LinkedIn segment.\n\nSEGMENT: ${seg.value} (${seg.pivot.replace("MEMBER_", "").replace(/_/g, " ")})\nPERFORMANCE: ${seg.impressions.toLocaleString()} impressions | ${seg.clicks.toLocaleString()} clicks | CTR: ${seg.ctr}% | ${seg.conversions} conversions\n\nProduce: 1) Why this segment responds 2) Content brief 3) 3 headlines 4) Key messages 5) Distribution strategy 6) CTA`,
      }),
    }).then(r => r.json());

    console.log(`\n${"=".repeat(50)}`);
    console.log(`SEGMENT: ${seg.value} | CTR: ${seg.ctr}% | Clicks: ${seg.clicks.toLocaleString()}`);
    console.log("=".repeat(50));
    console.log((brief.content || "").slice(0, 600));
  }
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
==================================================
SEGMENT: Information Technology | CTR: 3.42% | Clicks: 1,847
==================================================
## Content Brief: IT Leaders & Digital Transformation

### Why This Segment Responds
IT leaders are actively evaluating tools that reduce manual processes.
Your ad's "60% faster" claim maps to their OKRs around operational efficiency.

### Brief
- Topic: "The Hidden Cost of Manual Reporting in IT Organizations"
- Format: Gated whitepaper (LinkedIn lead gen form)
- Angle: Quantified pain — tie manual hours to opportunity cost

### Headlines
1. "Your IT Team Spends 12 Hours/Week on Reports Nobody Reads"
2. "How [Company] Cut Reporting Time by 60% — Without New Headcount"
3. "The CFO Wants Faster Insights. Here's How IT Delivers."

### Distribution
- Organic: 3-part LinkedIn carousel summarizing key findings
- Paid: Sponsored Content targeting IT directors + VPs, 201-1000 employees
```

### Error Handling

<AccordionGroup>
  <Accordion title="Analytics data delays">LinkedIn analytics data can lag 24–48 hours. Don't expect same-day metrics. Schedule this job to run on T+2 data.</Accordion>
  <Accordion title="Pivot value mapping">Pivot values like `MEMBER_INDUSTRY` return LinkedIn's internal taxonomy codes (e.g., `urn:li:industry:4`). Map them via `GET /industries` for human-readable names.</Accordion>
  <Accordion title="Low-volume segments">Segments with under 100 impressions produce unreliable CTR. The code filters these out.</Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="All LinkedIn Marketing jobs" icon="linkedin" href="/integrations/linkedin-marketing" />

  <Card title="Mave Agent" icon="brain" href="/features/mave-agent" />
</CardGroup>
