Claude
Skills
Sign in
Back

monitor

Included with Lifetime
$97 forever

Check Spotify Ads API campaign health — pacing, delivery issues, budget burn rate, stalled campaigns, and underpacing alerts. Use for one-shot health checks or recurring monitoring when the host supports scheduled automations.

Ads & Marketing

What this skill does


# Spotify Ads API — Campaign Health Monitor

Diagnose delivery problems across active campaigns. Goes beyond the dashboard by running diagnostic checks and recommending specific actions.

## Setup

1. Read `access_token`, `ad_account_id`, and `auto_execute` from the active platform settings file:
   - Codex: prefer `.codex/spotify-ads-api.local.md`, then fall back to `.claude/spotify-ads-api.local.md`.
   - Claude: prefer `.claude/spotify-ads-api.local.md`, then fall back to `.codex/spotify-ads-api.local.md`.
2. Base URL: `https://api-partner.spotify.com/ads/v3`
3. If neither settings file exists, instruct the user to run `/spotify-ads-api:configure` first.
4. Read the active platform manifest for the plugin `version`: `.codex-plugin/plugin.json` on Codex or `.claude-plugin/plugin.json` on Claude.
5. Set `SDK_PRODUCT` to `codex-plugin` on Codex or `claude-code-plugin` on Claude. Set `SDK_HEADER="X-Spotify-Ads-Sdk: $SDK_PRODUCT/$PLUGIN_VERSION"` and include `-H "$SDK_HEADER"` on all API requests.

## Parsing Arguments

- No argument or `--all` → Health check all active campaigns
- `<campaign_id>` (UUID) → Deep health check on a specific campaign (includes ad set and ad level diagnostics)
- If ambiguous, ask the user.

---

## Account-Wide Health Check (default)

### API Calls

Execute these calls to gather the data needed for diagnostics:

#### 1. Active campaigns

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/campaigns?statuses=ACTIVE&limit=50&sort_direction=DESC"
```

#### 2. Active ad sets

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/ad_sets?statuses=ACTIVE&limit=50&sort_direction=DESC"
```

#### 3. Today's campaign metrics

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/aggregate_reports?\
entity_type=CAMPAIGN&\
fields=IMPRESSIONS&fields=SPEND&fields=REACH&fields=CLICKS&fields=CTR&fields=FREQUENCY&\
granularity=DAY&\
report_start=$(date -u +%Y-%m-%dT00:00:00Z)&\
report_end=$(date -u +%Y-%m-%dT00:00:00Z)&\
entity_status_type=CAMPAIGN&\
statuses=ACTIVE&\
limit=50"
```

#### 4. Lifetime campaign metrics (for pacing)

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/aggregate_reports?\
entity_type=CAMPAIGN&\
fields=IMPRESSIONS&fields=SPEND&fields=REACH&fields=CLICKS&\
granularity=LIFETIME&\
entity_status_type=CAMPAIGN&\
statuses=ACTIVE&\
limit=50"
```

### Health Checks

Run these diagnostics against the fetched data:

#### 1. Pacing Check

For each active campaign, compare spend progress to flight progress:

- **DAILY budgets**: Sum the daily budgets of all active ad sets under the campaign. Compare today's spend to the total daily budget.
  - Display: `$142.50 / $200.00 daily (71%)`

- **LIFETIME budgets**: Compare total lifetime spend to total lifetime budget, and compare against elapsed flight percentage.
  - `elapsed_pct = (today - start_date) / (end_date - start_date) * 100`
  - `spend_pct = total_spend / total_budget * 100`
  - Display: `$2,100 / $5,000 lifetime (42% spent, 35% of flight elapsed)`

**Alert levels:**
- **OK**: Spend % and elapsed % within 20 points of each other
- **WARNING**: 20-40 point gap between spend % and elapsed %
- **CRITICAL**: >40 point gap, OR zero spend with >24 hours elapsed since campaign start

#### 2. Stalled Delivery Check

- If an ACTIVE campaign has zero impressions today AND its start_time is more than 4 hours ago, flag as **STALLED**.
- Exclude campaigns that started within the last 4 hours (they may still be ramping up).

#### 3. Budget Exhaustion Check

For LIFETIME budgets, project when the budget will run out at the current daily burn rate:
- `daily_burn = lifetime_spend / days_elapsed`
- `days_remaining_at_pace = (budget - spend) / daily_burn`
- `projected_end = today + days_remaining_at_pace`

Flag if:
- Budget will exhaust **before** the scheduled `end_time` → "May exhaust budget early"
- Budget will be **>20% unspent** at `end_time` → "Likely to underspend"

### Display Format

```
=== Campaign Health Check ===
Checked: 3 active campaigns, 7 active ad sets
Time: 2026-05-14 14:30 UTC

| Campaign | Status | Spend Today | Pacing | Issues |
|----------|--------|-------------|--------|--------|
| Summer Promo | OK | $142.50 / $200 daily (71%) | On track | — |
| Q2 Brand | WARNING | $28.00 / $100 daily (28%) | Underpacing | 1 stalled ad set |
| Podcast Launch | CRITICAL | $0.00 / $75 daily (0%) | Stalled | No delivery today |

Issues Found (2):
  1. [WARNING] Q2 Brand: Spending at 28% of daily budget with 62% of day elapsed
     → Consider increasing bid or broadening targeting. Run: /spotify-ads-api:dashboard <campaign_id>
  2. [CRITICAL] Podcast Launch: Zero impressions today (campaign started 2026-05-12)
     → Campaign may have delivery issues. Check ad approval status with: /spotify-ads-api:monitor <campaign_id>
```

If no issues are found:

```
All 3 active campaigns are healthy. No issues detected.
```

---

## Deep Campaign Health Check (`<campaign_id>`)

### API Calls

#### 1. Campaign details

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/campaigns/$CAMPAIGN_ID"
```

#### 2. All ad sets under the campaign

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/ad_sets?campaign_ids=$CAMPAIGN_ID&limit=50"
```

#### 3. All ads under the campaign

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/ads?campaign_ids=$CAMPAIGN_ID&limit=50"
```

Extract active and paused ad set IDs from Step 2 and build repeated query parameters before fetching ad set metrics:

```bash
AD_SET_IDS_QUERY="entity_ids=<AD_SET_ID_1>&entity_ids=<AD_SET_ID_2>"
```

Use the ad set IDs directly because non-`LIFETIME` aggregate reports require `entity_ids_type` to match `entity_type`. If the campaign has more than 50 ad sets, chunk report requests in groups of 50.

#### 4. Today's ad set metrics

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/aggregate_reports?\
entity_type=AD_SET&\
fields=IMPRESSIONS&fields=SPEND&fields=CLICKS&fields=REACH&fields=CTR&fields=FREQUENCY&fields=COMPLETES&\
granularity=DAY&\
report_start=$(date -u +%Y-%m-%dT00:00:00Z)&\
report_end=$(date -u +%Y-%m-%dT00:00:00Z)&\
${AD_SET_IDS_QUERY}&\
entity_ids_type=AD_SET&\
entity_status_type=AD_SET&\
limit=50"
```

#### 5. Lifetime ad set metrics

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -H "Authorization: Bearer $TOKEN" \
  -H "$SDK_HEADER" \
  "$BASE_URL/ad_accounts/$AD_ACCOUNT_ID/aggregate_reports?\
entity_type=AD_SET&\
fields=IMPRESSIONS&fields=SPEND&fields=CLICKS&fields=REACH&fields=FREQUENCY&\
granularity=LIFETIME&\
${AD_SET_IDS_QUERY}&\
entity_ids_type=AD_SET&\
entity_status_type=AD_SET&\
include_parent_entity=true&\
limit=50"
```

### Additional Health Checks (Deep Mode)

In addition to the pacing, stalled, and exhaustion checks from the account-wide mode, the deep check adds:

#### 4. Ad Health Check

- **Rejected ads**: Ads with status `REJECTED` — flag with recommendation to review and re-create.
- **Pending ads**: Ads with status `PENDING` where `created_at` is more than 24 hours ago — flag as unusually slow approval.
- **Delivery OFF**: Ads with `delivery: OFF` under an ACTIVE ad set — flag as potentially unintentional.

#### 5. Audience Fatigue Check

- **High frequency**: If lifetime frequency > 3.0 on any ad set, warn about potential audience fatigue. Suggest expanding targeting
Files: 1
Size: 10.6 KB
Complexity: 20/100
Category: Ads & Marketing

Related in Ads & Marketing