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 Google Ads account has thousands of actual search queries that triggered your ads — real language from real buyers. Instead of guessing what content to write, you pull the top 100 search terms by impressions, send them to Mave with the instruction to cluster by intent, and get back a content strategy mapped to how people actually search. The result is a content calendar grounded in paid search data.

Architecture

Code

import os, requests
from google.ads.googleads.client import GoogleAdsClient

MV = os.environ["MAVERA_API_KEY"]
CUSTOMER_ID = os.environ["GOOGLE_ADS_CUSTOMER_ID"]

client = GoogleAdsClient.load_from_env()
ga_service = client.get_service("GoogleAdsService")

query = """
    SELECT
        search_term_view.search_term,
        metrics.impressions,
        metrics.clicks,
        metrics.conversions,
        metrics.cost_micros
    FROM search_term_view
    WHERE segments.date DURING LAST_30_DAYS
        AND metrics.impressions > 10
    ORDER BY metrics.impressions DESC
    LIMIT 100
"""

response = ga_service.search(customer_id=CUSTOMER_ID, query=query)

terms = []
for row in response:
    stv = row.search_term_view
    m = row.metrics
    terms.append({
        "term": stv.search_term,
        "impressions": m.impressions,
        "clicks": m.clicks,
        "conversions": m.conversions,
        "cost": m.cost_micros / 1_000_000,
    })

term_block = "\n".join(
    f"- \"{t['term']}\" (imp: {t['impressions']}, clicks: {t['clicks']}, conv: {t['conversions']:.0f}, cost: ${t['cost']:.2f})"
    for t in terms
)

mave = requests.post(
    "https://app.mavera.io/api/v1/mave/chat",
    headers={"Authorization": f"Bearer {MV}", "Content-Type": "application/json"},
    json={"message": f"""Cluster these {len(terms)} Google Ads search terms by user intent.

For each cluster:
1. Cluster name and intent type (informational, navigational, commercial, transactional)
2. Representative terms
3. Total impressions and conversions for the cluster
4. Recommended content type (blog post, landing page, comparison guide, tutorial, etc.)
5. Suggested title and angle

Prioritize clusters by conversion potential.

SEARCH TERMS:
{term_block}"""},
).json()

print("--- Search Term Content Strategy ---")
print(mave.get("content", "")[:3000])
print(f"\nSources: {len(mave.get('sources', []))}")

Example Output

--- Search Term Content Strategy ---

## Cluster 1: Evaluation / Comparison (Transactional)
Terms: "best crm for startups", "hubspot vs salesforce pricing", "crm comparison 2026"
Impressions: 8,420 | Conversions: 34
→ Content: Comparison landing page
→ Title: "CRM Comparison Guide: Features, Pricing, and Fit for Growing Teams"

## Cluster 2: How-To / Implementation (Informational)
Terms: "how to set up crm pipeline", "crm automation examples", "lead scoring setup"
Impressions: 12,300 | Conversions: 12
→ Content: Tutorial blog series
→ Title: "How to Build a CRM Pipeline That Actually Converts"

## Cluster 3: Problem-Aware (Commercial)
Terms: "sales team losing deals", "pipeline visibility tool", "forecast accuracy software"
Impressions: 5,100 | Conversions: 28
→ Content: Problem/solution landing page
→ Title: "Why Your Sales Team Keeps Losing Deals (and How to Fix It)"

Sources: 3

Error Handling

Invalid field names or date ranges return QUERY_ERROR. Test queries in the Google Ads Query Builder.
New campaigns or Smart campaigns may not expose search terms. Ensure campaigns use manual or broad-match keywords with search term reporting enabled.
Pass the 10-digit ID without dashes. The Python client strips dashes automatically; the REST API does not.

All Google Ads jobs

View all 7 Google Ads integration jobs

Mave Agent

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