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. Find Lookalike Audiences and their seeds
audiences = requests.get(
f"{GRAPH}/{ACCT}/customaudiences",
params={
"access_token": META,
"fields": "id,name,subtype,approximate_count,lookalike_spec,description",
"limit": 50,
},
).json().get("data", [])
lookalikes = [a for a in audiences if a.get("subtype") == "LOOKALIKE"]
print(f"Lookalike audiences: {len(lookalikes)}")
# 2. Get seed audience details
seeds = {}
for la in lookalikes[:5]:
spec = la.get("lookalike_spec", {})
origin_id = spec.get("origin", [{}])[0].get("id") if isinstance(spec.get("origin"), list) else None
if not origin_id:
continue
seed_info = requests.get(
f"{GRAPH}/{origin_id}",
params={"access_token": META, "fields": "id,name,approximate_count,description,subtype"},
).json()
seeds[la["id"]] = {
"lookalike_name": la["name"],
"seed_name": seed_info.get("name", "Unknown"),
"seed_size": seed_info.get("approximate_count", 0),
"seed_description": seed_info.get("description", ""),
"ratio": spec.get("ratio", 0.01),
"country": spec.get("country", "US"),
}
# 3. Get demographic insights on ads using these lookalikes
for la_id, seed in seeds.items():
insights = requests.get(
f"{GRAPH}/{ACCT}/insights",
params={
"access_token": META,
"fields": "impressions,clicks,ctr,actions",
"breakdowns": "age,gender",
"filtering": f'[{{"field":"audience","operator":"CONTAIN","value":"{la_id}"}}]',
"date_preset": "last_90d",
"limit": 50,
},
).json().get("data", [])
top_demos = sorted(insights, key=lambda x: int(x.get("clicks", 0)), reverse=True)[:5]
seed["top_demographics"] = [
{"age": d.get("age"), "gender": d.get("gender"), "clicks": d.get("clicks")}
for d in top_demos
]
time.sleep(0.5)
# 4. Create seed personas
seed_personas = []
for la_id, seed in seeds.items():
demo_desc = ", ".join(
f"{d['gender']} {d['age']} ({d['clicks']} clicks)"
for d in seed.get("top_demographics", [])[:3]
)
persona = requests.post(f"{MB}/personas", headers=MH, json={
"name": f"Seed: {seed['seed_name'][:40]}",
"description": (
f"Seed audience for lookalike '{seed['lookalike_name']}'. "
f"Size: {seed['seed_size']:,}. Country: {seed['country']}. "
f"Top converting demographics: {demo_desc}. "
f"{seed['seed_description']}"
),
"demographic": {
"top_segments": seed.get("top_demographics", []),
"country": seed["country"],
},
}).json()
seed_personas.append({
"persona_id": persona["id"],
"seed_name": seed["seed_name"],
"lookalike_name": seed["lookalike_name"],
})
time.sleep(0.3)
# 5. Mave: identify adjacent expansion segments
seed_summary = "\n".join(
f"- Seed \"{sp['seed_name']}\" → Lookalike \"{sp['lookalike_name']}\""
for sp in seed_personas
)
demo_summary = "\n".join(
f" {s['seed_name']}: {', '.join(f\"{d['gender']} {d['age']}\" for d in s.get('top_demographics',[])[:3])}"
for s in seeds.values()
)
expansion = requests.post(f"{MB}/mave/chat", headers=MH, json={
"message": f"""Analyze these Meta Ads seed audiences and identify adjacent segments for expansion.
SEED AUDIENCES:
{seed_summary}
CONVERTING DEMOGRAPHICS:
{demo_summary}
For each seed audience:
1. What adjacent demographic segments are likely to convert but aren't in the current seed?
2. What psychographic traits unite the converting demographics?
3. Suggest 3-4 expansion personas (new segments to test) with:
- Name, age range, gender, interests
- Why they're adjacent to the seed audience
- Estimated overlap with current targeting (low/medium/high)
- Recommended ad angle for this segment
4. Which expansion segment should be tested first and why?"""
}).json()
print("\n=== Expansion Analysis ===")
print(expansion.get("content", "")[:2000])
# 6. Create expansion personas from Mave's recommendations
expansion_prompt = requests.post(f"{MB}/mave/chat", headers=MH, json={
"message": f"""Based on your expansion analysis, output exactly 4 expansion personas in this format:
Name: [persona name]
Age: [range]
Gender: [any/male/female]
Interests: [comma-separated]
Description: [2 sentences]
Only output the 4 personas, no other text."""
}).json()
expansion_text = expansion_prompt.get("content", "")
personas_blocks = [b.strip() for b in expansion_text.split("\n\n") if b.strip().startswith("Name:")]
expansion_personas = []
for block in personas_blocks[:4]:
lines = {l.split(":")[0].strip(): ":".join(l.split(":")[1:]).strip()
for l in block.split("\n") if ":" in l}
if not lines.get("Name"):
continue
p = requests.post(f"{MB}/personas", headers=MH, json={
"name": f"Expansion: {lines['Name']}",
"description": lines.get("Description", "Expansion segment from Mave analysis."),
"demographic": {
"age_range": lines.get("Age", "25-54"),
"gender": lines.get("Gender", "any"),
"interests": [i.strip() for i in lines.get("Interests", "").split(",")],
},
}).json()
expansion_personas.append({"name": lines["Name"], "id": p["id"]})
time.sleep(0.3)
print(f"\nCreated {len(expansion_personas)} expansion personas:")
for ep in expansion_personas:
print(f" {ep['name']} → {ep['id']}")