Website Content Audit Tool
Analyze your webpage content against key SEO and readability metrics.
Content for Analysis
Content Audit Report
Overall Content Score
0
Audit Checklist
Oatmeal is a fantastic source of complex carbs. Adding berries provides antioxidants. This is one of the best healthy breakfast ideas for cold mornings.
`;
// --- TAB LOGIC ---
let currentTabIndex = 0;
const tabs = ['input', 'analysis'];
function switchTab(idx) {
currentTabIndex = idx;
tabBtns.forEach((b, i) => {
b.classList.toggle('active', tabs[i] === tabs[idx]);
});
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.getElementById(`${tabs[idx]}-content`).classList.add('active');
}
analyzeBtn.addEventListener('click', () => {
runAnalysis();
switchTab(1);
});
// --- CORE LOGIC ---
function countSyllables(word) {
word = word.toLowerCase().trim().replace(/e$/, '');
if (word.length <= 3) return 1;
const matches = word.match(/[aeiouy]{1,2}/g);
return matches ? matches.length : 1;
}
function runAnalysis() {
const htmlString = contentHtmlInput.value;
const keyword = targetKeywordInput.value.toLowerCase();
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const checks = {};
let totalScore = 0;
const textContent = doc.body.textContent || "";
const words = textContent.trim().split(/\s+/).filter(Boolean);
const wordCount = words.length;
const sentences = textContent.match(/[^.!?]+[.!?]+/g) || [];
const sentenceCount = sentences.length;
const syllableCount = words.reduce((sum, word) => sum + countSyllables(word), 0);
// 1. Readability
const fleschKincaid = (0.39 * (wordCount/sentenceCount)) + (11.8 * (syllableCount / wordCount)) - 15.59;
checks.readability = { pass: fleschKincaid < 10, detail: `Grade ${fleschKincaid.toFixed(1)}` };
if (checks.readability.pass) totalScore += AUDIT_FACTORS.readability.weight;
// 2. Word Count
checks.wordCount = { pass: wordCount > 500, detail: `${wordCount} words` };
if (checks.wordCount.pass) totalScore += AUDIT_FACTORS.wordCount.weight;
// 3. Title Keyword
const title = doc.querySelector('title')?.textContent.toLowerCase() || "";
checks.titleKeyword = { pass: title.includes(keyword) };
if (checks.titleKeyword.pass) totalScore += AUDIT_FACTORS.titleKeyword.weight;
// 4. H1 Keyword
const h1 = doc.querySelector('h1')?.textContent.toLowerCase() || "";
checks.h1Keyword = { pass: h1.includes(keyword) };
if (checks.h1Keyword.pass) totalScore += AUDIT_FACTORS.h1Keyword.weight;
// 5. H2 Keyword
const h2s = Array.from(doc.querySelectorAll('h2')).some(h => h.textContent.toLowerCase().includes(keyword));
checks.h2Keyword = { pass: h2s };
if (checks.h2Keyword.pass) totalScore += AUDIT_FACTORS.h2Keyword.weight;
// 6. Keyword Density
const keywordCount = (textContent.toLowerCase().match(new RegExp(keyword.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g')) || []).length;
const density = wordCount > 0 ? (keywordCount / wordCount) * 100 : 0;
checks.keywordDensity = { pass: density >= 0.5 && density <= 2.0, detail: `${density.toFixed(2)}%` };
if (checks.keywordDensity.pass) totalScore += AUDIT_FACTORS.keywordDensity.weight;
// 7. Meta Description
const meta = doc.querySelector('meta[name="description"]')?.getAttribute('content') || "";
checks.metaDescription = { pass: meta.length >= 50 && meta.length <= 160, detail: `${meta.length} chars` };
if (checks.metaDescription.pass) totalScore += AUDIT_FACTORS.metaDescription.weight;
// 8. Image Alts
const images = doc.querySelectorAll('img');
const imagesWithAlts = Array.from(images).filter(img => img.alt && img.alt.trim() !== "").length;
checks.imageAlts = { pass: images.length === 0 || imagesWithAlts === images.length, detail: `${imagesWithAlts}/${images.length} have alts` };
if (checks.imageAlts.pass) totalScore += AUDIT_FACTORS.imageAlts.weight;
analysisResults = {
score: totalScore,
checks,
keyword: targetKeywordInput.value,
url: contentUrlInput.value
};
renderAnalysis();
}
// --- UI RENDERING ---
function renderAnalysis() {
const scoreEl = document.getElementById('seo-score');
const scoreBar = document.getElementById('score-bar');
const checklistContainer = document.getElementById('checklist-container');
scoreEl.textContent = analysisResults.score;
scoreBar.style.width = `${analysisResults.score}%`;
let scoreColor = 'bg-red-500';
if (analysisResults.score > 75) scoreColor = 'bg-green-500';
else if (analysisResults.score > 40) scoreColor = 'bg-yellow-500';
scoreBar.className = `h-4 rounded-full transition-all duration-500 ${scoreColor}`;
checklistContainer.innerHTML = Object.entries(analysisResults.checks).map(([key, result]) => {
const icon = result.pass
? ``
: ``;
return `
${icon}
${AUDIT_FACTORS[key].label}
${result.detail || (result.pass ? 'Pass' : 'Fail')}
`;
}).join('');
}
// --- PDF GENERATION ---
async function generatePdfReport() {
downloadPdfBtn.disabled = true;
downloadPdfBtn.textContent = 'Generating...';
const scoreColor = analysisResults.score > 75 ? '#16a34a' : (analysisResults.score > 40 ? '#f59e0b' : '#dc2626');
const checklistHtml = Object.entries(analysisResults.checks).map(([key, result]) => `
${result.pass ? '✔' : '✖'}
${AUDIT_FACTORS[key].label}
${result.detail || (result.pass ? 'Pass' : 'Fail')}
`).join('');
const reportHtml = `
Content Audit Report
For Keyword: "${analysisResults.keyword}"
${analysisResults.score}
/ 100
${analysisResults.url || 'No URL provided'}
Detailed Analysis${new Date().toLocaleDateString()}
${checklistHtml}
Generated by the On-Page SEO Analyzer.
