Systems Library / Marketing Automation / How to Automate Weekly Ad Performance Summaries
Marketing Automation paid advertising

How to Automate Weekly Ad Performance Summaries

Generate and send weekly ad performance summaries to clients automatically.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

When you automate your weekly ad report email summary, clients get consistent updates without you spending Friday afternoons building slide decks. I send these to every client. The script pulls data, generates insights with AI, and sends a formatted email by 9 AM Monday.

Clients love it because it is reliable. I love it because it takes zero time once built.

What You Need Before Starting

Step 1: Pull Weekly Performance Data

import sqlite3
from datetime import datetime, timedelta

def get_weekly_data(db_path, account_name):
    conn = sqlite3.connect(db_path)
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
    
    summary = conn.execute("""
        SELECT SUM(spend), SUM(impressions), SUM(clicks), SUM(leads),
            SUM(purchases), SUM(purchase_value),
            CASE WHEN SUM(clicks)>0 THEN SUM(spend)/SUM(clicks) ELSE 0 END,
            CASE WHEN SUM(leads)>0 THEN SUM(spend)/SUM(leads) ELSE 0 END
        FROM ad_daily
        WHERE account_name = ? AND date BETWEEN ? AND ?
    """, (account_name, start_date, end_date)).fetchone()
    
    prev_start = (datetime.now() - timedelta(days=14)).strftime("%Y-%m-%d")
    prev_end = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
    
    prev_summary = conn.execute("""
        SELECT SUM(spend), SUM(impressions), SUM(clicks), SUM(leads),
            SUM(purchases), SUM(purchase_value)
        FROM ad_daily WHERE account_name = ? AND date BETWEEN ? AND ?
    """, (account_name, prev_start, prev_end)).fetchone()
    
    top_ads = conn.execute("""
        SELECT ad_name, SUM(spend), SUM(leads),
            CASE WHEN SUM(leads)>0 THEN SUM(spend)/SUM(leads) ELSE 999 END as cpa
        FROM ad_daily
        WHERE account_name = ? AND date BETWEEN ? AND ?
        GROUP BY ad_name HAVING SUM(spend) > 5
        ORDER BY cpa ASC LIMIT 5
    """, (account_name, start_date, end_date)).fetchall()
    
    conn.close()
    return {"current": summary, "previous": prev_summary, "top_ads": top_ads, "period": f"{start_date} to {end_date}"}

Step 2: Generate AI Insights

import anthropic

def generate_weekly_insight(data):
    client = anthropic.Anthropic()
    
    curr = data["current"]
    prev = data["previous"]
    
    spend_change = ((curr[0] or 0) - (prev[0] or 0)) / (prev[0] or 1) * 100
    lead_change = ((curr[3] or 0) - (prev[3] or 0)) / (prev[3] or 1) * 100
    
    prompt = f"""Write a 3-sentence weekly ad performance insight.

This week: ${curr[0] or 0:.2f} spend, {curr[3] or 0} leads, ${curr[7] or 0:.2f} CPL
Last week: ${prev[0] or 0:.2f} spend, {prev[3] or 0} leads
Spend change: {spend_change:+.1f}%, Lead change: {lead_change:+.1f}%

Top performing ad: {data['top_ads'][0][0] if data['top_ads'] else 'N/A'}

Be direct. No fluff. State what happened, why it matters, and what to do next.
Do not use the words "leverage", "utilize", or "it's important to note"."""

    resp = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=300,
        messages=[{"role": "user", "content": prompt}]
    )
    return resp.content[0].text

Step 3: Build the Email Template

def build_email_html(data, insight):
    curr = data["current"]
    top_ads_html = ""
    for ad in data["top_ads"]:
        top_ads_html += f"<tr><td style='padding:8px;border-bottom:1px solid #eee;'>{ad[0]}</td><td>${ad[1]:.2f}</td><td>{ad[2]}</td><td>${ad[3]:.2f}</td></tr>"
    
    html = f"""
    <div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;">
        <h2 style="color:#333;">Weekly Ad Performance Summary</h2>
        <p style="color:#666;">{data['period']}</p>
        
        <table style="width:100%;border-collapse:collapse;margin:20px 0;">
            <tr style="background:#f5f5f5;">
                <td style="padding:12px;"><strong>Spend</strong><br>${curr[0] or 0:.2f}</td>
                <td style="padding:12px;"><strong>Leads</strong><br>{curr[3] or 0}</td>
                <td style="padding:12px;"><strong>CPL</strong><br>${curr[7] or 0:.2f}</td>
                <td style="padding:12px;"><strong>Clicks</strong><br>{curr[2] or 0}</td>
            </tr>
        </table>
        
        <h3>Insight</h3>
        <p style="color:#333;line-height:1.6;">{insight}</p>
        
        <h3>Top Performing Ads</h3>
        <table style="width:100%;border-collapse:collapse;">
            <tr style="background:#f5f5f5;"><th style="padding:8px;text-align:left;">Ad</th><th>Spend</th><th>Leads</th><th>CPL</th></tr>
            {top_ads_html}
        </table>
    </div>"""
    return html

Step 4: Send the Email

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

def send_report(to_email, subject, html_content):
    smtp_user = os.getenv("GMAIL_ADDRESS")
    smtp_pass = os.getenv("GMAIL_APP_PASSWORD")
    
    msg = MIMEMultipart("alternative")
    msg["Subject"] = subject
    msg["From"] = smtp_user
    msg["To"] = to_email
    msg.attach(MIMEText(html_content, "html"))
    
    with smtplib.SMTP("smtp.gmail.com", 587) as server:
        server.starttls()
        server.login(smtp_user, smtp_pass)
        server.sendmail(smtp_user, to_email, msg.as_string())
    
    print(f"Report sent to {to_email}")

Step 5: Schedule for Monday Morning

if __name__ == "__main__":
    clients = [
        {"name": "Client A", "account": "Client A Account", "email": "[email protected]"},
    ]
    
    for client in clients:
        data = get_weekly_data("meta_ads.db", client["account"])
        insight = generate_weekly_insight(data)
        html = build_email_html(data, insight)
        send_report(client["email"], f"Weekly Ad Report - {data['period']}", html)
# Monday at 9 AM
0 9 * * 1 cd /path/to/project && python3 weekly_report.py

Consistent, data-driven, and automatic. Clients see value every Monday without you lifting a finger.

What to Build Next

Add week-over-week trend charts using matplotlib or a charting library. Then add a "This Week's Plan" section that uses AI to recommend budget shifts and creative tests.

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