Chrome Extension Word Counter — Developer Guide
7 min readBuild a Word Counter Chrome Extension
In this tutorial, we’ll build a Chrome extension that counts words, characters, sentences, and more on any webpage. We’ll implement selection counting, readability metrics, and a badge display.
Prerequisites: Basic JavaScript and HTML knowledge.
Step 1: Manifest with activeTab Permission
Create manifest.json with activeTab permission for secure page access:
{
"manifest_version": 3,
"name": "Word Counter Pro",
"version": "1.0",
"permissions": ["activeTab", "clipboardWrite"],
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
}
}
The activeTab permission ensures we only access the page when the user explicitly invokes our extension.
Step 2: Popup Showing Page Statistics
Create popup.html to display word count, character count, sentences, and paragraphs:
<!DOCTYPE html>
<html>
<head>
<style>
body { width: 300px; padding: 15px; font-family: system-ui; }
.stat { display: flex; justify-content: space-between; margin: 8px 0; }
button { width: 100%; margin-top: 10px; padding: 8px; }
</style>
</head>
<body>
<h3>Page Statistics</h3>
<div class="stat"><span>Words:</span><span id="words">-</span></div>
<div class="stat"><span>Characters:</span><span id="chars">-</span></div>
<div class="stat"><span>Sentences:</span><span id="sentences">-</span></div>
<div class="stat"><span>Paragraphs:</span><span id="paragraphs">-</span></div>
<div class="stat"><span>Avg Word Length:</span><span id="avgLen">-</span></div>
<div class="stat"><span>Reading Time:</span><span id="readTime">-</span></div>
<div class="stat"><span>Flesch-Kincaid:</span><span id="grade">-</span></div>
<button id="copyBtn">Copy Stats</button>
<script src="popup.js"></script>
</body>
</html>
Step 3: Content Script Extracting Page Text
Create content.js to extract text from the page using document.body.innerText:
// content.js - runs on page to extract text
function getPageText() {
return document.body.innerText || document.body.textContent;
}
function getSelectedText() {
const selection = window.getSelection();
return selection ? selection.toString() : '';
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getStats') {
const text = request.includeSelection ? getSelectedText() : getPageText();
sendResponse({ text, hasSelection: !!getSelectedText() });
}
return true;
});
Edge Cases: Handle frames by iterating through document.frames, skip empty elements, and trim whitespace.
Step 4: Text Analysis Functions
Implement analysis functions in popup.js:
function countWords(text) {
return text.trim().split(/\s+/).filter(w => w.length > 0).length;
}
function countCharacters(text) {
return text.length;
}
function countSentences(text) {
return (text.match(/[.!?]+/g) || []).length || 1;
}
function countParagraphs(text) {
return text.split(/\n\n+/).filter(p => p.trim().length > 0).length;
}
function averageWordLength(text) {
const words = text.trim().split(/\s+/).filter(w => w.length > 0);
if (!words.length) return 0;
const total = words.reduce((sum, w) => sum + w.length, 0);
return (total / words.length).toFixed(1);
}
Step 5: Selection Counting
Detect selected text and show stats for the selection. Update popup.js:
document.getElementById('includeSelection').addEventListener('change', async (e) => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, {
action: 'getStats',
includeSelection: e.target.checked
}, updateStats);
});
When text is selected, the popup updates to show stats for only that selection.
Step 6: Readability Metrics
Add Flesch-Kincaid grade level and reading time estimates:
function fleschKincaid(text) {
const words = countWords(text);
const sentences = countSentences(text);
const syllables = text.split(/[aeiouy]+/).length - 1;
if (!words || !sentences) return 0;
return (0.39 * (words / sentences) + 11.8 * (syllables / words) - 15.59).toFixed(1);
}
function readingTime(text) {
const words = countWords(text);
const minutes = Math.ceil(words / 200); // 200 WPM avg
return `${minutes} min`;
}
Step 7: Badge Showing Word Count
Update manifest.json to include background script, then in popup.js:
chrome.action.setBadgeText({ text: String(wordCount) });
chrome.action.setBadgeBackgroundColor({ color: '#4CAF50' });
The badge displays the word count directly on the extension icon.
Step 8: Copy Stats to Clipboard
Add clipboard functionality using navigator.clipboard (see patterns/clipboard-patterns.md):
document.getElementById('copyBtn').addEventListener('click', async () => {
const stats = `Words: ${wordCount}\nCharacters: ${charCount}\nSentences: ${sentenceCount}`;
await navigator.clipboard.writeText(stats);
});
Performance Considerations
- Run analysis on demand (not continuously)
- Use
requestAnimationFramefor UI updates - Debounce user input for selection counting
- For large pages, use Web Workers to prevent UI blocking
Cross-References
- Content script patterns: see
guides/content-script-patterns.md - Clipboard API: see
patterns/clipboard-patterns.md - Badge UI: see
patterns/badge-action-ui.md
Your word counter extension is ready! Install it via chrome://extensions in developer mode.
-e
—
Turn Your Extension Into a Business
Ready to monetize? The Extension Monetization Playbook covers freemium models, Stripe integration, subscription architecture, and growth strategies for Chrome extension developers.
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.