-
Notifications
You must be signed in to change notification settings - Fork 0
Negative Placement Guardian
Script: scripts/negative_placement_guardian.js
Level: Single account (CID), scheduled weekly
What it does: Automatically excludes brand-misaligned and wasteful placements — kids' apps, mobile games, junk inventory, zero-converting sites — across Display, Video/YouTube, and Performance Max campaigns.
Display and PMax campaigns bleed into inventory your customers will never be on. For a beauty/facial brand targeting women 25–55, mobile games alone commonly eat 30–60% of Display spend — accidental taps from kids playing games, zero purchase intent. Nobody reviews placement reports weekly by hand, so the waste compounds quietly.
Layer 1 — Pattern Blocklist. A fully editable regex list tested against every placement's URL, app name, and channel/video title. Ships tuned for a beauty brand: kids' content (cocomelon, paw patrol, coloring, nursery…), gaming (roblox, solitaire, match 3, idle, tycoon…), junk inventory (mod apk, wallpaper, ringtone, fake call…). Pattern hits are excluded on sight — no performance data required. See Customizing for Your Vertical to retune the list for any industry in minutes.
Layer 2 — Performance Rules (Display & Video only):
- Spend ≥
$10(configurable) with zero conversions over a 90-day lookback - Accidental-click detector: 10+ clicks at 5%+ CTR — on Display inventory, that's an ad blocking a game button, not genuine interest
| Channel | Exclusion Level | Why |
|---|---|---|
| Display / Video | Campaign-level negative placement criteria | Scoped to the campaign where the placement actually served |
| Performance Max |
Account-level via customer_negative_criterion
|
PMax ignores campaign-level placement exclusions — account-level is the only kind it respects |
PMax placements are evaluated by the pattern layer only, because Google's performance_max_placement_view exposes impressions but no cost or conversion data. That's an API limitation, clearly labeled in the report.
- Incremental: every run loads all existing exclusions first and skips them — week two only processes new placements
-
Capped:
MAX_EXCLUSIONS_PER_RUN(default 500) so a bad pattern edit can't nuke thousands of placements blind -
Allowlisted: placements matching your
ALLOWLISTpatterns are never excluded — protect your own properties and known-good partners - Fully logged: every flagged placement gets a sheet row with scope, type, metrics, the exact reason (which pattern hit, or which rule fired), and the action taken
| Setting | Default | Notes |
|---|---|---|
DRY_RUN |
false |
Set true for a report-only first pass |
SPREADSHEET_URL |
'' |
Blank Google Sheet URL for the log |
LOOKBACK_DAYS |
90 |
Performance window for Display/Video stats |
MIN_SPEND_NO_CONVERSIONS |
10.00 |
Zero-conversion spend threshold ($) |
MIN_CLICKS_FOR_CTR_RULE / CTR_ANOMALY
|
10 / 0.05
|
Accidental-click detector |
MAX_EXCLUSIONS_PER_RUN |
500 |
Per-run safety cap |
BLOCK_PATTERNS |
~60 beauty-tuned patterns | Edit freely — see Customizing for Your Vertical |
ALLOWLIST |
brand properties | Overrides everything |
- Follow the Installation Guide to paste the script into Google Ads Scripts
- Paste your blank Google Sheet URL into
SPREADSHEET_URL - Run once — the first run is your backlog cleanup and may flag hundreds of placements; skim the report and allowlist anything legitimate
- Set the schedule to Weekly — each subsequent run handles only new inventory
The first run's report doubles as a placement waste audit. Sum the Spend column on pattern-flagged rows and you have a defensible "recovered $X/month from misaligned inventory" number for your client or CFO.
By AHMEEGO™ / It All Started With A Idea LLC — makers of Buddy, the Google Ads AI Agent. Discuss in r/ppc_.