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

Customers at your downtown café are different from customers at your suburban location. Downtown draws office workers during lunch; suburbs get families on weekends. You extract review text with location context, identify distinct customer profiles per location, then create geo-specific Mavera personas. These local personas power hyper-targeted marketing for each location. Flow: Google reviews + location data → Identify per-location customer profiles → Mavera POST /personas → Geo-specific personas

Code

import os, requests, time, re
from collections import Counter

GOOG = os.environ["GOOGLE_ACCESS_TOKEN"]
ACCT = os.environ["GOOGLE_ACCOUNT_ID"]
MV = os.environ["MAVERA_API_KEY"]
GB_BASE = "https://mybusiness.googleapis.com/v4"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
GB_H = {"Authorization": f"Bearer {GOOG}"}
STAR_MAP = {"ONE": 1, "TWO": 2, "THREE": 3, "FOUR": 4, "FIVE": 5}

# 1. Locations + reviews
locations = requests.get(f"{GB_BASE}/{ACCT}/locations",
    headers=GB_H, params={"pageSize": 100}).json().get("locations", [])

persona_ids = []
for loc in locations[:8]:
    loc_id = loc.get("name", "")
    loc_name = loc.get("locationName", "Unknown")
    city = loc.get("address", {}).get("locality", "Unknown")
    state = loc.get("address", {}).get("administrativeArea", "")
    category = loc.get("primaryCategory", {}).get("displayName", "Business")

    r = requests.get(f"{GB_BASE}/{loc_id}/reviews",
        headers=GB_H, params={"pageSize": 50})
    if r.status_code != 200:
        continue
    reviews = r.json().get("reviews", [])

    if len(reviews) < 5:
        continue

    # 2. Extract customer signals from review text
    all_text = " ".join(rev.get("comment", "") for rev in reviews).lower()
    signals = {
        "family": len(re.findall(r'\b(family|kids|children|stroller)\b', all_text)),
        "business": len(re.findall(r'\b(meeting|office|work|lunch break|colleague)\b', all_text)),
        "tourist": len(re.findall(r'\b(tourist|visiting|trip|vacation|hotel)\b', all_text)),
        "local_regular": len(re.findall(r'\b(regular|every week|always come|our spot)\b', all_text)),
        "date_night": len(re.findall(r'\b(date|anniversary|romantic|evening)\b', all_text)),
    }
    dominant_segment = max(signals, key=signals.get) if any(signals.values()) else "general"

    avg_rating = sum(STAR_MAP.get(r.get("starRating", "FIVE"), 5) for r in reviews) / len(reviews)

    # 3. Create geo-specific persona
    sample_quotes = [rev.get("comment", "")[:150] for rev in reviews if rev.get("comment")][:3]

    p = requests.post("https://app.mavera.io/api/v1/personas", headers=MV_H, json={
        "name": f"GBP: {loc_name}{dominant_segment.replace('_', ' ').title()}",
        "description": (
            f"Customer of {loc_name} in {city}, {state}. Category: {category}. "
            f"N={len(reviews)} reviews, avg {avg_rating:.1f}/5. "
            f"Dominant segment: {dominant_segment}. "
            f"Signal scores: {', '.join(f'{k}: {v}' for k, v in sorted(signals.items(), key=lambda x: -x[1])[:3])}. "
            f"Sample: \"{sample_quotes[0][:100]}...\""
        ),
        "demographic": {
            "location": f"{city}, {state}",
            "customer_type": dominant_segment,
        },
        "psychographic": {
            "visit_context": dominant_segment,
            "satisfaction": "high" if avg_rating >= 4 else "mixed" if avg_rating >= 3 else "low",
        },
    }).json()
    persona_ids.append({"id": p["id"], "location": loc_name, "city": city, "segment": dominant_segment})
    print(f"Persona: {p['id']}{loc_name} ({city}) → {dominant_segment}")
    time.sleep(0.5)

print(f"\nCreated {len(persona_ids)} local personas")

Example Output

{
  "personas_created": 5,
  "local_profiles": [
    { "location": "Downtown Café", "city": "Austin", "segment": "business", "avg_rating": 4.5,
      "insight": "Office workers on lunch. Care about speed, Wi-Fi, quiet spaces." },
    { "location": "Suburban Store", "city": "Round Rock", "segment": "family", "avg_rating": 4.1,
      "insight": "Families on weekends. Care about kid-friendliness, parking, portion sizes." },
    { "location": "Airport Kiosk", "city": "Austin", "segment": "tourist", "avg_rating": 3.7,
      "insight": "Travelers in a hurry. Care about grab-and-go, clear pricing, speed." },
    { "location": "University Ave", "city": "Austin", "segment": "local_regular", "avg_rating": 4.6,
      "insight": "Regulars who come weekly. Care about consistency, loyalty, and knowing the staff." }
  ]
}

Error Handling

Each location requires separate review API calls. Batch across locations with delays to stay within 300 req/min.
Some Google reviews are ratings-only with no text. Filter comment: null reviews before persona creation.
Simple keyword matching for segments is approximate. For better accuracy, send review text to Mave for classification.