Systems Library / Marketing Automation / How to Create Automated Content Performance Reports
Marketing Automation content marketing

How to Create Automated Content Performance Reports

Track and report on content performance metrics automatically.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

I stopped manually pulling content metrics when I realized I was spending three hours a week on a report nobody acted on. This automated content performance report analytics system pulls data from Google Analytics, runs it through Claude for interpretation, and emails a plain-English summary every Monday morning. The report tells you what is working, what is dying, and what to do next week.

The difference between a good content team and a great one is not the volume of content they publish. It is whether they know what is working and double down on it fast. This report makes that loop run on autopilot.

What You Need Before Starting

Step 1: Set Up Google Analytics API Access

First, enable the Google Analytics Data API in your Google Cloud Console. Then download your service account key and store the path in your .env:

ANTHROPIC_API_KEY=your_key_here
GA4_PROPERTY_ID=123456789
GOOGLE_CREDENTIALS_PATH=C:/path/to/service-account.json
[email protected]

Then initialize the GA4 client:

import os
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
    RunReportRequest, DateRange, Dimension, Metric, OrderBy
)
from google.oauth2 import service_account
from dotenv import load_dotenv

load_dotenv()

def get_ga4_client():
    credentials = service_account.Credentials.from_service_account_file(
        os.getenv("GOOGLE_CREDENTIALS_PATH"),
        scopes=["https://www.googleapis.com/auth/analytics.readonly"]
    )
    return BetaAnalyticsDataClient(credentials=credentials)

Step 2: Pull Top Content Performance Data

def get_top_content(client, property_id: str, days: int = 30) -> list:
    request = RunReportRequest(
        property=f"properties/{property_id}",
        date_ranges=[DateRange(start_date=f"{days}daysAgo", end_date="today")],
        dimensions=[
            Dimension(name="pagePath"),
            Dimension(name="pageTitle")
        ],
        metrics=[
            Metric(name="screenPageViews"),
            Metric(name="averageSessionDuration"),
            Metric(name="bounceRate"),
            Metric(name="newUsers")
        ],
        order_bys=[
            OrderBy(metric=OrderBy.MetricOrderBy(metric_name="screenPageViews"), desc=True)
        ],
        limit=20
    )
    
    response = client.run_report(request)
    
    results = []
    for row in response.rows:
        results.append({
            "path": row.dimension_values[0].value,
            "title": row.dimension_values[1].value,
            "pageviews": int(row.metric_values[0].value),
            "avg_duration_sec": float(row.metric_values[1].value),
            "bounce_rate": float(row.metric_values[2].value),
            "new_users": int(row.metric_values[3].value)
        })
    
    return results

Step 3: Get Traffic Trend Data

You need week-over-week comparison to spot momentum:

def get_traffic_trend(client, property_id: str) -> dict:
    def fetch_period(start, end):
        request = RunReportRequest(
            property=f"properties/{property_id}",
            date_ranges=[DateRange(start_date=start, end_date=end)],
            metrics=[
                Metric(name="screenPageViews"),
                Metric(name="newUsers"),
                Metric(name="sessions")
            ]
        )
        response = client.run_report(request)
        row = response.rows[0]
        return {
            "pageviews": int(row.metric_values[0].value),
            "new_users": int(row.metric_values[1].value),
            "sessions": int(row.metric_values[2].value)
        }
    
    this_week = fetch_period("7daysAgo", "today")
    last_week = fetch_period("14daysAgo", "8daysAgo")
    
    def pct_change(current, previous):
        if previous == 0:
            return 0
        return round(((current - previous) / previous) * 100, 1)
    
    return {
        "this_week": this_week,
        "last_week": last_week,
        "pageviews_change": pct_change(this_week["pageviews"], last_week["pageviews"]),
        "new_users_change": pct_change(this_week["new_users"], last_week["new_users"]),
        "sessions_change": pct_change(this_week["sessions"], last_week["sessions"])
    }

Step 4: Generate AI Interpretation

Raw numbers are not a report. This is where Claude turns the data into decisions:

import anthropic
import json

ai_client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

def generate_insights(top_content: list, trend: dict) -> str:
    top_5 = top_content[:5]
    content_summary = json.dumps(top_5, indent=2)
    
    prompt = f"""You are a content analytics expert. Analyze this data and write a concise performance report.

WEEKLY TRAFFIC TREND:
- Pageviews this week: {trend['this_week']['pageviews']} ({trend['pageviews_change']:+}% vs last week)
- New users this week: {trend['this_week']['new_users']} ({trend['new_users_change']:+}% vs last week)
- Sessions this week: {trend['this_week']['sessions']} ({trend['sessions_change']:+}% vs last week)

TOP 5 CONTENT PIECES (last 30 days):
{content_summary}

Write a report with these sections:

## This Week's Summary
[2-3 sentences. Overall health. Is traffic growing or declining? What is the trend saying?]

## Top Performers
[List top 3 pieces with one insight about WHY each is likely performing well based on the metrics]

## Warning Signs
[Any pieces with high pageviews but high bounce rate or low session duration that need work]

## Action Items for Next Week
[3 specific, actionable recommendations based on the data. Not generic advice.]

Keep it short. Executives read this. No fluff."""

    message = ai_client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1000,
        messages=[{"role": "user", "content": prompt}]
    )
    
    return message.content[0].text

Step 5: Send the Report by Email

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from datetime import datetime

def send_report(report_text: str):
    sender = os.getenv("GMAIL_ADDRESS")
    password = os.getenv("GMAIL_APP_PASSWORD")
    recipient = os.getenv("REPORT_EMAIL")
    
    today = datetime.now().strftime("%B %d, %Y")
    
    msg = MIMEMultipart("alternative")
    msg["Subject"] = f"Content Performance Report - Week of {today}"
    msg["From"] = sender
    msg["To"] = recipient
    
    msg.attach(MIMEText(report_text, "plain"))
    
    with smtplib.SMTP("smtp.gmail.com", 587) as server:
        server.starttls()
        server.login(sender, password)
        server.sendmail(sender, recipient, msg.as_string())
    
    print(f"Report sent to {recipient}")

if __name__ == "__main__":
    ga_client = get_ga4_client()
    property_id = os.getenv("GA4_PROPERTY_ID")
    
    top_content = get_top_content(ga_client, property_id, days=30)
    trend = get_traffic_trend(ga_client, property_id)
    report = generate_insights(top_content, trend)
    
    print(report)
    send_report(report)

What to Build Next

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems