WordScope · SEO analyzer
word counter · keyword density · readability · live metrics
🔒 local only · zero data upload
Words
0
unique: 0
Chars (no spaces)
0
with spaces: 0
Sentences
0
paragraphs: 0
⏱️ Read time
0
min · speak: 0 sec
📈 Top keywords (density)
—
🧠 Readability & hints
Analyzing…
⚡ Real-time · local processing
10 && sentenceCount > 0) {
const avgWordsPerSentence = wordCount / sentenceCount;
const avgCharsPerWord = charNoSpace / (wordCount || 1);
if (avgWordsPerSentence > 22) {
readabilityScore = "Hard to read";
hintMsg = "Sentences too long; break into shorter ones for better readability.";
} else if (avgWordsPerSentence > 16) {
readabilityScore = "Fairly difficult";
hintMsg = "Simplify sentence structure for broader audience.";
} else if (avgWordsPerSentence > 12) {
readabilityScore = "Plain English";
hintMsg = "Good balance for most audiences.";
} else if (avgWordsPerSentence > 0) {
readabilityScore = "Very easy";
hintMsg = "Engaging & accessible copy.";
} else {
readabilityScore = "N/A";
}
if (avgCharsPerWord > 5.5) {
hintMsg += " Reduce complex jargon.";
} else if (!hintMsg) hintMsg = "Solid readability, keep consistent.";
} else {
readabilityScore = "Insufficient text";
hintMsg = "Add more content for readability metrics.";
}
// SEO hint based on word count & density
let seoAdvice = "";
if (wordCount < 300 && wordCount > 0) seoAdvice = "📉 Add more words (300+ recommended for SEO).";
else if (wordCount >= 300 && wordCount < 800) seoAdvice = "👍 Good length, consider adding headings/sublists.";
else if (wordCount >= 800) seoAdvice = "✅ Excellent length, check keyword density below.";
if (sorted.length && sorted[0][1] / totalWordsForDensity > 0.05) {
seoAdvice += " ⚠️ High keyword density for '" + sorted[0][0] + "', reduce repetition.";
} else if (sorted.length && sorted[0][1] / totalWordsForDensity < 0.005 && wordCount > 100) {
seoAdvice += " 🔍 Consider focusing on target keyword more frequently.";
}
if (!seoAdvice) seoAdvice = "Optimize with semantic variations.";
return {
wordCount,
uniqueCount,
charNoSpace,
charWithSpace,
sentenceCount,
paraCount,
readingTime,
speakingTime: speakingTimeFinal,
keywordDensity: densityItems,
readabilityScore,
seoHint: seoAdvice,
hintMsg
};
}
function emptyResult() {
return {
wordCount:0, uniqueCount:0, charNoSpace:0, charWithSpace:0, sentenceCount:0, paraCount:0,
readingTime:0, speakingTime:0, keywordDensity:[], readabilityScore:"—", seoHint:"Enter text to analyze", hintMsg:""
};
}
function updateUI(data) {
wordCountSpan.innerText = data.wordCount;
uniqueWordSpan.innerText = data.uniqueCount;
charNoSpaceSpan.innerText = data.charNoSpace;
charWithSpaceSpan.innerText = data.charWithSpace;
sentenceCountSpan.innerText = data.sentenceCount;
paraCountSpan.innerText = data.paraCount;
readingTimeSpan.innerText = data.readingTime + ' min';
speakingTimeSpan.innerText = data.speakingTime;
if (data.keywordDensity.length === 0) {
keywordDensityDiv.innerHTML = '— add content —';
} else {
keywordDensityDiv.innerHTML = data.keywordDensity.map(k => `${k.word} ${k.density}%`).join('');
}
let readabilityHtml = `${data.readabilityScore}`;
if (data.hintMsg && data.wordCount > 0) readabilityHtml += `${data.hintMsg}`;
readabilityTextSpan.innerHTML = readabilityHtml;
seoHintSpan.innerHTML = data.seoHint;
}
function processAndUpdate() {
const rawText = textarea.value;
const analysis = analyzeText(rawText);
updateUI(analysis);
}
// debounce for smooth real-time
let debounceTimer;
function handleInput() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
processAndUpdate();
}, 20);
}
// paste button with clipboard api
async function pasteFromClipboard() {
try {
const text = await navigator.clipboard.readText();
if (text) {
textarea.value = text;
processAndUpdate();
// subtle selection feedback
textarea.focus();
} else {
// edge case
}
} catch (err) {
// fallback
textarea.focus();
document.execCommand('paste');
setTimeout(processAndUpdate, 30);
}
}
function clearContent() {
textarea.value = '';
processAndUpdate();
textarea.focus();
}
function copyStatsToClipboard() {
const stats = buildStatsText();
navigator.clipboard.writeText(stats).then(() => {
// micro feedback: change copy button temporarily
const copyBtn = document.getElementById('copyResultsBtn');
const originalText = copyBtn.innerHTML;
copyBtn.innerHTML = '✓ Copied!';
setTimeout(() => { copyBtn.innerHTML = originalText; }, 1500);
}).catch(() => {
alert("Could not copy");
});
}
function buildStatsText() {
const raw = textarea.value;
const data = analyzeText(raw);
return `WORDSTATS EXPORT
-------------------
Words: ${data.wordCount}
Unique words: ${data.uniqueCount}
Characters (no spaces): ${data.charNoSpace}
Characters (with spaces): ${data.charWithSpace}
Sentences: ${data.sentenceCount}
Paragraphs: ${data.paraCount}
Reading time: ${data.readingTime} min
Speaking time: ${data.speakingTime} sec
Top keywords: ${data.keywordDensity.map(k=>`${k.word} (${k.density}%)`).join(', ') || 'none'}
Readability: ${data.readabilityScore}
SEO tip: ${data.seoHint}
`;
}
function exportAsTxt() {
const statsContent = buildStatsText();
const blob = new Blob([statsContent + "\n\n--- Full content ---\n" + textarea.value], {type: "text/plain"});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `wordscope_export_${new Date().toISOString().slice(0,19)}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function exportAsJSON() {
const rawText = textarea.value;
const analysis = analyzeText(rawText);
const exportObj = {
exportTime: new Date().toISOString(),
content: rawText,
stats: {
wordCount: analysis.wordCount,
uniqueWords: analysis.uniqueCount,
charactersNoSpaces: analysis.charNoSpace,
charactersWithSpaces: analysis.charWithSpace,
sentences: analysis.sentenceCount,
paragraphs: analysis.paraCount,
readingTimeMinutes: analysis.readingTime,
speakingTimeSeconds: analysis.speakingTime,
keywordDensity: analysis.keywordDensity,
readabilityScore: analysis.readabilityScore,
seoHint: analysis.seoHint
}
};
const jsonStr = JSON.stringify(exportObj, null, 2);
const blob = new Blob([jsonStr], {type: "application/json"});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `wordscope_analysis_${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// event binding
textarea.addEventListener('input', handleInput);
document.getElementById('pasteBtn').addEventListener('click', pasteFromClipboard);
document.getElementById('clearBtn').addEventListener('click', clearContent);
document.getElementById('copyResultsBtn').addEventListener('click', copyStatsToClipboard);
document.getElementById('exportTxtBtn').addEventListener('click', exportAsTxt);
document.getElementById('exportJsonBtn').addEventListener('click', exportAsJSON);
// initial analysis
processAndUpdate();
// add keyboard shortcut: Ctrl/Cmd + K clear (optional)
window.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
clearContent();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'c' && e.shiftKey) {
e.preventDefault();
copyStatsToClipboard();
}
});
})();