> ## 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.

# Landing Page Performance → Content Refresh

> Pull underperforming high-traffic landing pages from GA4 and use Mavera Generate to rewrite copy for specific audience segments with brand voice

### Scenario

Your top landing pages are underperforming — high traffic but poor engagement or high bounce rates. You pull the worst-performing high-traffic pages from GA4, then use Mavera's Generate endpoint to rewrite the copy for a specific audience segment, applying your brand voice. The result is refreshed landing page copy informed by actual performance data.

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A["GA4 RunReport (landingPage + bounceRate + engagement)"] --> B["Filter: high traffic + low engagement"] --> C["POST /api/v1/generations"] --> D[Audience-targeted copy rewrites]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests
  from google.analytics.data_v1beta import BetaAnalyticsDataClient
  from google.analytics.data_v1beta.types import (
      RunReportRequest, Dimension, Metric, DateRange, OrderBy, FilterExpression,
      Filter,
  )

  PROPERTY_ID = os.environ["GA4_PROPERTY_ID"]
  MV = os.environ["MAVERA_API_KEY"]
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  client = BetaAnalyticsDataClient()

  report = client.run_report(RunReportRequest(
      property=f"properties/{PROPERTY_ID}",
      dimensions=[Dimension(name="landingPage")],
      metrics=[
          Metric(name="totalUsers"),
          Metric(name="bounceRate"),
          Metric(name="engagementRate"),
          Metric(name="averageSessionDuration"),
          Metric(name="conversions"),
          Metric(name="screenPageViews"),
      ],
      date_ranges=[DateRange(start_date="30daysAgo", end_date="today")],
      dimension_filter=FilterExpression(filter=Filter(
          field_name="landingPage",
          string_filter=Filter.StringFilter(
              match_type=Filter.StringFilter.MatchType.BEGINS_WITH,
              value="/",
          ),
      )),
      order_bys=[OrderBy(metric=OrderBy.MetricOrderBy(metric_name="totalUsers"), desc=True)],
      limit=50,
  ))

  pages = []
  for row in report.rows:
      path = row.dimension_values[0].value
      users = int(row.metric_values[0].value)
      bounce = float(row.metric_values[1].value)
      engagement = float(row.metric_values[2].value)
      duration = float(row.metric_values[3].value)
      conversions = int(row.metric_values[4].value)
      views = int(row.metric_values[5].value)

      if users < 100:
          continue

      pages.append({
          "path": path, "users": users, "bounce": bounce,
          "engagement": engagement, "duration": duration,
          "conversions": conversions, "views": views,
          "conv_rate": conversions / max(users, 1),
      })

  needs_refresh = [p for p in pages if p["bounce"] > 0.6 or p["engagement"] < 0.4]
  needs_refresh.sort(key=lambda p: p["users"], reverse=True)

  BRAND_VOICE_ID = os.environ.get("BRAND_VOICE_ID", "")
  AUDIENCE = "B2B marketing directors at mid-market SaaS companies (200–2000 employees)"

  print(f"Pages needing refresh: {len(needs_refresh)} of {len(pages)} total\n")

  for page in needs_refresh[:5]:
      prompt = (
          f"Rewrite the landing page copy for this URL path: {page['path']}\n\n"
          f"CURRENT PERFORMANCE (last 30 days):\n"
          f"- Users: {page['users']}\n"
          f"- Bounce rate: {page['bounce']:.0%}\n"
          f"- Engagement rate: {page['engagement']:.0%}\n"
          f"- Avg session duration: {page['duration']:.0f}s\n"
          f"- Conversion rate: {page['conv_rate']:.2%}\n\n"
          f"TARGET AUDIENCE: {AUDIENCE}\n\n"
          f"Generate:\n"
          f"1. New H1 headline (max 10 words)\n"
          f"2. Sub-headline (max 20 words)\n"
          f"3. 3 benefit bullet points (max 15 words each)\n"
          f"4. CTA button text (max 5 words)\n"
          f"5. Social proof line (max 15 words)\n\n"
          f"The current copy has a {page['bounce']:.0%} bounce rate — the rewrite must hook visitors in 3 seconds."
      )

      payload = {"prompt": prompt}
      if BRAND_VOICE_ID:
          payload["brand_voice_id"] = BRAND_VOICE_ID

      gen = requests.post(f"{MB}/generations", headers=MH, json=payload).json()

      print(f"{'='*50}")
      print(f"Page: {page['path']}")
      print(f"Users: {page['users']} | Bounce: {page['bounce']:.0%} | Engagement: {page['engagement']:.0%}")
      print(f"{'='*50}")
      print(gen.get("output", gen.get("content", ""))[:600])
      print()
  ```

  ```javascript JavaScript theme={"dark"}
  const MV = process.env.MAVERA_API_KEY;
  const PROPERTY_ID = process.env.GA4_PROPERTY_ID;
  const KEY_FILE = JSON.parse(require("fs").readFileSync(process.env.GOOGLE_APPLICATION_CREDENTIALS, "utf8"));
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
  const BRAND_VOICE_ID = process.env.BRAND_VOICE_ID || "";

  const { GoogleAuth } = require("google-auth-library");
  const auth = new GoogleAuth({
    credentials: KEY_FILE,
    scopes: ["https://www.googleapis.com/auth/analytics.readonly"],
  });
  const accessToken = await auth.getAccessToken();

  const gaRes = await fetch(
    `https://analyticsdata.googleapis.com/v1beta/properties/${PROPERTY_ID}:runReport`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        dimensions: [{ name: "landingPage" }],
        metrics: [
          { name: "totalUsers" }, { name: "bounceRate" },
          { name: "engagementRate" }, { name: "averageSessionDuration" },
          { name: "conversions" }, { name: "screenPageViews" },
        ],
        dateRanges: [{ startDate: "30daysAgo", endDate: "today" }],
        orderBys: [{ metric: { metricName: "totalUsers" }, desc: true }],
        limit: 50,
      }),
    }
  ).then((r) => r.json());

  const pages = (gaRes.rows || [])
    .map((row) => ({
      path: row.dimensionValues[0].value,
      users: parseInt(row.metricValues[0].value),
      bounce: parseFloat(row.metricValues[1].value),
      engagement: parseFloat(row.metricValues[2].value),
      duration: parseFloat(row.metricValues[3].value),
      conversions: parseInt(row.metricValues[4].value),
    }))
    .filter((p) => p.users >= 100);

  const needsRefresh = pages
    .filter((p) => p.bounce > 0.6 || p.engagement < 0.4)
    .sort((a, b) => b.users - a.users);

  const AUDIENCE = "B2B marketing directors at mid-market SaaS (200–2000 employees)";

  console.log(`Pages needing refresh: ${needsRefresh.length} of ${pages.length}\n`);

  for (const page of needsRefresh.slice(0, 5)) {
    const convRate = page.conversions / (page.users || 1);
    const payload = {
      prompt:
        `Rewrite landing page copy for ${page.path}.\n\n` +
        `PERFORMANCE: Users: ${page.users}, Bounce: ${(page.bounce * 100).toFixed(0)}%, ` +
        `Engagement: ${(page.engagement * 100).toFixed(0)}%, Conv: ${(convRate * 100).toFixed(2)}%\n\n` +
        `AUDIENCE: ${AUDIENCE}\n\n` +
        `Generate: 1) H1 headline 2) Sub-headline 3) 3 benefit bullets 4) CTA text 5) Social proof line`,
    };
    if (BRAND_VOICE_ID) payload.brand_voice_id = BRAND_VOICE_ID;

    const gen = await fetch(`${MB}/generations`, {
      method: "POST", headers: MH, body: JSON.stringify(payload),
    }).then((r) => r.json());

    console.log(`${"=".repeat(50)}`);
    console.log(`Page: ${page.path} | Bounce: ${(page.bounce * 100).toFixed(0)}% | Users: ${page.users}`);
    console.log((gen.output || gen.content || "").slice(0, 600));
    console.log();
  }
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
Pages needing refresh: 8 of 34

==================================================
Page: /features/analytics
Users: 2,340 | Bounce: 72% | Engagement: 31%
==================================================
1. H1: Stop Guessing. Start Knowing Your Audience.
2. Sub: Real-time persona intelligence that turns GA4 data into
   actionable content strategy.
3. Benefits:
   - Build personas from your actual converting demographics
   - Test messaging with synthetic focus groups before launch
   - Generate brand-aligned content in minutes, not weeks
4. CTA: Start Free — No Credit Card
5. Social proof: Trusted by 2,000+ marketing teams at companies like
   Notion, Figma, and Ramp.
```

### Error Handling

<AccordionGroup>
  <Accordion title="Landing page paths vs full URLs">GA4 reports `landingPage` as path only (e.g. `/pricing`), not full URLs. If you need to pass actual page content to Generate, fetch the page HTML separately or maintain a content map.</Accordion>
  <Accordion title="Brand voice not found">If `BRAND_VOICE_ID` is invalid, the Generate call returns 404. Omit the field to use Mavera's default voice, or create a voice first via `POST /api/v1/brand-voices`.</Accordion>
  <Accordion title="Bounce rate interpretation in GA4">GA4's bounce rate = 100% minus engagement rate. A "bounced" session has no engagement events, lasts under 10 seconds, and has no conversions. This differs from Universal Analytics.</Accordion>
</AccordionGroup>

***

## What's Next

<CardGroup cols={2}>
  <Card title="GA4 Integration" icon="chart-line" href="/integrations/ga4">
    Back to GA4 integration overview
  </Card>

  <Card title="Conversion Path → Focus Group Validation" icon="comments" href="/integrations/ga4/conversion-focus-group">
    Validate funnel drop-offs with focus groups
  </Card>

  <Card title="Real-Time Audience → Trending Response" icon="bolt" href="/integrations/ga4/realtime-trending-response">
    Diagnose traffic spikes in real time
  </Card>

  <Card title="Generate API" icon="wand-magic-sparkles" href="/api-reference/generations">
    Full reference for POST /api/v1/generations
  </Card>
</CardGroup>
