BEST-PRACTICES PLAYBOOKS
Doctrine
Doctrine is plain markdown. Marketers edit the playbook; the engine and the LLM both obey it. The prose grounds the LLM lane; the RED FLAGS section at the bottom of each file is the machine-checkable grammar the deterministic engine evaluates on every audit — no code change required to tune a threshold.
src/lib/adops/doctrine/google-ads.md · 11 MACHINE-CHECKABLE RULES
Google Ads — Best Practices Doctrine
Purpose. This is the playbook the audit engine diffs a live account against. The prose
sections encode account-management doctrine the LLM reasons over; the final RED FLAGS
section is a machine-checkable checklist the deterministic pre-check parses into guaranteed
recommendations. Marketers edit this file; the engine and the LLM both obey it.
Account structure
Google Ads has a fixed hierarchy: Account → Campaign → Ad Group → (Keywords + Ads). Structure is the single biggest lever on Quality Score, budget control, and reporting clarity — budget, bid strategy, geo and schedule live at the campaign level; relevance (keyword ↔ ad ↔ landing page) is decided at the ad group level.
- One theme per ad group. Every keyword in an ad group maps to one searcher intent so a
- Segment campaigns by the dimension you must control independently — budget, geography,
- Separate brand and non-brand — always. Brand terms convert at high rates and low CPCs and
- STAG over SKAG. Group 3–15 tightly related keywords per ad group so Responsive Search Ads
single ad set is genuinely relevant to all of them. Mixed-intent ad groups depress Quality Score.
vertical margin, brand vs. non-brand. Two keyword sets that need different budgets belong in different campaigns, not different ad groups.
will flatter the blended numbers of prospecting campaigns, hiding poor performance. For an affiliate lead-gen book, this is doubly true: brand traffic is house money; non-brand is where margin is won or lost.
have query variety to optimize against. Single-keyword ad groups splinter conversion data below the volume Smart Bidding needs to learn.
Budget & bid strategy
Match bid strategy to conversion volume — automated strategies need data to learn:
1. Manual CPC / Maximize Clicks — bootstrap only; migrate off as soon as conversions accrue. 2. Maximize Conversions (no target) — tracking is live but volume is thin. 3. Target CPA — only once a campaign reliably produces ~15–30 conversions / 30 days. 4. Target ROAS — needs conversion value tracking and ~30+ valued conversions / 30d.
Do not skip rungs. A low-volume campaign jumped straight onto tCPA starves the learning phase and produces volatile spend.
- Budget-limited is a signal, not a steady state. A campaign flagged "limited by budget"
- Daily budgets can overspend up to ~2× on a given day (Google averages to daily × 30.4).
- Reallocate toward marginal CPA, not average CPA — move budget to campaigns where the
while converting profitably is leaving volume on the table — raise the budget or reallocate from an underperformer. A budget-limited campaign that is NOT converting should be fixed (targeting, bids) before it gets another dollar.
Size against the monthly figure.
next dollar still clears the allowable, away from campaigns past their efficient frontier.
Keyword hygiene
- Broad match only with Smart Bidding and a strong negative list. Broad without negatives is
- Shared negative lists are mandatory — a global junk list applied across campaigns, plus
- Mine search terms weekly on high-spend accounts. Converting queries become keywords;
- Prune zero-impression and long-term zero-conversion keywords — they add management surface
the classic lead-gen budget-waster (searchers wanting free, jobs, DIY).
brand negatives on non-brand campaigns and vice versa so the two never cannibalize.
wasteful queries become negatives.
and mask the real term mix.
Ad copy
- ≥ 2–3 enabled RSAs per ad group is the durable floor; a single-ad ad group has no A/B
- 10–15 distinct headlines, ≥ 4 descriptions per RSA; include the theme keyword in a couple
- Disapproved ads in enabled campaigns are emergencies — for regulated lead-gen verticals
- CTR is the canary. Search campaigns sustaining under ~1% CTR at meaningful volume have an
signal and goes dark if that ad is disapproved. An enabled ad group with zero serving ads is dead spend surface.
of headlines. Pin only what compliance requires.
(insurance, finance) a policy flag can silence a whole ad group overnight. Replace or appeal immediately.
ad-relevance or query-mix problem — refresh copy and check the term report before touching bids.
Quality Score
Quality Score (1–10) = expected CTR + ad relevance + landing-page experience. Spending keywords at QS ≤ 3 overpay on every click and almost always signal a structural mismatch — wrong ad group, weak ad, or a generic landing page. Fix the structure, not the bid.
Conversion tracking
Everything above assumes conversions are measured. An account spending with zero recorded conversions is flying blind — either tracking is broken or the account is pure waste; both are critical. Verify at least one conversion action fired in the window before trusting any other number.
RED FLAGS
Machine-checkable checklist. Each bullet is one rule the deterministic pre-check
(
redflags.ts) evaluates against the AdSpec snapshot. Grammar:
- rule_id — when: <condition> — recommend: <RecommendationType> — action: <slug> — risk: <low|medium|high> — why: <rationale>
recommendMUST be one of the nine canonical types(
budget_change | pause | enable | keyword_add | keyword_negative | bid_change | new_creative | structure | other).Metrics are trailing-30-day unless suffixed. Thresholds here are the documented defaults.
gads-no-conversion-tracking— when:account.cost_30d > 0 AND account.conversions_30d == 0— recommend:other— action:add_conversion_tracking— risk:high— why: An account spending with zero recorded conversions is unmeasurable; this blocks every downstream optimization.gads-spend-zero-conversions— when:campaign.status == enabled AND campaign.cost_30d >= 0.20 * account.cost_30d AND campaign.conversions_30d == 0— recommend:pause— action:pause_campaign— risk:high— why: A campaign consuming ≥20% of account spend with zero conversions is bleeding budget; pause and diagnose before it spends more.gads-disapproved-ad— when:campaign.status == enabled AND ad.policy_status == disapproved— recommend:new_creative— action:replace_disapproved_ad— risk:high— why: A disapproved ad in an enabled campaign silences delivery and, in regulated verticals, risks account-level policy strikes.gads-adgroup-no-active-ad— when:ad_group.status == enabled AND enabled_ad_count == 0— recommend:new_creative— action:add_rsa— risk:high— why: An enabled ad group with no serving ad cannot show; it is dead spend surface.gads-adgroup-single-ad— when:ad_group.status == enabled AND enabled_ad_count == 1— recommend:new_creative— action:add_rsa— risk:medium— why: One RSA gives no A/B signal and the ad group goes dark if that ad is disapproved.gads-zero-impression-keyword— when:keyword.status == enabled AND keyword.impressions_30d == 0— recommend:pause— action:prune_keyword— risk:low— why: Zero-impression keywords add management surface and mask the real query mix; prune or restructure.gads-low-quality-score-spend— when:keyword.status == enabled AND keyword.quality_score <= 3 AND campaign.cost_30d > 0— recommend:structure— action:restructure_ad_group— risk:medium— why: A spending keyword at QS ≤ 3 overpays on every click; fix the ad-group/ad/landing-page mismatch, not the bid.gads-premature-smart-bidding— when:campaign.bid_strategy IN (target_cpa, target_roas) AND campaign.conversions_30d < 15— recommend:bid_change— action:change_bid_strategy— risk:medium— why: tCPA/tROAS need ~15–30 conversions/30d to stabilize; below that the learning phase starves and spend goes volatile.gads-budget-limited-converting— when:campaign.is_budget_limited == true AND campaign.conversions_30d > 0— recommend:budget_change— action:increase_budget— risk:medium— why: A budget-capped campaign that is converting is leaving profitable volume unclaimed; raise or reallocate.gads-budget-limited-not-converting— when:campaign.is_budget_limited == true AND campaign.conversions_30d == 0— recommend:other— action:fix_targeting_before_budget— risk:medium— why: Adding budget to a campaign that isn't converting scales waste; fix targeting first.gads-low-ctr-high-impressions— when:campaign.impressions_30d >= 10000 AND campaign.ctr_30d < 0.01— recommend:new_creative— action:improve_ad_strength— risk:medium— why: Search CTR under 1% at ≥10k impressions signals weak ad relevance or a polluted query mix; refresh copy and mine the term report.