google-ads-landing
Score and diagnose Google Ads landing pages. Use when asked to audit a landing page, check landing page quality, diagnose high-CTR but low-conversion-rate ad groups, improve Quality Score's Landing Page Experience component, or compare an ad group's messaging against its landing
Install
npx skills add https://github.com/nowork-studio/notfair-plugin/tree/main/google-ads/landing
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install nowork-studio-notfair-plugin@llmmart
git clone https://github.com/nowork-studio/notfair-plugin.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole nowork-studio/notfair-plugin collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Setup
Read and follow ../shared/preamble.md (MCP detection, account selection) and ../shared/analysis-principles.md (evidence requirement, guardrails). Both apply throughout this skill — every dimension below is a measurement, not an opinion.
Landing Page Scoring + Diagnostic
Google Ads campaigns fail on the landing page more often than in the auction. A great RSA that sends traffic to a slow, unfocused, or mismatched page burns budget twice — once on the click, once on the lost conversion. This skill scores landing pages on 5 weighted dimensions and emits concrete fixes.
Only score pages that actually run ad traffic. Don't score random marketing pages. Run this on direct request, on auto-handoff from /google-ads-audit (high-CTR / low-CVR ad groups), when QS diagnosis flags "Landing Page Experience: Below Average", or as a preflight before /google-ads-copy writes new copy for a page nobody's validated.
When the question is about ad-to-page fit, high CTR / low CVR, LPX, or testing ads and landing pages together, read references/message-chain-testing.md before scoring. It keeps the diagnosis focused on the paid-search message chain instead of drifting into a generic web-design audit.
Reference
references/scoring-rubric.md— the 5-dimension weighted rubric, thresholds, and evidence fields. Read before scoring.references/message-chain-testing.md— query → ad → page message-chain diagnosis and ad+LP test design.../manage/references/quality-score-framework.md— only when the user's explicit goal is QS improvement.
Phase 1: Resolve the target pages
Figure out which URLs to score. In priority order:
- User supplied a URL — score that page, skip discovery.
- User supplied an ad group or campaign name — retrieve the ads for that ad group or campaign using an available read capability and extract their final URLs. Normalize (strip tracking params, preserve path + query that affects routing).
- Auto-handoff from
/google-ads-audit— the handoff passes the specific ad groups flagged. Pull their final URLs the same way. - No arguments — retrieve account ad URLs and rank them by spend over an appropriate recent period, propose the top 3, ask the user to confirm.
De-duplicate aggressively. Many ads point to the same final URL — score each unique URL once, then map back to every ad group that uses it.
Phase 2: Gather signal (parallel)
Do all of these in a single tool-use turn:
- WebFetch the landing page — capture visible headline, subheadline, primary CTA text, form fields, trust signals, body copy tone. Capture the full HTML so we can spot script bloat and above-the-fold content.
- PageSpeed Insights API call —
https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={url}&strategy=mobile&category=performance&category=accessibility&category=best-practices&category=seovia WebFetch. No API key needed for single-URL queries. Extract LCP, CLS, INP, TTI, performance score, and the top 3 opportunities fromlighthouseResult.audits. - Pull the referring ad copy and the ad group's conversion metrics — retrieve headline/description text for message match and the associated clicks, conversions, and conversion rate for the impact estimate. Choose the available reads and batch them when useful.
- Read
{data_dir}/business-context.json— for brand voice, differentiators, offers, target audience. If missing, point the user to/google-ads-auditfirst. Don't guess the business.
If any single call fails, continue — note the gap in the report rather than blocking. PageSpeed Insights can rate-limit; if it does, fall back to a manual timing annotation ("PSI unavailable — could not score Page Speed") and deflate the final report's confidence rather than skipping the dimension.
Phase 3: Score the page
Read references/scoring-rubric.md and score each dimension 0-100 with evidence. The dimension scores are real measurements (PageSpeed Insights numbers, word-for-word copy comparison, form field counts, etc.) — they're not artificial ratings, they're observations.
Compute the weighted composite only as an internal reference number for the dollar-lift formula below. Do not surface it as a letter grade. The user sees the dimension-level measurements and the estimated dollar lift — the composite is plumbing.
internal_composite = 0.25 * Message Match
+ 0.25 * Page Speed
+ 0.20 * Mobile Experience
+ 0.15 * Trust Signals
+ 0.15 * Form & CTA
Dollar lift is the headline. If business-context.json.unit_economics has aov_usd + profit_margin, compute the estimated monthly lift from raising the composite by 15 points (see ../shared/ppc-math.md):
Target lift = min(+15, 90 - internal_composite) # cap at 90 internal
Assumed CVR lift = target_lift / 100 * 0.5 # cap at 50% relative lift
Current conversions = ad group conversions from last 30d
Additional conversions = current_conversions * assumed_CVR_lift
Additional revenue = additional_conversions * AOV
Additional profit = additional_conversions * AOV * profit_margin
Present the lift as fixing this page is worth ~$X/mo in profit — never as a guarantee. The 50% cap on CVR lift and the 15-point cap on score improvement keep estimates out of fantasy territory. If unit_economics isn't available, skip the dollar line entirely rather than making up a number — the dimension measurements still stand on their own.
Phase 4: Deliver the report
Max 60 lines. Lead with the dollar lift (when available) and the single biggest fix. No letter grade.
# Landing Page — [URL]
Ads sending traffic here: [N ad groups] · [X clicks/mo] · [$Y spent/mo] · CVR [Z%]
[If unit_economics available] **Estimated lift from top 3 fixes: ~$X/mo in profit**
[If unit_economics is missing] _(Dollar lift unavailable — no verified AOV/margin. Confirm unit economics in business-context.json for sharper estimates.)_
**Biggest leak:** [one sentence naming the dimension and the specific observation, e.g. "LCP is 5.8s on mobile — 2.8s slower than the 3s threshold that kills conversion rate."]
## Measurements
| Dimension | Measurement | Top Finding |
|-----------|-------------|-------------|
| Message Match | [word-for-word verdict: Match / Drift / Broken] | [one line citing ad H1 vs page H1] |
| Page Speed | LCP Xs · INP Xms · CLS X · PSI perf score X | [top blocking audit from Lighthouse] |
| Mobile Experience | PSI accessibility X · [mobile-specific issue count] | [one line: e.g. "No click-to-call, form below fold"] |
| Trust Signals | [review count, years in business, cert count] | [one line: e.g. "Zero named testimonials, copyright 2023"] |
| Form & CTA | [field count] fields · CTA text: "[button]" · [above/below fold] | [one line: e.g. "11 fields for a free quote"] |
## Fix First (top 3, ranked by estimated $ lift)
1. **[Action]** — est. +$X/mo · `<time_to_fix>`
Evidence: [the actual text/number from the page or PSI audit]
2. **[Action]** — est. +$X/mo · `<time_to_fix>`
Evidence: [...]
3. **[Action]** — est. +$X/mo · `<time_to_fix>`
Evidence: [...]
## Message Match Detail
Ad headline: "[actual headline from top-spending ad]"
Page H1: "[actual H1 from landing page]"
Observation: [Match / Drift / Broken] — [one-line rationale citing the specific words that match or don't]
## Handoff
[Pick one:]
- Page speed dominates the problem → "Share these fixes with your developer: [list]"
- Message mismatch dominates → "Run /google-ads-copy to rewrite ads to match the page, or update the page to match the ads"
- Form friction dominates → "Reduce form to [specific fields]. Every removed field is ~10% more conversions"
Writing back to history
Append the score to {data_dir}/landing-page-history.json so re-audits can show deltas:
{
"pages": {
"https://example.com/services/roofing": {
"history": [
{
"date": "2026-04-14",
"internal_composite": 67,
"dimensions": {
"message_match": 72,
"page_speed": 45,
"mobile": 80,
"trust": 70,
"form_cta": 65
},
"psi_mobile_lcp_s": 4.2,
"psi_mobile_cls": 0.15,
"psi_mobile_inp_ms": 320,
"estimated_lift_usd_per_month": 380,
"ad_groups": ["Example City Search - Roofing"],
"monthly_spend": 1240.50,
"monthly_cvr": 2.1,
"biggest_leak": "Page Speed — LCP 4.2s on mobile"
}
]
}
}
}
internal_composite is stored for trend tracking only — it's the internal reference number used by the dollar-lift formula, never shown to the user as a letter grade. On subsequent runs against the same URL, diff the raw dimension measurements and the dollar lift: LCP 4.2s → 2.1s · Page Speed 45 → 78 · estimated lift $380/mo → $120/mo remaining. Three measurements moved, no artificial grade flip.
Rules
- Never score a page without WebFetch'ing it. The rubric demands evidence. No WebFetch = no score. Ask the user to help if the page is gated or requires auth.
- Never report a PSI number you didn't measure. If PSI failed, say "PSI unavailable" — don't estimate.
- One page at a time unless the user asks for multiple. Scoring three pages in one turn creates unreadable reports. Batch only when explicitly requested.
- Don't rewrite copy here. This skill diagnoses the page. Handoff to
/google-ads-copyfor new headlines or/google-adsfor bid/negative/budget moves. - Margin-aware dollar impact requires verified unit economics. If
unit_economics.source == "inferred_from_template", append_(using industry defaults — confirm your AOV/margin for sharper estimates)_to the lift line. - Always persist. Every scored page goes into
landing-page-history.json, even if the user doesn't ask — future audits depend on the baseline.
Files (notfair-plugin)
-
evals
-
evals.json 848 B
{ "skill_name": "google-ads-landing", "evals": [ { "id": 1, "prompt": "audit this landing page for my Google Ads traffic: https://example.com/roof-repair. CTR is solid but conversions are weak — tell me what's hurting the page and what to fix first.", "expected_output": "A landing-page diagnostic covering message match, speed/mobile UX, trust signals, CTA/form friction, and the single highest-impact fix.", "files": [], "expectations": [ "Scores or diagnoses the page across the landing-page rubric dimensions", "Checks message match between ad intent and page copy", "Calls out page speed or mobile UX as part of the analysis", "Identifies trust-signal or CTA/form friction issues", "Prioritizes the top fix instead of giving an unranked list" ] } ] }
-
-
references
-
message-chain-testing.md 3.8 KB
# Ad + Landing Page Message-Chain Testing Use this when landing-page experience, high CTR / low CVR, Quality Score LPX, or ad-copy testing points to a mismatch between the query, ad, and landing page. Core idea: sometimes you are not testing an ad or a page in isolation — you are testing a **message chain**. Query intent → RSA promise → landing-page headline/offer/form must reinforce one another. --- ## 1. Map the message chain For each target ad group or URL, collect: - Top search terms and converting terms. - Active RSA headlines/descriptions and pinned assets. - Final URL, H1, hero subheadline, CTA, form fields, trust proof. - Keyword QS components if available, especially ad relevance and landing-page experience. - Last 30d clicks, spend, CTR, CVR, conversions, CPA/ROAS. Then classify: - **Match:** query phrase, ad promise, and page H1/offer use the same concept. - **Drift:** same general business, but page does not reinforce the exact promise. - **Broken:** ad promises one thing and page leads with another. Examples: - Query: `Seattle bookkeeping services`; ad: `Bookkeeping from $190/mo`; page H1: `Seattle & King County Bookkeeping Services` → strong match. - Query: `QuickBooks cleanup`; ad: `QuickBooks Cleanup Help`; page H1: generic `Accounting Services` → drift. --- ## 2. Decide test design ### Ad-only test Use when page is already tightly aligned and the bottleneck is CTR/ad relevance. ### Landing-page-only test Use when ads are clear and CTR is healthy, but CVR / LPX / form friction is weak. ### Paired message-chain test Use when the angle changes both ad and page promise, e.g.: - `Free bookkeeping review` ad → page hero and form explicitly offer the review. - `QuickBooks cleanup` ad → page hero, proof, FAQ, and CTA are cleanup-specific. - `NotFair for Claude MCP` ad → page hero clarifies NotFair + Claude/Codex/OpenClaw compatibility. ### Full factorial ad × page test Use when you need to know whether the ad, page, or their combination drives the win. This requires enough traffic and clean tracking; otherwise it creates noise. --- ## 3. What to fix first Prioritize by evidence: 1. **Broken message match** — update H1/hero/CTA or rewrite RSA to match the page. 2. **Missing trust proof** — add reviews, local proof, certifications, price transparency, client type, examples. 3. **Form friction** — reduce fields, clarify what happens next, make CTA specific. 4. **Mobile/page speed** — if PSI or manual browser evidence shows slow LCP/interaction problems. 5. **Offer ambiguity** — if the ad says free/review/quote but the page hides or dilutes it. Do not redesign the entire page when a specific above-the-fold message change would fix the paid-search problem. --- ## 4. Reporting format Lead with the concrete chain: - Search term theme: `<actual query/theme>` - Top ad promise: `<headline/description>` - Page H1 / CTA: `<actual text>` - Verdict: Match / Drift / Broken - Fix first: `<single above-the-fold change>` - Why: `<metric + window>` For small accounts, keep recommendations conservative. One high-CPC click can look dramatic; the right proposal may be "watch for 3–5 more relevant clicks" if traffic is clean but sample is tiny. --- ## 5. Mutation boundary This skill diagnoses pages. If the repo/site is available and the user asks for local page edits, make the smallest page change and verify with browser screenshots / HTML checks. If only Google Ads changes are needed, hand off to `/google-ads-copy` for RSA assets or `/google-ads` for final URL / experiment changes. Always avoid form submissions unless explicitly approved; they can trigger client emails or CRM automations. --- ## Sources - `../../shared/ppc-optimization-pattern-playbook.md` — landing page and ad+LP testing modules. - General landing-page experience, ad+landing-page testing, customer-journey testing, and Quality Score patterns. -
scoring-rubric.md 10.4 KB
# Landing Page Measurement Rubric Five dimensions, each measured against real evidence. The dimension scores are observations (real PageSpeed Insights numbers, word-for-word ad-to-page comparison, form field counts) — not artificial ratings. There is no letter grade. The report surfaces each dimension's measurement and the top finding, plus a dollar-denominated lift estimate. Internally, the skill computes a weighted composite only to feed the lift formula: ``` internal_composite = 0.25 × Message Match + 0.25 × Page Speed + 0.20 × Mobile Experience + 0.15 × Trust Signals + 0.15 × Form & CTA ``` The two 25% dimensions (Message Match, Page Speed) are deliberately weighted equally — Google's Landing Page Experience QS component considers both, and real-world CVR correlates strongly with both. Everything else is secondary. The 0-100 scores per dimension are kept as internal numbers for history tracking and the lift formula; the user-facing report cites the underlying measurement (LCP seconds, field count, H1 word match) rather than the score. --- ## 1. Message Match (25%) *"Did the user arrive where they expected?"* The ad promises something. The page must deliver it within 3 seconds of scroll-free viewing. This is the single strongest predictor of CVR lift. ### Scoring | Score | Rubric | |-------|--------| | 90-100 | Page H1 contains the ad's promise word-for-word or a tight synonym. Subhead reinforces. CTA matches the ad's action verb. Offer in ad (if any) is front-and-center on the page | | 75-89 | H1 clearly relates to the ad's service and location. Primary CTA matches ad intent. Minor drift in tone or offer language | | 60-74 | Page is on-topic but generic — H1 says "Quality Roofing Services" when the ad said "Emergency Roof Repair in Example City". User has to infer the connection | | 45-59 | Page is about the business but not about the ad's specific angle. Ad pushed urgency, page is evergreen. Ad pushed a specific service, page is a services overview | | <45 | Homepage, category page, or completely mismatched content. Ad said "free quote", page has no quote CTA. Ad said "24/7", page shows business hours | ### Evidence to capture - **Ad headline 1** (the one most users see) vs. **Page H1** — quote both verbatim in the report - **Ad CTA verb** (Get, Book, Call, Shop) vs. **Primary page button text** - **Offer in ad** (if any) vs. **offer visible above the fold** - **Location from ad** (if geo-targeted) vs. **location shown on page** - **Keyword from search query** (pull top search term for the ad group) — does it appear on the page at all? ### Common failure patterns | Pattern | Fix | |---------|-----| | Ad points to homepage | Build a service-specific landing page or change final URL | | Ad headline promises a discount, page has no mention | Either remove the discount from ad or add it to page hero | | Ad pushes one service, page lists 15 | Send traffic to a single-service page | | Ad says "free estimate", page says "call for pricing" | Align the CTA or expand the pricing page | --- ## 2. Page Speed (25%) *"Can the user even see the page before bouncing?"* Measured via PageSpeed Insights API on mobile (Google's default crawl profile for ads since 2019). Desktop is secondary. ### Scoring (based on mobile Core Web Vitals) | Score | LCP | INP | CLS | Notes | |-------|-----|-----|-----|-------| | 90-100 | <2.0s | <100ms | <0.05 | All three in green. Page feels instant | | 75-89 | 2.0-2.5s | 100-200ms | 0.05-0.10 | Mostly green, one metric in yellow | | 60-74 | 2.5-4.0s | 200-500ms | 0.10-0.25 | All yellow, or one metric in red | | 45-59 | 4.0-6.0s | 500-1000ms | 0.25-0.40 | Two metrics in red | | <45 | >6.0s | >1000ms | >0.40 | All three red. User bounced before LCP fired | If PSI returns a performance score directly, use that as a tiebreaker within the band the vitals place you in. ### Evidence to capture - LCP (s), INP (ms), CLS (unitless), Performance Score (0-100) — all from mobile strategy - Top 3 `lighthouseResult.audits` with `score < 0.5` and `details.overallSavingsMs > 200` — these are the biggest levers - Total page weight (kB), number of blocking scripts, number of image requests ### Common failure patterns | Audit | Typical fix | |-------|------------| | `uses-optimized-images` | Serve WebP/AVIF, compress hero image | | `render-blocking-resources` | Defer or async third-party scripts (analytics, chat widgets, tag managers) | | `unused-javascript` | Remove marketing tags that aren't being read (Facebook Pixel on a B2B page, etc.) | | `largest-contentful-paint-element` points to a hero image | Preload the hero image, set explicit dimensions to prevent CLS | | `uses-long-cache-ttl` | Configure CDN cache headers | --- ## 3. Mobile Experience (20%) *"Does the page work with a thumb?"* 70%+ of Google Ads traffic is mobile. A page that renders but is unusable on a 375px viewport is worse than a slow page — users rage-quit. ### Scoring | Score | Rubric | |-------|--------| | 90-100 | Tap targets >48px. Text >=16px body. Sticky CTA or phone number in mobile viewport. Form fits without horizontal scroll. No popups that cover content. PSI accessibility >95 | | 75-89 | Tap targets adequate, text readable. One minor issue (e.g., hero text partially cropped, footer form below fold) | | 60-74 | 2+ mobile issues: small tap targets, zoomed-out default viewport, form requires zoom to complete, CTA below fold | | 45-59 | Unusable without pinch-zoom. Content overflows. Multiple popups. PSI accessibility <75 | | <45 | Desktop-only site. No mobile viewport meta. Broken rendering | ### Evidence to capture - `viewport` meta tag present and correct (`width=device-width, initial-scale=1`) - PSI mobile accessibility score - Visible above-the-fold content on mobile (from WebFetch rendered markup) - Presence of click-to-call link (`tel:` anchor) — critical for service businesses - Presence of sticky mobile CTA - Popup/interstitial detection — any element with `position: fixed` and `z-index > 1000` covering content ### Common failure patterns | Pattern | Fix | |---------|-----| | Phone number not click-to-call | Wrap in `<a href="tel:...">` | | No sticky mobile CTA | Add bottom-fixed button bar with primary action | | Hero image dominates viewport, pushes headline below fold | Reduce hero size, move headline up | | Popup appears on load | Delay to 30s scroll or remove entirely on paid-traffic pages | --- ## 4. Trust Signals (15%) *"Would a stranger give this page their credit card or phone number?"* Trust is the invisible conversion tax. Even a perfect ad-to-page match with blazing speed will lose conversions if the page feels sketchy. ### Scoring | Score | Rubric | |-------|--------| | 90-100 | All of: real reviews/testimonials with names, star rating visible, trust badges (BBB, industry certs), years in business, physical address, phone number, photos of real people/work | | 75-89 | Most of the above. One category missing (e.g., no certs but strong reviews) | | 60-74 | Generic trust signals only: stock-photo testimonials, no names, no specifics | | 45-59 | No reviews, no address, no photos. Just marketing copy | | <45 | Active distrust signals: broken links, copyright year 3 years old, typos, contact form only (no phone) | ### Evidence to capture - Review count and star rating (visible on page) - Named testimonials (first name + last initial minimum) - Physical address - Phone number (ideally click-to-call) - HTTPS + valid certificate - Copyright year — must be current or last year - Privacy policy link (critical for lead-gen compliance) ### Common failure patterns | Pattern | Fix | |---------|-----| | No reviews on page | Pull from `business-context.json.social_proof` and add a reviews section | | Copyright 2023 in 2026 | Update footer — tiny fix, surprisingly high impact on trust perception | | No phone number on a service page | Add one, use click-to-call | | Stock photos of "our team" | Replace with real photos, even phone-quality beats stock | --- ## 5. Form & CTA (15%) *"Can the user actually convert?"* The page can be perfect, but if the form has 11 fields or the button says "Submit", conversions leak out here. ### Scoring | Score | Rubric | |-------|--------| | 90-100 | Primary CTA above fold, action-oriented ("Get My Free Quote", not "Submit"). Form has 3-4 fields max for lead gen. Clear value prop next to form ("We'll respond within 24h"). No dark patterns | | 75-89 | CTA visible, form reasonable (5-6 fields), button copy active. One friction point | | 60-74 | CTA below fold OR form has 7-8 fields OR button is generic ("Submit", "Send") | | 45-59 | Multiple friction: 9+ field form, generic CTA, no value prop near form, unclear what happens after submit | | <45 | No clear CTA, form broken, or form requires login/account creation before conversion | ### Evidence to capture - Number of form fields (required vs. optional) - Button text verbatim - Above-fold CTA presence (from WebFetch'd markup, estimate using viewport-sized window) - Secondary CTAs that might compete with the primary (too many CTAs = analysis paralysis) - Trust reinforcement next to form (privacy note, response time, guarantee) ### Common failure patterns | Pattern | Fix | |---------|-----| | Form has 10 fields for a "free estimate" | Reduce to name, phone, service type — everything else can wait for the follow-up call | | Button says "Submit" or "Send" | Change to the action ("Get My Free Quote", "Book My Consultation") | | Primary CTA below fold | Move above fold or add a sticky header CTA | | Phone number hidden in footer | Put it in the header AND next to the form | --- ## Calibration notes - **Don't over-weight speed for non-e-commerce.** A lead-gen page with LCP 3.5s and message-match 95 will convert better than LCP 1.5s with message-match 60. The weighted formula handles this correctly — don't override it. - **Mobile accessibility floors the grade.** If PSI mobile accessibility < 60, cap Mobile Experience at 59 regardless of other factors. Broken accessibility is a trust/legal issue. - **Don't trust average CVR as a benchmark without context.** A legal services page at 2% CVR is healthy; an e-commerce page at 2% CVR is broken. Use `industry-templates.json` → `typical_cvr` as the baseline. - **Confidence decays with missing data.** If PSI didn't run, cap the final score at 85 (can't grade A without speed data). If `business-context.json` is missing, cap Message Match at 80 (can't validate brand voice).
-
-
SKILL.md 10.5 KB
--- name: google-ads-landing description: Score and diagnose Google Ads landing pages. Use when asked to audit a landing page, check landing page quality, diagnose high-CTR but low-conversion-rate ad groups, improve Quality Score's Landing Page Experience component, or compare an ad group's messaging against its landing page. Trigger on "landing page audit", "landing page score", "landing page quality", "why is my conversion rate low", "LPX", "landing page experience", "ad to page match", or when `/google-ads-audit` surfaces a high-CTR / low-CVR ad group. argument-hint: "<landing page URL or ad group name>" --- ## Setup Read and follow `../shared/preamble.md` (MCP detection, account selection) and `../shared/analysis-principles.md` (evidence requirement, guardrails). Both apply throughout this skill — every dimension below is a measurement, not an opinion. # Landing Page Scoring + Diagnostic Google Ads campaigns fail on the landing page more often than in the auction. A great RSA that sends traffic to a slow, unfocused, or mismatched page burns budget twice — once on the click, once on the lost conversion. This skill scores landing pages on **5 weighted dimensions** and emits concrete fixes. Only score pages that actually run ad traffic. Don't score random marketing pages. Run this on direct request, on auto-handoff from `/google-ads-audit` (high-CTR / low-CVR ad groups), when QS diagnosis flags "Landing Page Experience: Below Average", or as a preflight before `/google-ads-copy` writes new copy for a page nobody's validated. When the question is about ad-to-page fit, high CTR / low CVR, LPX, or testing ads and landing pages together, read `references/message-chain-testing.md` before scoring. It keeps the diagnosis focused on the paid-search message chain instead of drifting into a generic web-design audit. ## Reference - `references/scoring-rubric.md` — the 5-dimension weighted rubric, thresholds, and evidence fields. Read before scoring. - `references/message-chain-testing.md` — query → ad → page message-chain diagnosis and ad+LP test design. - `../manage/references/quality-score-framework.md` — only when the user's explicit goal is QS improvement. ## Phase 1: Resolve the target pages Figure out which URLs to score. In priority order: 1. **User supplied a URL** — score that page, skip discovery. 2. **User supplied an ad group or campaign name** — retrieve the ads for that ad group or campaign using an available read capability and extract their final URLs. Normalize (strip tracking params, preserve path + query that affects routing). 3. **Auto-handoff from `/google-ads-audit`** — the handoff passes the specific ad groups flagged. Pull their final URLs the same way. 4. **No arguments** — retrieve account ad URLs and rank them by spend over an appropriate recent period, propose the top 3, ask the user to confirm. **De-duplicate aggressively.** Many ads point to the same final URL — score each unique URL once, then map back to every ad group that uses it. ## Phase 2: Gather signal (parallel) Do all of these in a single tool-use turn: 1. **WebFetch the landing page** — capture visible headline, subheadline, primary CTA text, form fields, trust signals, body copy tone. Capture the full HTML so we can spot script bloat and above-the-fold content. 2. **PageSpeed Insights API call** — `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={url}&strategy=mobile&category=performance&category=accessibility&category=best-practices&category=seo` via WebFetch. No API key needed for single-URL queries. Extract LCP, CLS, INP, TTI, performance score, and the top 3 opportunities from `lighthouseResult.audits`. 3. **Pull the referring ad copy and the ad group's conversion metrics** — retrieve headline/description text for message match and the associated clicks, conversions, and conversion rate for the impact estimate. Choose the available reads and batch them when useful. 4. **Read `{data_dir}/business-context.json`** — for brand voice, differentiators, offers, target audience. If missing, point the user to `/google-ads-audit` first. Don't guess the business. If any single call fails, continue — note the gap in the report rather than blocking. PageSpeed Insights can rate-limit; if it does, fall back to a manual timing annotation ("PSI unavailable — could not score Page Speed") and deflate the final report's confidence rather than skipping the dimension. ## Phase 3: Score the page Read `references/scoring-rubric.md` and score each dimension 0-100 with evidence. The dimension scores are real measurements (PageSpeed Insights numbers, word-for-word copy comparison, form field counts, etc.) — they're not artificial ratings, they're observations. Compute the weighted composite only as an **internal reference number** for the dollar-lift formula below. Do not surface it as a letter grade. The user sees the dimension-level measurements and the estimated dollar lift — the composite is plumbing. ``` internal_composite = 0.25 * Message Match + 0.25 * Page Speed + 0.20 * Mobile Experience + 0.15 * Trust Signals + 0.15 * Form & CTA ``` **Dollar lift is the headline.** If `business-context.json.unit_economics` has `aov_usd` + `profit_margin`, compute the estimated monthly lift from raising the composite by 15 points (see `../shared/ppc-math.md`): ``` Target lift = min(+15, 90 - internal_composite) # cap at 90 internal Assumed CVR lift = target_lift / 100 * 0.5 # cap at 50% relative lift Current conversions = ad group conversions from last 30d Additional conversions = current_conversions * assumed_CVR_lift Additional revenue = additional_conversions * AOV Additional profit = additional_conversions * AOV * profit_margin ``` Present the lift as `fixing this page is worth ~$X/mo in profit` — never as a guarantee. The 50% cap on CVR lift and the 15-point cap on score improvement keep estimates out of fantasy territory. If `unit_economics` isn't available, skip the dollar line entirely rather than making up a number — the dimension measurements still stand on their own. ## Phase 4: Deliver the report Max 60 lines. Lead with the dollar lift (when available) and the single biggest fix. No letter grade. ``` # Landing Page — [URL] Ads sending traffic here: [N ad groups] · [X clicks/mo] · [$Y spent/mo] · CVR [Z%] [If unit_economics available] **Estimated lift from top 3 fixes: ~$X/mo in profit** [If unit_economics is missing] _(Dollar lift unavailable — no verified AOV/margin. Confirm unit economics in business-context.json for sharper estimates.)_ **Biggest leak:** [one sentence naming the dimension and the specific observation, e.g. "LCP is 5.8s on mobile — 2.8s slower than the 3s threshold that kills conversion rate."] ## Measurements | Dimension | Measurement | Top Finding | |-----------|-------------|-------------| | Message Match | [word-for-word verdict: Match / Drift / Broken] | [one line citing ad H1 vs page H1] | | Page Speed | LCP Xs · INP Xms · CLS X · PSI perf score X | [top blocking audit from Lighthouse] | | Mobile Experience | PSI accessibility X · [mobile-specific issue count] | [one line: e.g. "No click-to-call, form below fold"] | | Trust Signals | [review count, years in business, cert count] | [one line: e.g. "Zero named testimonials, copyright 2023"] | | Form & CTA | [field count] fields · CTA text: "[button]" · [above/below fold] | [one line: e.g. "11 fields for a free quote"] | ## Fix First (top 3, ranked by estimated $ lift) 1. **[Action]** — est. +$X/mo · `<time_to_fix>` Evidence: [the actual text/number from the page or PSI audit] 2. **[Action]** — est. +$X/mo · `<time_to_fix>` Evidence: [...] 3. **[Action]** — est. +$X/mo · `<time_to_fix>` Evidence: [...] ## Message Match Detail Ad headline: "[actual headline from top-spending ad]" Page H1: "[actual H1 from landing page]" Observation: [Match / Drift / Broken] — [one-line rationale citing the specific words that match or don't] ## Handoff [Pick one:] - Page speed dominates the problem → "Share these fixes with your developer: [list]" - Message mismatch dominates → "Run /google-ads-copy to rewrite ads to match the page, or update the page to match the ads" - Form friction dominates → "Reduce form to [specific fields]. Every removed field is ~10% more conversions" ``` ## Writing back to history Append the score to `{data_dir}/landing-page-history.json` so re-audits can show deltas: ```json { "pages": { "https://example.com/services/roofing": { "history": [ { "date": "2026-04-14", "internal_composite": 67, "dimensions": { "message_match": 72, "page_speed": 45, "mobile": 80, "trust": 70, "form_cta": 65 }, "psi_mobile_lcp_s": 4.2, "psi_mobile_cls": 0.15, "psi_mobile_inp_ms": 320, "estimated_lift_usd_per_month": 380, "ad_groups": ["Example City Search - Roofing"], "monthly_spend": 1240.50, "monthly_cvr": 2.1, "biggest_leak": "Page Speed — LCP 4.2s on mobile" } ] } } } ``` `internal_composite` is stored for trend tracking only — it's the internal reference number used by the dollar-lift formula, never shown to the user as a letter grade. On subsequent runs against the same URL, diff the raw dimension measurements and the dollar lift: `LCP 4.2s → 2.1s · Page Speed 45 → 78 · estimated lift $380/mo → $120/mo remaining`. Three measurements moved, no artificial grade flip. ## Rules 1. **Never score a page without WebFetch'ing it.** The rubric demands evidence. No WebFetch = no score. Ask the user to help if the page is gated or requires auth. 2. **Never report a PSI number you didn't measure.** If PSI failed, say "PSI unavailable" — don't estimate. 3. **One page at a time unless the user asks for multiple.** Scoring three pages in one turn creates unreadable reports. Batch only when explicitly requested. 4. **Don't rewrite copy here.** This skill diagnoses the page. Handoff to `/google-ads-copy` for new headlines or `/google-ads` for bid/negative/budget moves. 5. **Margin-aware dollar impact requires verified unit economics.** If `unit_economics.source == "inferred_from_template"`, append `_(using industry defaults — confirm your AOV/margin for sharper estimates)_` to the lift line. 6. **Always persist.** Every scored page goes into `landing-page-history.json`, even if the user doesn't ask — future audits depend on the baseline.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.