Skip to content

Negative Placement Guardian

John Williams edited this page Jul 20, 2026 · 1 revision

Negative Placement Guardian — Automated Placement Exclusions for Display, YouTube & Performance Max

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.

The Problem

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.

Two Detection Layers

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

Where Exclusions Land (the part everyone gets wrong)

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.

Built for Weekly Automation

  • 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 ALLOWLIST patterns 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

Configuration Reference

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

Setup (Today) + Schedule (Weekly)

  1. Follow the Installation Guide to paste the script into Google Ads Scripts
  2. Paste your blank Google Sheet URL into SPREADSHEET_URL
  3. Run once — the first run is your backlog cleanup and may flag hundreds of placements; skim the report and allowlist anything legitimate
  4. Set the schedule to Weekly — each subsequent run handles only new inventory

Bonus: Quantify the Waste

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_.