Loading...
Loading...
The Landing Page Audit skill performs comprehensive evaluations of post-click experiences, combining technical performance analysis with conversion rate optimization (CRO) assessment.
npx skill4agent add itallstartedwithaidea/agent-skills landing-page-auditflowchart TD
A[Landing Page URL] --> B[Parallel Analysis Pipeline]
B --> C[Technical Performance]
B --> D[Content & Relevance]
B --> E[CRO Assessment]
C --> C1[Core Web Vitals\nLCP, INP, CLS]
C --> C2[Page Speed\nTTFB, FCP, SI]
C --> C3[Resource Analysis\nRender-blocking, Images]
C --> C4[Mobile Performance\nViewport, Touch Targets]
D --> D1[Message Match Scoring\nAd Copy vs Page Content]
D --> D2[Keyword Relevance\nTarget Keywords in Content]
D --> D3[Content Quality\nReadability, Depth]
D --> D4[SEO Alignment\nMeta Tags, Headers]
E --> E1[CTA Analysis\nVisibility, Clarity, Urgency]
E --> E2[Form Audit\nField Count, Friction]
E --> E3[Trust Signals\nReviews, Badges, Social Proof]
E --> E4[Visual Hierarchy\nAbove-Fold Content, Layout]
C1 --> F[Scoring Engine]
C2 --> F
C3 --> F
C4 --> F
D1 --> F
D2 --> F
D3 --> F
D4 --> F
E1 --> F
E2 --> F
E3 --> F
E4 --> F
F --> G[Overall Landing Page Score]
G --> H[Prioritized Recommendations]
G --> I[Estimated QS Impact]
G --> J[Estimated CVR Improvement]async function auditLandingPage(url, config) {
const { adCopyText, targetKeywords, device = 'both' } = config;
const [technical, content, cro] = await Promise.all([
runTechnicalAudit(url, device),
runContentAudit(url, adCopyText, targetKeywords),
runCROAudit(url, device)
]);
const overallScore = calculateOverallScore(technical, content, cro);
return {
url,
overallScore,
technical,
content,
cro,
recommendations: prioritizeRecommendations(technical, content, cro),
estimatedQSImpact: estimateQualityScoreImpact(overallScore),
estimatedCVRImprovement: estimateCVRImprovement(cro)
};
}
async function runTechnicalAudit(url, device) {
const mobileMetrics = device !== 'desktop' ? await measurePerformance(url, 'mobile') : null;
const desktopMetrics = device !== 'mobile' ? await measurePerformance(url, 'desktop') : null;
const metrics = mobileMetrics || desktopMetrics;
return {
coreWebVitals: {
lcp: { value: metrics.lcp, rating: rateLCP(metrics.lcp) },
inp: { value: metrics.inp, rating: rateINP(metrics.inp) },
cls: { value: metrics.cls, rating: rateCLS(metrics.cls) }
},
additionalMetrics: {
ttfb: metrics.ttfb,
fcp: metrics.fcp,
speedIndex: metrics.speedIndex,
totalBlockingTime: metrics.tbt
},
resourceAnalysis: {
renderBlockingResources: metrics.renderBlocking,
unoptimizedImages: metrics.unoptimizedImages,
unusedCSS: metrics.unusedCSS,
unusedJS: metrics.unusedJS,
totalPageWeight: metrics.totalBytes
},
mobileUsability: {
viewportConfigured: metrics.hasViewport,
textReadable: metrics.fontSizeAdequate,
touchTargetsSized: metrics.touchTargetsAdequate,
contentFitsViewport: metrics.noHorizontalScroll
}
};
}
function rateLCP(ms) {
if (ms <= 2500) return { score: 'good', color: 'green' };
if (ms <= 4000) return { score: 'needs_improvement', color: 'orange' };
return { score: 'poor', color: 'red' };
}
function rateINP(ms) {
if (ms <= 200) return { score: 'good', color: 'green' };
if (ms <= 500) return { score: 'needs_improvement', color: 'orange' };
return { score: 'poor', color: 'red' };
}
function rateCLS(value) {
if (value <= 0.1) return { score: 'good', color: 'green' };
if (value <= 0.25) return { score: 'needs_improvement', color: 'orange' };
return { score: 'poor', color: 'red' };
}function scoreMessageMatch(adCopy, pageContent) {
const adHeadlines = adCopy.headlines.map(h => h.toLowerCase());
const adDescriptions = adCopy.descriptions.map(d => d.toLowerCase());
const pageText = pageContent.toLowerCase();
let matchScore = 0;
const headlineMatches = adHeadlines.filter(h =>
pageText.includes(h) || fuzzyMatch(h, pageText) > 0.8
);
matchScore += (headlineMatches.length / adHeadlines.length) * 40;
const keyPhrases = extractKeyPhrases([...adHeadlines, ...adDescriptions]);
const phraseMatches = keyPhrases.filter(p => pageText.includes(p));
matchScore += (phraseMatches.length / keyPhrases.length) * 30;
const aboveFoldContent = pageContent.aboveFold?.toLowerCase() || '';
const aboveFoldRelevance = keyPhrases.filter(p => aboveFoldContent.includes(p));
matchScore += (aboveFoldRelevance.length / keyPhrases.length) * 30;
return {
score: Math.round(matchScore),
headlinePresence: headlineMatches,
missingPhrases: keyPhrases.filter(p => !pageText.includes(p)),
aboveFoldRelevance: aboveFoldRelevance.length / keyPhrases.length
};
}
function auditCTA(pageData) {
return {
ctaPresent: pageData.ctaElements.length > 0,
ctaAboveFold: pageData.ctaElements.some(cta => cta.yPosition < pageData.viewportHeight),
ctaContrast: pageData.ctaElements.map(cta => ({
text: cta.text,
contrastRatio: calculateContrast(cta.color, cta.backgroundColor),
meetsWCAG: calculateContrast(cta.color, cta.backgroundColor) >= 4.5
})),
ctaClarity: evaluateCTAText(pageData.ctaElements),
ctaCount: pageData.ctaElements.length,
recommendation: pageData.ctaElements.length === 0
? 'Add a clear, prominent CTA above the fold'
: pageData.ctaElements.length > 3
? 'Reduce CTA options to avoid choice paralysis'
: 'CTA count is appropriate'
};
}
function auditForm(formData) {
return {
fieldCount: formData.fields.length,
frictionScore: calculateFormFriction(formData),
recommendations: [
formData.fields.length > 5 && 'Reduce form fields to 3-5 for higher completion rates',
!formData.hasProgressIndicator && formData.steps > 1 && 'Add progress indicator for multi-step forms',
!formData.hasInlineValidation && 'Add inline validation to reduce submission errors',
formData.requiredFields > formData.fields.length * 0.8 && 'Mark fewer fields as required to reduce friction'
].filter(Boolean)
};
}| Platform | Supported |
|---|---|
| Claude Code | ✅ |
| Cursor | ✅ |
| Codex | ✅ |
| Gemini | ✅ |