DEV Community

Peter Panda
Peter Panda

Posted on

A Daily Ad Spend Anomaly Check in Python Using Exported CSVs

Overspending on ads rarely happens because of one big mistake. It usually comes from a campaign that quietly doubles its spend over a weekend, or a new ad set with a typo in the budget field. If you manage several ad accounts across Meta, Google and TikTok, a simple daily check on exported spend data catches most of these before they become expensive.

This approach does not need API access. It works on the CSV exports every platform provides.

Normalise the exports

Each platform names columns differently. Map them to one schema:

import pandas as pd

MAP = {
    "meta":   {"Campaign name": "campaign", "Day": "date", "Amount spent (USD)": "spend"},
    "google": {"Campaign": "campaign", "Day": "date", "Cost": "spend"},
    "tiktok": {"Campaign name": "campaign", "By Day": "date", "Cost": "spend"},
}

def load(path, platform):
    df = pd.read_csv(path).rename(columns=MAP[platform])
    df["platform"] = platform
    df["date"] = pd.to_datetime(df["date"])
    return df[["platform", "campaign", "date", "spend"]]
Enter fullscreen mode Exit fullscreen mode

Flag unusual days

Compare yesterday's spend for each campaign with its median over the previous 14 days:

def anomalies(df, ratio=1.8, min_spend=50):
    df = df.sort_values("date")
    last = df["date"].max()
    hist = df[df["date"] < last]
    base = (hist[hist["date"] >= last - pd.Timedelta(days=14)]
            .groupby(["platform", "campaign"])["spend"].median().rename("median"))
    today = df[df["date"] == last].set_index(["platform", "campaign"])["spend"]
    out = pd.concat([today, base], axis=1).fillna(0)
    out["ratio"] = out["spend"] / out["median"].replace(0, float("nan"))
    flagged = out[(out["spend"] >= min_spend) & ((out["ratio"] >= ratio) | out["median"].eq(0))]
    return flagged.sort_values("spend", ascending=False)
Enter fullscreen mode Exit fullscreen mode

The min_spend filter keeps tiny campaigns from generating noise. New campaigns with no history appear because their median is zero, which is usually what you want.

Deliver the result

Print it, email it, or post it to a chat channel. The format matters less than the habit. Someone should look at it every morning before budgets reset.

Tuning

  • Raise ratio during planned promotions, or exclude campaigns tagged as tests.
  • Add a second rule for drops in spend, which often signal disapproved ads or payment failures.
  • Keep a short log of flagged items and what caused them. After a month you will know which thresholds are useful.

Beyond spend

Spend anomalies are only meaningful against results. A campaign that doubles spend and doubles purchases is fine. Join conversions from the same exports and compare cost per result, not just raw spend. To set the targets those comparisons rely on, our a ROAS and ad budget calculator works backwards from margin to a break-even ROAS and daily budget.

Published by PandaWM, an overseas marketing team based in Hong Kong.

Top comments (0)