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

Over time, you’ve created 20+ segments in Klaviyo — “VIP”, “High CLV”, “Frequent Buyers”, “Loyal Customers” — and many of them overlap significantly. A customer might be in 5 segments at once, receiving redundant messaging. You pull all segments with member counts, identify overlaps, and send the data to Mave for analysis. The result is a simplified segmentation strategy that eliminates redundancy.

Architecture

Code

import os, requests, time

KL_KEY = os.environ["KLAVIYO_API_KEY"]
MV = os.environ["MAVERA_API_KEY"]
MB = "https://app.mavera.io/api/v1"
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
KH = {
    "Authorization": f"Klaviyo-API-Key {KL_KEY}",
    "Content-Type": "application/json",
    "revision": "2024-10-15",
}

segments = []
url = "https://a.klaviyo.com/api/segments"
params = {"fields[segment]": "name,definition,created,updated,is_active,profile_count"}

for page_num in range(3):
    r = requests.get(url, headers=KH, params=params if page_num == 0 else None)
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", 10)))
        continue
    r.raise_for_status()
    data = r.json()
    segments.extend(data.get("data", []))
    url = data.get("links", {}).get("next")
    if not url:
        break
    params = None
    time.sleep(0.5)

print(f"Found {len(segments)} segments\n")

segment_info = []
for seg in segments:
    attrs = seg.get("attributes", {})
    segment_info.append({
        "id": seg["id"],
        "name": attrs.get("name", ""),
        "count": attrs.get("profile_count", 0),
        "active": attrs.get("is_active", True),
        "definition": str(attrs.get("definition", ""))[:200],
        "created": attrs.get("created", "")[:10],
        "updated": attrs.get("updated", "")[:10],
    })

segment_info.sort(key=lambda s: s["count"], reverse=True)
total_profiles = sum(s["count"] for s in segment_info)

segment_block = "\n".join(
    f"- **{s['name']}**: {s['count']:,} profiles | Active: {s['active']} | Created: {s['created']}\n"
    f"  Definition: {s['definition'][:150]}{'...' if len(s['definition']) > 150 else ''}"
    for s in segment_info
)

mave = requests.post(f"{MB}/mave/chat", headers=MH, json={
    "message": f"""Analyze our Klaviyo segments for redundancy and recommend a simplified segmentation strategy.

CURRENT SEGMENTS ({len(segment_info)} total, {total_profiles:,} total profile memberships):

{segment_block}

Analyze:
1. Which segments likely have significant overlap? (based on names, definitions, and member counts)
2. Which segments are redundant and could be merged? Suggest specific merges.
3. Are there gaps — behavioral groups that should have segments but don't?
4. Recommend a simplified structure with max 8-10 segments. Name each and describe its purpose.
5. Which segments are stale (created long ago, rarely updated) and should be archived?
6. How should these segments map to email/SMS flows?

Goal: Reduce segment count by 40-60% while maintaining targeting precision.""",
}).json()

print("--- Segment Overlap Analysis ---")
print(mave.get("content", "")[:3000])

Example Output

--- Segment Overlap Analysis ---

## Likely Overlaps
| Segments | Est. Overlap | Recommendation |
|----------|-------------|----------------|
| "VIP" + "High CLV" + "Loyal" | ~70% overlap | Merge into "Top Customers" |
| "Recent Buyers" + "Active 30d" | ~85% overlap | "Recent Buyers" subsumes both |
| "Newsletter" + "All Subscribers" | ~95% overlap | Archive "All Subscribers" |

## Recommended Simplified Structure (8 segments)
1. **Top Customers** — CLV > $500, 3+ orders (merge VIP + High CLV + Loyal)
2. **Growth Customers** — 2+ orders, CLV $100-500
3. **New Customers** — First order in last 30 days
4. **At Risk** — Churn risk > 50%, was active in last 90d
5. **Win Back** — No order in 90+ days, had 2+ previous orders
6. **Browse Abandoners** — Viewed products, no cart/purchase in 7d
7. **Cart Abandoners** — Active cart, no purchase in 24h
8. **Engaged Non-Buyers** — Opens/clicks emails, never purchased

## Stale Segments to Archive
- "Holiday 2024 Shoppers" (created 2024-11-15, never updated)
- "Beta Testers" (created 2024-03-01, 12 profiles)
- "Imported List 3" (created 2024-06-01, unknown purpose)

## Flow Mapping
| Segment | Flow | Cadence |
|---------|------|---------|
| New Customers | Welcome + education | 5 emails / 14 days |
| At Risk | Win-back | 3 emails / 10 days |
| Top Customers | VIP exclusives | 1 email / week |
| Browse Abandoners | Product nudge | 2 emails / 3 days |

Error Handling

Klaviyo segment definitions use a nested JSON structure for conditions. The code truncates to 200 chars for readability. For precise overlap analysis, compare the actual condition logic, not just names.
The profile_count field updates asynchronously. It may lag behind real-time segment membership by minutes to hours. For exact counts, query the Profiles endpoint filtered by segment.
Klaviyo returns segments paginated. The code fetches up to 3 pages (~300 segments). If you have more, increase the page loop or use a higher page[size].

What’s Next

Klaviyo Integration

Back to Klaviyo integration overview

Flow Content Refresh

Rewrite underperforming flow content

Product Affinity Focus Group

Cross-sell validation with Likert + NPS

Mave Agent

Full reference for POST /api/v1/mave/chat