---
name: the-daily-pacing-check
description: "Every morning, compare spend vs plan across every connected account and raise honest, evidence-backed alerts only when something needs a human. Read-only; hands off to the reallocator for changes."
license: MIT
compatibility: "Works with any Agent-Skills-compatible AI (Claude, ChatGPT, Cursor, Codex, and more). Ad-account actions run through Adspirer."
metadata:
  author: "Adspirer"
  version: "1.0.0"
  adspirer_category: "ad-ops-optimization"
  adspirer_source: "https://www.adspirer.com/skills/the-daily-pacing-check"
  adspirer_connection_url: "https://adspirer.ai/sign-up"
  adspirer_primary_keyword: "budget pacing"
  adspirer_secondary_keywords: "ad spend pacing, ppc budget pacing"
  adspirer_launch_wave: "1"
  adspirer_kind: "agent"
  adspirer_level: "operator"
  adspirer_platforms: "google,meta,linkedin,tiktok,amazon"
  adspirer_supported_clients: "claude,claude-code,chatgpt,codex,cursor,gemini,windsurf"
  adspirer_summary: "Every morning, compare spend vs plan across every connected account and raise honest, evidence-backed alerts only when something needs a human. Read-only; hands off to the reallocator for changes."
  adspirer_connections_required: "adspirer"
  adspirer_connections_optional: ""
---

# The Daily Pacing Check

## Use this when

Run this every morning across all connected ad accounts (Google, Meta, LinkedIn, TikTok, Amazon) to catch pacing problems before they become budget disasters — accounts burning through monthly budget too fast (will exhaust with 10+ days left), accounts pacing too slow (will underspend and miss delivery commitments), or campaigns that stopped spending entirely overnight (policy rejection, card decline, budget cap hit, audience exhaustion, disapproval). Best for accounts with defined monthly or flight budgets where a human is checking in daily or would want to know same-day if pacing breaks. Not a substitute for real-time budget alerts on accounts with hard compliance spend caps (e.g., co-op/MDF funded campaigns) — those need platform-native alerts too, since this only runs once per morning.

## What you need

- An Adspirer connection to each platform you want checked (Google Ads, Meta, LinkedIn, TikTok, Amazon Ads) — read access is sufficient, this workflow makes zero write calls.
- A stated budget reference for each account/campaign you want paced against — either (a) the platform's own campaign/daily budget fields (works out of the box, no setup), or (b) a separate monthly flight budget or IO amount if it differs from what's configured in-platform (tell the agent the number and the flight start/end dates; otherwise it defaults to the platform-configured daily/monthly budget × days elapsed).
- Your timezone and what "morning" means for this check (account timezone vs. your local timezone matter — platform "yesterday" spend can be split across two of your calendar days if they don't match).
- Tolerance thresholds if you have opinions beyond the defaults below (this workflow defaults to flagging accounts >15% ahead or >20% behind expected linear pace over a trailing 3-day window, not a single day — say so if you want tighter or looser bands, or a different lookback window).
- Optional: which accounts are "flight" campaigns with a hard end date (LinkedIn and some Meta/Amazon deals) vs. always-on monthly budgets — flight campaigns need day-of-flight pacing math, not calendar-month pacing.

## Procedure

1. Pull the full list of connected accounts across all five platforms and confirm which are active/eligible (skip anything paused, disapproved fleet-wide, or with zero live campaigns — note skipped accounts, don't silently drop them).
**Connect Adspirer (the ads connection):** when you reach a step that touches a live ad account, connect Adspirer first. In Claude Code, run `/plugin marketplace add anthropics/claude-plugins-community` then `/plugin install adspirer-ads-agent@claude-community`. In claude.ai or ChatGPT, add the Adspirer connector from https://www.adspirer.com/docs/ai-clients. Any other agent: follow https://www.adspirer.com/docs/ai-clients for your client. Sign-in link for the user: https://adspirer.ai/sign-up. Do not proceed with live ad-account steps until the connection is confirmed.
2. For each active account, pull live campaign-level spend for the current billing period to date (calendar month for standard budgets, days-into-flight for flight campaigns) plus a trailing 3-day daily spend series — the 3-day window matters because a single low-spend day is normal noise (weekend dip, one slow auction day) but three days in a row is a real signal.
3. For each account, pull the budget reference: platform-configured daily/monthly budget by default, or the user-supplied flight/IO amount if one was given in setup. Compute expected spend-to-date using linear pacing (days elapsed ÷ total days in period × total budget) — note in the output when a campaign has known non-linear delivery (e.g., accelerated delivery setting, dayparting, a mid-month budget change) since linear pacing isn't the right yardstick there and should be flagged as "pacing math not applicable" rather than forced into the model.
4. Compute the pacing ratio (actual spend-to-date ÷ expected spend-to-date) per campaign and per account rollup. Classify: on-pace (within the tolerance band), overpacing (ahead of band — will exhaust budget before period end at current burn rate; compute the projected exhaust date), underpacing (behind band), or dark (spend = $0 in the last 24-48h on a campaign that has spent every prior day this period — this is the most urgent case, it usually means disapproval, card decline, budget cap already hit, or audience/inventory exhaustion, not benign pacing).
5. For every dark or overpacing/underpacing-outside-band campaign, pull the specific root-cause signal before writing the alert: campaign/ad status and any disapproval or rejection reason, ad set/ad group delivery status, payment/billing status on the account, and — for Meta/TikTok especially — whether the campaign is still inside learning phase (< 50 optimization events in 7 days) since erratic day-to-day spend during learning is expected, not a pacing bug, and should be labeled as such rather than alarmed on.
6. Cross-check each finding against what actually changed in-platform in the last 48h if that history is available (recent budget edits, bid strategy changes, audience edits, new ad launches) — a spend drop the same day someone cut a daily budget in half is a known cause, not a mystery; say so in the alert instead of raising it as unexplained.
7. Draft one alert per account that needs a human (not per campaign, unless a single campaign is a large % of account spend) — plain language, the actual numbers pulled in step 2-3, the classification from step 4, the root cause from step 5-6 if found, and — for overpacing — the projected exhaust date and the dollar/percent gap to closing it back to on-pace. No alert is raised for accounts that are on-pace; those get a one-line "checked, on pace" rollup entry, not a full alert.
8. Hand off: overpacing and underpacing accounts route to the reallocator/reallocation workflow as candidates (this workflow does not itself propose or make budget changes); dark campaigns route to a root-cause/policy-check workflow if the cause wasn't resolvable from status fields alone; do not take any action on any account — output the findings and stop.

## Fixed checks

- Spend-to-date, daily spend series, campaign/ad status, disapproval reasons, and budget fields are all pulled live from the platform via Adspirer at run time — never inferred, cached from a prior run, or asserted from memory.
- A "dark" classification requires confirming $0 spend via the live daily series for the account's actual timezone, not a UTC/local mismatch artifact — cross-check the account's configured timezone before concluding a day was truly zero-spend.
- Learning-phase status (Meta/TikTok) is checked live via the ad set/campaign optimization event count before any erratic-spend day is escalated as a pacing anomaly — never assumed from campaign age alone.
- Root-cause fields (disapproval reason, billing status, recent edit history) are pulled and quoted verbatim from the platform response in the alert — never paraphrased into a guessed cause when the platform gives no reason.
- Every "on-pace" claim is derived from the actual computed ratio in that run, not carried over from yesterday's alert state — an account that was flagged yesterday and shows on-pace today gets a fresh "resolved" note, not silence.

## Stop conditions

- Success: all connected accounts checked; each classified on-pace, overpacing, underpacing, or dark; alerts drafted only for accounts needing a human; on-pace accounts logged in the rollup with no alert noise.
- No-op: every connected account is on-pace within tolerance for the day — output is the rollup summary only, zero alerts, run ends cleanly.
- Blocked: one or more platform connections fail, return stale/error data, or an account's timezone/budget reference is unknown and wasn't supplied in setup — that account is reported as "could not verify pacing" with the specific reason (auth failure, API error, missing budget reference), not silently skipped or guessed at.
- Needs-approval: not applicable to this workflow's own actions (it is read-only and proposes nothing), but any account flagged overpacing or underpacing is explicitly handed off as "needs a budget-change decision" for the reallocator workflow to bring to the user for approval — this workflow never decides or requests approval for a budget change itself.

## Approval boundaries

Read-only. This workflow takes no spend actions, changes no budgets, pauses no campaigns, and edits nothing in any connected ad account — it only reads live performance and status data and produces alerts/rollup output. Any budget reallocation, pause, or other spend action it identifies as needed is explicitly hand-off-only to a separate workflow (the reallocator) that carries its own explicit user-approval requirement before touching a live account.

## What you get

A daily rollup across every connected account (one line each: on-pace / overpacing / underpacing / dark / could-not-verify) plus a full alert for each account that needs attention — containing the live spend-to-date and expected-spend numbers, the pacing ratio, the root cause if one was found in platform data (disapproval reason, billing issue, recent budget/bid edit, learning-phase noise), and for overpacing accounts a projected budget-exhaust date. Dark and off-pace accounts are flagged as hand-off candidates for the reallocation or root-cause workflows — no changes are made to any account by this workflow itself.
