From toprank
Generates Google Ads RSA headlines, descriptions, and variants for A/B testing to improve CTR using business context, personas, and benchmarks.
npx claudepluginhub nowork-studio/toprank --plugin toprankThis skill uses the workspace's default tool permissions.
Read and follow `../shared/preamble.md` — it handles MCP detection, token, and account selection. If config is already cached, this is instant.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Read and follow ../shared/preamble.md — it handles MCP detection, token, and account selection. If config is already cached, this is instant.
Write Google Ads RSA copy and run structured A/B tests to find winning messaging.
Before generating any copy, read these reference documents for expert-level context:
references/rsa-best-practices.md — Character limits, headline formulas, pinning strategy, A/B methodology, common mistakes../ads/references/industry-benchmarks.md — Industry-specific CTR benchmarks to beat../ads/references/quality-score-framework.md — How ad copy impacts Quality Score componentsThese contain the specific formulas, character counts, and patterns that separate amateur ad copy from expert-level RSAs.
Every ad copy decision depends on understanding the business. Business context is stored in {data_dir}/business-context.json.
{data_dir}/business-context.json. If it exists and has content, use it — skip to the next section.../ads-audit/references/business-context.md (website crawl, data bootstrapping, JSON schema). That document is the single source of truth for gathering business context.| Field | Copy application |
|---|---|
services | Determines headline categories and description angles |
locations | Geo-specific headlines get higher quality scores and CTR |
brand_voice | Tone, forbidden words, preferred language |
differentiators | These ARE the value prop headlines — the reason someone picks you |
competitors | Sharpens positioning (without naming them in ads) |
seasonality | When to push urgency copy vs. evergreen |
social_proof | Trust signal headlines and descriptions |
offers_or_promotions | Time-sensitive copy angles, CTA variations |
landing_pages | Copy must match the page or conversions drop |
Cross-reference {data_dir}/personas/{accountId}.json (created by /ads-audit) and {data_dir}/business-context.json to ground every piece of copy in real customer data.
| Persona Field | Copy Application |
|---|---|
search_terms | Use these exact words and phrases in headlines — they're the language real customers use |
pain_points | Lead descriptions with the pain point, then present the solution. Pain > features for click-through |
decision_trigger | This IS your CTA angle. If the trigger is "seeing reviews mentioned", put the review count in a headline |
primary_goal | Match H1 to this goal. The first headline should answer "will this page help me do X?" |
demographics | Adjust register: corporate buyer gets different language than homeowner. Technical user gets specs, consumer gets benefits |
For each ad group, identify which persona(s) it serves:
search_termsprimary_goal languagepain_points (solution framing)decision_triggerIf an ad group serves multiple personas (common in broad campaigns), create separate ad variants — one optimized per persona — and A/B test which performs better.
Google's ad strength score optimizes for Google's internal ad diversity goals, not your conversion rate. Treat it as a secondary signal, never a primary optimization target.
| Situation | Action |
|---|---|
| "Excellent" ad strength, CTR < 2% | Ad strength is misleading. The headlines are varied but not compelling. Rewrite for relevance over diversity |
| "Good" ad strength, CTR > 5% | Do not touch this ad to chase "Excellent". The ad is working. Ad strength is a vanity metric here |
| "Poor" ad strength, CTR > industry avg | Add more headline/description variety to satisfy Google's diversity requirement, but don't change the winning headlines |
| "Poor" ad strength, CTR < industry avg | Both signals agree — the ad needs a rewrite. Start with headline relevance to keywords |
| Ad strength drops after headline edit | If CTR improved, ignore the ad strength drop. If CTR also dropped, revert |
Read {data_dir}/business-context.json competitors and differentiators fields. If empty, infer competitors from auction overlap (high impression share keywords where rank-lost IS is elevated suggest active competitors).
| Rule | Rationale |
|---|---|
| NEVER name competitors in ad copy | Policy violation risk with Google Ads. Also sends brand awareness to competitors. Even "Better than [Competitor]" is dangerous |
| NEVER use "best" or "#1" without qualification | Google requires substantiation for superlative claims. "Best-Rated on Google" is OK if verifiable. "Best Plumber" is not |
| DO use specific features competitors lack | "Same-Day Service" beats "Better Service". Specificity implies superiority without claiming it |
| DO use pricing advantage if real | "Flat-Rate Pricing" or "From $99" differentiates against competitors with opaque pricing |
| DO use trust signals aggressively | "25+ Years", "4.9★ Google Rating", "500+ 5-Star Reviews" — these are verifiable and powerful |
| DO use location specificity | "Seattle's Own [Service]" or "Locally Owned Since 1998" differentiates against national chains |
| DO use speed/convenience | "Same-Day", "24/7", "Book Online in 60 Seconds" — operational advantages competitors may not match |
| DO use guarantees | "Satisfaction Guaranteed", "Free Re-Service", "No Fix, No Fee" — risk reversal converts |
Based on the competitive landscape, choose the strongest angle:
| Business Situation | Best Differentiation Angle | Example Headline |
|---|---|---|
| Competing against national chains | Local ownership, personal service, community ties | "Family-Owned Since 2005" |
| Competing against cheaper alternatives | Quality, guarantees, reviews, expertise | "Licensed & Insured Pros" |
| Competing against premium alternatives | Value, transparent pricing, same quality for less | "Premium Service, Fair Prices" |
| Unique service offering | The specific feature itself | "Same-Day Emergency Visits" |
| Crowded market, no clear advantage | Speed, convenience, or customer experience | "Book Online — Arrive in 1hr" |
Detect or ask:
listCampaigns → listAdGroups)Cross-reference against the business context — if the user says "write copy for boarding" and context has boarding details, you already know the angles.
Pull data before writing — copy should be grounded in what converts, not guesses.
Current ad performance (use GAQL for multi-campaign research, see ../shared/gaql-cookbook.md):
If the user specified a single campaign/ad group, use helper tools directly. If researching across campaigns (common for brand-wide copy refresh), use GAQL:
For single-campaign work, the per-campaign helpers are simpler:
listAds(campaignId) — existing headlines/descriptionsgetKeywords(campaignId) — active keywordsgetSearchTermReport(campaignId) — actual user queriesgetCampaignPerformance(campaignId) — CTR benchmarksUse seasonality context. If business context shows peak months, factor that into copy urgency. During slow months, lean on evergreen value props. During peaks, lean on scarcity and timeliness.
Use keyword landscape context. For competitive terms (high CPC, many bidders), copy must differentiate harder — lead with what's unique, not what everyone says. For long-tail terms, match the specific intent closely.
If the user has a database with lead/conversion data, query it to find which keywords and messaging actually convert. The language paying customers use is the language your ads should mirror.
Google RSA: up to 15 headlines (30 chars max) and 4 descriptions (90 chars max). Google's AI mixes and matches them.
Always count characters. Flag any that exceed limits. A single character over = rejected by Google.
See references/rsa-best-practices.md — Headline Formula Table (27 formulas across 8 categories) and Description Formula Table (5 formulas). Use those as the source of truth for all copy generation.
Headline selection rules:
Description selection rules:
Show 2-3 variants, each with a distinct messaging angle. Name the angle so it's clear what's being tested.
VARIANT A: "[Angle Name — e.g., Trust & Experience]"
Target persona: [persona name from {data_dir}/personas/]
H1 [Pin 1]: [Service] in [Location] (XX chars)
H2: [Value prop headline] (XX chars)
H3: [Trust headline] (XX chars)
H4: [CTA headline] (XX chars)
... (up to 15 headlines)
D1: [Core value + location — max 90 chars] (XX chars)
D2: [Differentiator + CTA — max 90 chars] (XX chars)
D3: [Trust + proof — max 90 chars] (XX chars)
D4: [Urgency/offer — max 90 chars] (XX chars)
VARIANT B: "[Different Angle — e.g., Price & Value]"
Target persona: [persona name]
H1 [Pin 1]: ...
...
Always show character counts. Always show pin positions. Always name the target persona.
Variant differentiation rules:
After user approves a variant, push it live:
createAd — create the RSA in the target ad group (created paused)updateAdAssets — replace headlines/descriptions on a live adenableAdAlways confirm before any write operation. Note the changeId returned — user can undo within 7 days (if the entity hasn't been modified since) via undoChange.
(Call tools under the MCP prefix detected by the shared preamble — do not hardcode mcp__adsagent__.)
Statistical significance rules:
After the test period, pull results:
listAds → compare metrics for each variant
| Variant | Impressions | Clicks | CTR | Conversions | Conv Rate | CPA | Winner? |
|---|---|---|---|---|---|---|---|
| A | |||||||
| B |
Interpretation matrix:
| CTR | Conv Rate | Diagnosis | Action |
|---|---|---|---|
| A higher | A higher | Clear winner | Pause B. Iterate on A's angle with fresh headlines |
| A higher | B higher | A attracts more clicks but B converts better | Keep B as primary. Test A's headlines on B's landing page — the click-through message may need landing page alignment. Offer /ads-landing |
| Similar | Similar | No meaningful difference | Need a bolder test — the variants were too similar. Change the core messaging angle, not just word choice |
| Both low | Both low | Neither variant works | The problem isn't A vs B — it's the overall approach. Check: keyword intent match, landing page quality, offer strength. May need /ads-audit to diagnose |
After deciding a winner: pause the loser with pauseAd, keep the winner running. Then create a new variant to test against the winner — continuous improvement, never stop testing.
{data_dir}/business-context.json before doing anything. If it doesn't exist, build it./ads./ads-audit to build them.