@ads-repo/meta-creative-buckets
v1.0.1
Published
Sort your Meta creatives into Scale, Wait and Kill on a spend vs CRR grid — drop-in Claude Code skill
Readme
Meta Creative Buckets
Sort every creative in your Meta ad account into Scale, Wait, Kill or Not enough data on a Spend × CRR grid. The output is a single self-contained HTML file with the quadrant chart, a time slider that replays the window day by day, and a sortable creative table — no server, no database, no Google Sheet in between.
CRR bad (high) │ Wait │ Kill
├───────────┼──────────
CRR good (low) │ NotData │ Scale
└──────────────────────
low spend enough spendWhat you get
- One HTML file with all data embedded, opens straight off disk
- Quadrant scatter — one bubble per ad, area ∝ spend, X = spend (log), Y = CRR %
- Time slider — replays the window day by day, with Day / Week / Month granularity and a date-range picker
- Live thresholds — target CRR and spend gate as sliders, both seeded from your own account
- Spend distribution bar — what share of budget sits in each bucket
- Creative table — spend, revenue, purchases, CRR, ROAS, last-3-day trend, CTR, active days, all sortable
- Cascading filters: campaign / ad set / ad, status, Active-only toggle
- Day-over-day ▲▼ arrows once you have run it twice
- Password-locked copy for client sharing (
encrypt-dashboard.cjs) - adsrepo.com brand styling (Raleway font, orange accent #ff5722)
The metric
CRR = spend ÷ purchase revenue, as a percentage, on the 7-day-click window.
It is ROAS upside down: CRR 40% means 40 € of ads per 100 € of sales, so lower is better (CRR 40% = ROAS 2.5).
| Bucket | Rule (target CRR T, spend gate S) |
|---|---|
| Not enough data | spend < S — under the gate, never judged |
| Scale | spend ≥ S and CRR ≤ T — earning well, give it more |
| Wait | spend ≥ S and T < CRR < 3T — mediocre, watch it |
| Kill | spend ≥ S and CRR ≥ 3T — burning money |
Both thresholds are computed from your account at build time, not hardcoded: the target starts at your blended CRR, the spend gate at the 75th percentile of per-ad spend (floored at 3 × AOV). Both are sliders — that is only the opening position.
Requirements
- Node.js 18+ (download)
- A Meta access token with the
ads_readpermission - Your ad account id — the
act_…number in the Ads Manager URL - An account that tracks purchases: the grid is built on revenue, so lead-gen accounts have nothing on the Y axis
No npm dependencies — the scripts use only Node's standard library.
Installation
Option A — Claude Code (recommended)
npm install -g @ads-repo/meta-creative-bucketsThat copies the skill into ~/.claude/skills/meta-creative-buckets/, available in every session. Restart Claude Code, then say:
build the creative buckets dashboard
Claude picks the skill up from the trigger phrase, fetches the data and opens the dashboard.
Manual install (if you would rather not install globally): unzip the ZIP from adsrepo.com and move the meta-creative-buckets/ folder into ~/.claude/skills/ or <project>/.claude/skills/, then restart Claude Code. Nothing to npm install — there are no dependencies.
Option B — Standalone CLI (no Claude Code)
The scripts are plain Node and run on their own:
cd ~/.claude/skills/meta-creative-buckets
node scripts/fetch-buckets-data.cjs 30
node scripts/build-buckets-matrix.cjsSetup
Get a token with the ads_read scope from the Graph API Explorer: pick your app, add the scope, generate. That token expires in about an hour — for repeat use, exchange it for a long-lived token or create a System User token in Business Manager.
Then put both values in a .env file in your project root (see env.example):
META_ACCESS_TOKEN=your-token-here
META_AD_ACCOUNT_ID=act_1234567890Reading several accounts from one project? Suffix each pair with a client slug and pass the flag:
META_ACCESS_TOKEN_ACME_CZ=...
META_AD_ACCOUNT_ID_ACME_CZ=act_9876543210node scripts/fetch-buckets-data.cjs 30 --client acme-czOptionally add buckets.config.json in the project root for a nicer header (account name, logo). Every field is optional — see buckets.config.example.json.
What the script does
- Read the account currency and name from the Meta API (never guessed from the account name)
- Fetch 30 days of daily ad-level spend and purchase revenue, falling back to day-by-day if Meta refuses the bulk range
- Collect the ids that actually spent, then look up creative metadata for just those in batches of 40
- Work out CRR, ROAS, CTR and AOV per creative from the summed atoms, never averaged from daily rates
- Compute the starting thresholds from your own numbers
- Write one self-contained HTML file and open it in your browser
Output
data/meta-ads/<client>/
├── buckets-latest.json # per-ad summary + daily series
├── history/YYYYMMDD-buckets.json # dated snapshot, drives the ▲▼ arrows
└── buckets-matrix.html # the dashboardThe HTML works fully offline once generated. Email it, host it on a static server, or open it locally.
Custom window: node scripts/fetch-buckets-data.cjs 60 2026-09-07 fetches 60 days ending on that date. Passing yesterday avoids a partial final day.
Troubleshooting
| Problem | Fix |
|---|---|
| credentials missing | Add META_ACCESS_TOKEN and META_AD_ACCOUNT_ID to .env in your project root, not in the skill folder |
| Invalid OAuth access token | The Graph API Explorer token expired (about an hour). Generate a new one, or switch to a System User token |
| Blank creative thumbnails | Meta rate-limits the creative lookup on busy accounts. Every number is still correct — wait 15-30 min and run node scripts/fetch-creative-meta.cjs to patch them in |
| too many calls (error 80004) | Give the account a quiet 15-30 minutes; consecutive runs keep the rolling window full. Raise META_API_RATE_LIMIT_DELAY in .env if it persists |
| Every ad in "Not enough data" | Normal on accounts where spend concentrates in a few creatives. Drag the spend gate slider down to judge more of them |
| Dashboard opens empty | Check the account actually had spend in the window, and that it tracks purchase events |
Metrics glossary
- CRR — spend ÷ purchase revenue, as a %. Lower is better. ROAS upside down
- Target CRR — the line between Scale and Wait. Starts at your account's blended CRR
- Spend gate — minimum spend before an ad is judged at all. Starts at the 75th percentile of per-ad spend, floored at 3 × AOV
- CRR 3D — the same ratio over the last three days, so you can see where a creative is heading
- No revenue yet — ads with spend but no purchases sit in a separate strip, placed by spend only. They are never "Wait": there is nothing to wait on without a single sale
Two attribution notes worth knowing. Revenue is read from the named 7d_click sub-field of action_values, not Meta's plain value — that one is the account default attribution (click + view) and can overstate revenue by roughly a third. And summing revenue across ads gives a higher number than the same period read at account level, typically +8-12%, because one purchase touched by two ads is credited to both. Per-ad CRR is sound for ranking creatives against each other; read the true blended CRR at account level.
License
Copyright (c) 2026 Tomas Kliment / adsrepo.com. All rights reserved. See LICENSE for terms.
