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 top-performing ad campaigns reveal what messaging resonates with your audience, but that intelligence stays siloed in Ads Manager. This job pulls the highest-CTR campaigns, extracts winning themes and copy patterns, establishes a Brand Voice from ad copy, then generates long-form content (blog posts, social posts) that extends those proven themes across channels.

Architecture

Code

import os, requests, time

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 campaign insights sorted by CTR
campaigns = requests.get(
    f"{GRAPH}/{ACCT}/insights",
    params={
        "access_token": META,
        "fields": "campaign_name,campaign_id,impressions,clicks,ctr,conversions,spend,actions",
        "level": "campaign",
        "date_preset": "last_30d",
        "sort": "ctr_descending",
        "limit": 20,
    },
).json().get("data", [])

top_campaigns = [c for c in campaigns if float(c.get("ctr", 0)) > 1.0][:5]
print(f"Top {len(top_campaigns)} campaigns by CTR")

# 2. Pull ad copy from top campaigns
all_copy = []
for camp in top_campaigns:
    cid = camp.get("campaign_id")
    if not cid:
        continue
    ads = requests.get(
        f"{GRAPH}/{cid}/ads",
        params={
            "access_token": META,
            "fields": "creative{title,body,link_description}",
            "limit": 10,
        },
    ).json().get("data", [])

    for ad in ads:
        c = ad.get("creative", {})
        copy_text = f"Headline: {c.get('title', '')}\nBody: {c.get('body', '')}\nDescription: {c.get('link_description', '')}"
        if c.get("title") or c.get("body"):
            all_copy.append(copy_text)
    time.sleep(0.5)

# 3. Create Brand Voice from winning ad copy
samples = "\n\n---\n\n".join(all_copy[:15])
bv = requests.post(f"{MB}/brand-voices", headers=MH, json={
    "name": "Meta Top Campaign Voice",
    "samples": [samples],
}).json()
print(f"Brand Voice: {bv['id']}")

# 4. Extract themes
themes = [
    f"Campaign: {c.get('campaign_name','')}, CTR: {c.get('ctr','?')}%, "
    f"Clicks: {c.get('clicks','?')}, Spend: ${c.get('spend','?')}"
    for c in top_campaigns
]
theme_summary = "\n".join(themes)

# 5. Generate blog post
blog = requests.post(f"{MB}/generations", headers=MH, json={
    "brand_voice_id": bv["id"],
    "prompt": f"""Based on these top-performing Meta ad campaign themes, write a 600-word blog post 
that extends the most resonant messaging into long-form content.

TOP CAMPAIGNS:
{theme_summary}

WINNING COPY EXCERPTS:
{samples[:2000]}

Write a blog post that: uses the same tone and key phrases, expands on the core value proposition,
includes a clear CTA, and is optimized for SEO.""",
}).json()

# 6. Generate social posts
social = requests.post(f"{MB}/generations", headers=MH, json={
    "brand_voice_id": bv["id"],
    "prompt": f"""Create 5 social media posts (mix of LinkedIn, Twitter/X, Instagram caption) 
inspired by these top campaign themes:

{theme_summary}

Each post should: match the ad copy voice, be platform-appropriate length,
include a hook in the first line, end with CTA.""",
}).json()

print("\n=== Blog Post ===")
print((blog.get("output") or blog.get("content", ""))[:500])
print("\n=== Social Posts ===")
print((social.get("output") or social.get("content", ""))[:500])

Example Output

Brand Voice: bv_meta_top_8k3n

=== Blog Post ===
# Your Competitors Already Know This — Here's What They're Doing Differently

The data doesn't lie. After analyzing 50,000 ad impressions last month,
one pattern stands out: teams that centralize their analytics make decisions
40% faster. Not incrementally — fundamentally faster.

But here's what most articles about analytics won't tell you...

=== Social Posts ===
1. [LinkedIn] Most teams spend 60% of their time building reports nobody reads.
   We asked 200 marketing leaders what changed when they stopped. The answer
   surprised us. → Link in comments

2. [Twitter/X] "Stop guessing. Start growing." isn't just a tagline.
   We tracked 1,200 teams for 6 months. The ones who centralized analytics?
   3.2x faster campaign iterations. Here's the breakdown: 🧵

3. [Instagram] POV: You just cut your reporting time from 4 hours to 15 minutes.
   That's not a dream — it's what happens when you stop duct-taping dashboards.
   Link in bio for the free guide.

Error Handling

Meta returns ctr as a string like "2.345". Always parse with float() / parseFloat() before comparing.
Use level=campaign param. Without it, you get ad-account-level aggregates which won’t have campaign_id.
Under 5 copy samples produces a generic voice. The code caps at 15 samples from top campaigns — aim for 8+ distinct pieces.

All Meta Ads Jobs

Browse all Meta Ads integration jobs

Brand Voices

Full guide to creating and managing Brand Voices