Loading...
Loading...
The Quality Score Optimization skill provides a systematic framework for diagnosing, tracking, and improving Quality Score across every keyword in a Google Ads account.
npx skill4agent add itallstartedwithaidea/agent-skills quality-score-optimizationflowchart TD
A[Google Ads API:\nKeyword Quality Data] --> B[QS Data Extraction]
B --> C[Current QS Snapshot]
B --> D[Historical QS Tracking]
B --> E[Sub-Component Breakdown]
E --> F[Expected CTR Analysis]
E --> G[Ad Relevance Analysis]
E --> H[Landing Page Experience Analysis]
F --> I[CTR Improvement Engine]
I --> I1[Ad Copy Testing]
I --> I2[Ad Extension Optimization]
I --> I3[Audience Refinement]
G --> J[Relevance Improvement Engine]
J --> J1[Keyword-Ad Alignment]
J --> J2[Ad Group Restructuring]
J --> J3[DKI Opportunities]
H --> K[Landing Page Improvement Engine]
K --> K1[Page Speed Optimization]
K --> K2[Content Relevance Matching]
K --> K3[Mobile Experience Audit]
I1 --> L[Spend-Weighted Priority Ranker]
I2 --> L
I3 --> L
J1 --> L
J2 --> L
J3 --> L
K1 --> L
K2 --> L
K3 --> L
L --> M[QS Improvement Plan]
M --> N[Estimated CPC Savings]
M --> O[Implementation Roadmap]
M --> P[Progress Tracking Dashboard]async function analyzeQualityScores(customerId) {
const keywordData = await getKeywordQualityData(customerId);
const analysis = keywordData.map(kw => ({
keyword: kw.text,
matchType: kw.matchType,
qualityScore: kw.qualityScore,
expectedCtr: kw.expectedCtr,
adRelevance: kw.adRelevance,
landingPageExperience: kw.landingPageExperience,
monthlySpend: kw.costMicros / 1_000_000,
impressions: kw.impressions,
weightedImpact: calculateWeightedImpact(kw)
}));
return {
distribution: buildQSDistribution(analysis),
bottomKeywords: analysis.filter(kw => kw.qualityScore <= 5)
.sort((a, b) => b.weightedImpact - a.weightedImpact),
componentBreakdown: analyzeComponents(analysis),
estimatedSavings: estimateCPCSavings(analysis),
improvementPlan: generateImprovementPlan(analysis)
};
}
function calculateWeightedImpact(keyword) {
const spendWeight = keyword.costMicros / 1_000_000;
const qsDeficit = 10 - keyword.qualityScore;
const cpcSavingsPerPoint = keyword.avgCpc * 0.12;
return spendWeight * qsDeficit * cpcSavingsPerPoint;
}
function analyzeComponents(keywords) {
const components = { expectedCtr: [], adRelevance: [], landingPageExperience: [] };
for (const kw of keywords) {
if (kw.expectedCtr === 'BELOW_AVERAGE') components.expectedCtr.push(kw);
if (kw.adRelevance === 'BELOW_AVERAGE') components.adRelevance.push(kw);
if (kw.landingPageExperience === 'BELOW_AVERAGE') components.landingPageExperience.push(kw);
}
return {
expectedCtr: {
belowAverage: components.expectedCtr,
totalSpendAffected: sumSpend(components.expectedCtr),
strategies: [
'Test new ad copy with stronger CTAs and benefit statements',
'Add sitelink and callout extensions to increase ad real estate',
'Refine audience targeting to reach higher-intent users',
'Use ad customizers for time-sensitive or location-specific messaging'
]
},
adRelevance: {
belowAverage: components.adRelevance,
totalSpendAffected: sumSpend(components.adRelevance),
strategies: [
'Restructure ad groups to tighter keyword themes (max 15-20 keywords)',
'Include exact keyword text in at least 2 headlines per RSA',
'Use dynamic keyword insertion where natural',
'Create SKAGs for highest-spend keywords with persistent relevance issues'
]
},
landingPageExperience: {
belowAverage: components.landingPageExperience,
totalSpendAffected: sumSpend(components.landingPageExperience),
strategies: [
'Improve page load speed (target under 3 seconds on mobile)',
'Ensure keyword-relevant content appears above the fold',
'Add trust signals: reviews, certifications, security badges',
'Optimize mobile layout with clear CTA and minimal form fields'
]
}
};
}async function trackQualityScoreHistory(customerId, keyword, days = 180) {
const snapshots = await getHistoricalQSSnapshots(customerId, keyword, days);
return {
trend: calculateTrend(snapshots),
changePoints: detectChangePoints(snapshots),
correlations: correlateWithAccountChanges(snapshots, customerId),
forecast: forecastQS(snapshots, 30)
};
}
function estimateCPCSavings(keywords) {
let totalMonthlySavings = 0;
for (const kw of keywords) {
if (kw.qualityScore < 7) {
const targetQS = Math.min(kw.qualityScore + 2, 10);
const qsImprovement = targetQS - kw.qualityScore;
const cpcReduction = qsImprovement * 0.12;
const monthlySavings = kw.monthlySpend * cpcReduction;
totalMonthlySavings += monthlySavings;
}
}
return { estimatedMonthlySavings: totalMonthlySavings, annualized: totalMonthlySavings * 12 };
}| Platform | Supported |
|---|---|
| Claude Code | ✅ |
| Cursor | ✅ |
| Codex | ✅ |
| Gemini | ✅ |