Systems Library / Marketing Automation / How to Automate Ad Account Health Monitoring
Marketing Automation paid advertising

How to Automate Ad Account Health Monitoring

Monitor ad account health metrics and get alerts before issues impact performance.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Ad account health monitoring with automated alerts catches problems before they snowball. I have seen accounts get restricted, pixels break, and billing fail silently. By the time someone noticed, the damage was done. This system checks everything daily and pings you the moment something is off.

The checks take seconds to run. The problems they catch save days of lost performance.

What You Need Before Starting

Step 1: Define Health Checks

HEALTH_CHECKS = {
    "account_status": True,
    "payment_method": True,
    "pixel_health": True,
    "spend_anomaly": True,
    "delivery_issues": True,
    "policy_violations": True,
}

ACCOUNTS = [
    {"id": "act_123456789", "name": "Client A", "expected_daily_spend": 50},
    {"id": "act_987654321", "name": "Client B", "expected_daily_spend": 100},
]

Step 2: Check Account Status and Billing

import requests
import os

def check_account_status(account_id):
    token = os.getenv("META_ACCESS_TOKEN")
    resp = requests.get(f"https://graph.facebook.com/v19.0/{account_id}",
        params={"access_token": token, "fields": "account_status,disable_reason,name,balance,currency"})
    data = resp.json()
    
    issues = []
    status = data.get("account_status")
    
    # 1=Active, 2=Disabled, 3=Unsettled, 7=Pending Review, 9=In Grace Period
    status_map = {1: "Active", 2: "Disabled", 3: "Unsettled", 7: "Pending Review", 9: "Grace Period"}
    
    if status != 1:
        issues.append({
            "check": "account_status",
            "level": "critical",
            "message": f"Account status: {status_map.get(status, 'Unknown')} (code {status})"
        })
    
    if data.get("disable_reason"):
        issues.append({
            "check": "disable_reason",
            "level": "critical",
            "message": f"Disable reason: {data['disable_reason']}"
        })
    
    return issues

Step 3: Check Pixel Health

def check_pixel_health(pixel_id):
    token = os.getenv("META_ACCESS_TOKEN")
    resp = requests.get(f"https://graph.facebook.com/v19.0/{pixel_id}",
        params={"access_token": token, "fields": "name,last_fired_time,is_unavailable"})
    data = resp.json()
    
    issues = []
    
    if data.get("is_unavailable"):
        issues.append({
            "check": "pixel_health",
            "level": "critical",
            "message": f"Pixel {pixel_id} is unavailable"
        })
    
    last_fired = data.get("last_fired_time")
    if last_fired:
        from datetime import datetime
        last_fire_dt = datetime.fromisoformat(last_fired.replace("Z", "+00:00"))
        hours_since = (datetime.now(last_fire_dt.tzinfo) - last_fire_dt).total_seconds() / 3600
        
        if hours_since > 24:
            issues.append({
                "check": "pixel_health",
                "level": "warning",
                "message": f"Pixel has not fired in {hours_since:.0f} hours"
            })
    
    return issues

Step 4: Check Spend Anomalies

import sqlite3

def check_spend_anomaly(db_path, account_id, expected_daily):
    conn = sqlite3.connect(db_path)
    
    yesterday_spend = conn.execute("""
        SELECT COALESCE(SUM(spend), 0) FROM ad_daily
        WHERE account_id = ? AND date = DATE('now', '-1 day')
    """, (account_id,)).fetchone()[0]
    
    avg_spend = conn.execute("""
        SELECT COALESCE(AVG(daily_spend), 0) FROM (
            SELECT date, SUM(spend) as daily_spend FROM ad_daily
            WHERE account_id = ? AND date >= DATE('now', '-7 days')
            GROUP BY date
        )
    """, (account_id,)).fetchone()[0]
    conn.close()
    
    issues = []
    
    if yesterday_spend == 0 and expected_daily > 0:
        issues.append({
            "check": "spend_anomaly",
            "level": "critical",
            "message": f"Zero spend yesterday. Expected ~${expected_daily}/day"
        })
    elif avg_spend > 0 and yesterday_spend > avg_spend * 2:
        issues.append({
            "check": "spend_anomaly",
            "level": "warning",
            "message": f"Spend spike: ${yesterday_spend:.2f} vs ${avg_spend:.2f} 7-day avg"
        })
    elif avg_spend > 0 and yesterday_spend < avg_spend * 0.3:
        issues.append({
            "check": "spend_anomaly",
            "level": "warning",
            "message": f"Spend drop: ${yesterday_spend:.2f} vs ${avg_spend:.2f} 7-day avg"
        })
    
    return issues

Step 5: Run All Checks and Alert

def run_health_check(db_path):
    all_issues = []
    
    for account in ACCOUNTS:
        account_issues = []
        
        status_issues = check_account_status(account["id"])
        account_issues.extend(status_issues)
        
        spend_issues = check_spend_anomaly(db_path, account["id"], account["expected_daily_spend"])
        account_issues.extend(spend_issues)
        
        if account_issues:
            all_issues.append({"account": account["name"], "issues": account_issues})
    
    if all_issues:
        send_health_report(all_issues)
    else:
        print("All accounts healthy")
    
    return all_issues

def send_health_report(issues):
    webhook = os.getenv("SLACK_WEBHOOK_URL")
    
    message = "*Ad Account Health Report*\n\n"
    for account in issues:
        message += f"*{account['account']}*\n"
        for issue in account["issues"]:
            icon = "🔴" if issue["level"] == "critical" else "🟡"
            message += f"  {icon} {issue['message']}\n"
        message += "\n"
    
    requests.post(webhook, json={"text": message})
# Run twice daily
0 7,15 * * * cd /path/to/project && python3 health_check.py

Morning and afternoon checks cover most failure modes. Critical issues like disabled accounts get flagged immediately.

What to Build Next

Add billing health checks that verify payment methods are valid. Then build a weekly health summary that trends account health over time so you can spot gradual degradation.

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