Build a Reading Speed Calculator Extension: Complete WPM Guide
Have you ever wondered how long it will take you to read an article before diving in? Whether you are a student planning study time, a professional estimating document review duration, or a content creator wanting to help your audience, a reading speed extension can be an invaluable tool. In this comprehensive guide, we will walk you through building a fully functional Chrome extension that calculates reading time based on words per minute (WPM), giving users instant estimates of how long any web content will take to read.
The demand for reading time estimator tools has grown significantly as online content continues to explode. Users increasingly want to know before they click whether they have time to read an article. This presents a fantastic opportunity for developers to create useful Chrome extensions that solve real problems. By the end of this tutorial, you will have built a complete reading speed extension that works seamlessly in Chrome and provides accurate reading time estimates for any web page.
Understanding Reading Speed and WPM Calculations
Before diving into code, it is essential to understand the fundamentals of reading speed measurement. Words per minute (WPM) serves as the standard metric for measuring reading speed across the globe. The average adult reads at approximately 200 to 250 WPM, though this varies significantly based on reading purpose, content complexity, and individual capability.
Silent reading speed typically ranges from 200 to 300 WPM for average readers, while speed readers can achieve 400 to 700 WPM. On the other hand, reading aloud averages between 150 to 180 WPM. Your extension should account for these variations by allowing users to customize their reading speed preferences. This flexibility makes the extension useful for a broader audience with different reading capabilities and purposes.
The basic formula for calculating reading time is straightforward: divide the total word count by the reader’s WPM rate. However, additional factors can improve accuracy. Research shows that reading time increases by approximately 10 to 20 percent when content includes complex technical terms, unfamiliar vocabulary, or dense mathematical expressions. Similarly, content with many headings, bullet points, and short paragraphs tends to be scanned faster than continuous prose blocks.
Your reading speed calculator extension will need to count words accurately, apply the WPM formula, and potentially adjust for content type. We will build these features progressively throughout this tutorial, creating an extension that is both accurate and user-friendly.
Setting Up the Chrome Extension Project
Every Chrome extension begins with a manifest file that defines the extension’s metadata, permissions, and capabilities. For our reading speed calculator extension, we will use Manifest V3, which is the current standard and offers improved security and performance compared to older versions.
Create a new directory for your project called “reading-speed-calculator” and add the following manifest.json file. This manifest declares the extension’s name, version, description, and the permissions it requires. We need the activeTab permission to access the current page’s content and the scripting permission to execute code that extracts text from web pages.
{
"manifest_version": 3,
"name": "Reading Speed Calculator",
"version": "1.0",
"description": "Calculate reading time based on words per minute. Get instant estimates for any web content.",
"permissions": ["activeTab", "scripting"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
You will also need to create an icons directory with three PNG files of the appropriate sizes (16x16, 48x48, and 128x128 pixels). For development purposes, you can create simple placeholder icons or use any image editing tool to generate basic square images. These icons appear in the Chrome toolbar when your extension is installed.
The popup.html file defines the user interface that appears when users click your extension icon. This interface will display the calculated reading time, word count, and allow users to adjust their preferred WPM setting. We will build this interface next with HTML and CSS.
Building the Extension User Interface
The popup interface is the primary way users interact with your reading speed extension. It should be clean, informative, and easy to use. Create the popup.html file with the following structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reading Speed Calculator</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
width: 320px;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
}
.container {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
h1 {
font-size: 18px;
margin-bottom: 16px;
color: #2c3e50;
text-align: center;
}
.result-box {
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
text-align: center;
}
.reading-time {
font-size: 36px;
font-weight: bold;
color: #667eea;
margin-bottom: 4px;
}
.reading-time-label {
font-size: 12px;
color: #6c757d;
text-transform: uppercase;
letter-spacing: 1px;
}
.stats {
display: flex;
justify-content: space-around;
margin-bottom: 16px;
padding: 12px 0;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 18px;
font-weight: 600;
color: #2c3e50;
}
.stat-label {
font-size: 11px;
color: #6c757d;
}
.settings {
margin-top: 16px;
}
.settings label {
display: block;
font-size: 12px;
color: #6c757d;
margin-bottom: 6px;
}
.settings input[type="range"] {
width: 100%;
margin-bottom: 8px;
}
.wpm-display {
text-align: center;
font-size: 14px;
font-weight: 500;
color: #667eea;
}
.calculate-btn {
width: 100%;
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
margin-top: 16px;
}
.calculate-btn:hover {
background: #5568d3;
}
.loading {
text-align: center;
padding: 40px;
color: #6c757d;
}
</style>
</head>
<body>
<div class="container">
<h1>📖 Reading Speed Calculator</h1>
<div id="result" class="result-box" style="display: none;">
<div class="reading-time" id="readingTime">-</div>
<div class="reading-time-label">Estimated Reading Time</div>
</div>
<div id="stats" class="stats" style="display: none;">
<div class="stat-item">
<div class="stat-value" id="wordCount">-</div>
<div class="stat-label">Words</div>
</div>
<div class="stat-item">
<div class="stat-value" id="charsCount">-</div>
<div class="stat-label">Characters</div>
</div>
</div>
<div id="loading" class="loading">
Click to calculate reading time
</div>
<div class="settings">
<label>Your Reading Speed</label>
<input type="range" id="wpmSlider" min="100" max="600" value="250" step="10">
<div class="wpm-display"><span id="wpmValue">250</span> WPM</div>
</div>
<button class="calculate-btn" id="calculateBtn">Calculate Reading Time</button>
</div>
<script src="popup.js"></script>
</body>
</html>
This interface provides a clean, modern design with a gradient background and white card. It displays the estimated reading time prominently, shows word and character counts, and includes a slider for users to adjust their preferred WPM rate. The slider ranges from 100 to 600 WPM, covering slow readers to speed readers.
Implementing the Core Logic with JavaScript
The JavaScript file handles all the functionality: extracting text from the current page, counting words, calculating reading time, and updating the UI. Create popup.js with the following implementation:
document.addEventListener('DOMContentLoaded', () => {
const calculateBtn = document.getElementById('calculateBtn');
const wpmSlider = document.getElementById('wpmSlider');
const wpmValue = document.getElementById('wpmValue');
const resultBox = document.getElementById('result');
const statsBox = document.getElementById('stats');
const loadingBox = document.getElementById('loading');
// Initialize from stored preferences
chrome.storage.sync.get(['preferredWpm'], (result) => {
if (result.preferredWpm) {
wpmSlider.value = result.preferredWpm;
wpmValue.textContent = result.preferredWpm;
}
});
// Update WPM display when slider changes
wpmSlider.addEventListener('input', () => {
wpmValue.textContent = wpmSlider.value;
chrome.storage.sync.set({ preferredWpm: wpmSlider.value });
});
// Calculate reading time when button is clicked
calculateBtn.addEventListener('click', async () => {
loadingBox.innerHTML = 'Analyzing page content...';
try {
// Get the active tab
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
// Execute script to extract text content
const results = await chrome.scripting.executeScript({
target: { tabId: tab.id },
function: extractTextContent
});
const textContent = results[0].result;
if (!textContent || textContent.trim().length === 0) {
loadingBox.innerHTML = 'No readable content found on this page.';
return;
}
// Calculate statistics
const wordCount = countWords(textContent);
const charCount = textContent.replace(/\s/g, '').length;
const wpm = parseInt(wpmSlider.value);
const readingTimeMinutes = calculateReadingTime(wordCount, wpm);
// Update UI
document.getElementById('readingTime').textContent = formatReadingTime(readingTimeMinutes);
document.getElementById('wordCount').textContent = wordCount.toLocaleString();
document.getElementById('charsCount').textContent = charCount.toLocaleString();
resultBox.style.display = 'block';
statsBox.style.display = 'flex';
loadingBox.style.display = 'none';
} catch (error) {
console.error('Error calculating reading time:', error);
loadingBox.innerHTML = 'Error analyzing page. Please try again.';
}
});
});
// This function runs in the context of the web page
function extractTextContent() {
// Remove script and style elements
const elementsToRemove = document.querySelectorAll('script, style, noscript, iframe, nav, header, footer');
elementsToRemove.forEach(el => el.remove());
// Get text from body
const body = document.body;
return body ? body.innerText : '';
}
function countWords(text) {
// Clean and split text into words
const cleanedText = text
.replace(/[\r\n]+/g, ' ')
.replace(/\s+/g, ' ')
.trim();
if (cleanedText.length === 0) return 0;
return cleanedText.split(' ').filter(word => word.length > 0).length;
}
function calculateReadingTime(wordCount, wpm) {
return Math.ceil(wordCount / wpm);
}
function formatReadingTime(minutes) {
if (minutes < 1) {
return '< 1 min';
} else if (minutes === 1) {
return '1 min';
} else if (minutes < 60) {
return `${minutes} min`;
} else {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
}
}
The JavaScript implements several important features. First, it uses chrome.scripting.executeScript to run code in the context of the active tab, which allows us to access the page’s content. Second, it cleans the content by removing unwanted elements like scripts, styles, navigation, and footers that would skew the word count. Third, it saves the user’s preferred WPM setting using chrome.storage.sync so the preference persists across sessions.
The calculateReadingTime function uses the standard formula of dividing word count by WPM rate, with the result rounded up to the nearest minute. The formatReadingTime function then presents this in a human-readable format, showing minutes for shorter content and hours/minutes for longer articles.
Enhancing the Extension with Additional Features
Now that the core functionality works, let us add some enhancements that make the extension more useful and professional. First, we will add support for different reading modes: casual reading, careful reading, and speed reading. Each mode has different WPM assumptions and provides better estimates for different use cases.
Add this enhanced functionality to the popup.js file by introducing reading mode presets. These presets change the default WPM range and provide tooltips explaining each mode:
// Reading mode presets
const readingModes = {
slow: { wpm: 150, label: 'Careful Reading', description: 'For complex or technical content' },
normal: { wpm: 250, label: 'Casual Reading', description: 'Standard reading pace' },
fast: { wpm: 400, label: 'Speed Reading', description: 'For skimming and overview' }
};
// Display reading mode selector in the popup
function addReadingModeSelector() {
const settingsDiv = document.querySelector('.settings');
const modeSelector = document.createElement('div');
modeSelector.className = 'mode-selector';
modeSelector.innerHTML = `
<label>Reading Mode</label>
<div class="mode-buttons">
<button class="mode-btn" data-mode="slow">Careful</button>
<button class="mode-btn active" data-mode="normal">Normal</button>
<button class="mode-btn" data-mode="fast">Fast</button>
</div>
`;
settingsDiv.insertBefore(modeSelector, settingsDiv.firstChild);
// Add mode button event listeners
document.querySelectorAll('.mode-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.mode-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const mode = btn.dataset.mode;
wpmSlider.value = readingModes[mode].wpm;
wpmValue.textContent = readingModes[mode].wpm;
chrome.storage.sync.set({ preferredWpm: readingModes[mode].wpm, readingMode: mode });
});
});
}
Another valuable enhancement is displaying a reading progress indicator that shows how much of the current article the user has read. This feature uses the scroll position to calculate progress and provides visual feedback. To implement this, we need to inject a content script that tracks scrolling behavior.
Create a content.js file that will be injected into web pages:
// content.js - Runs in the context of web pages
let readingStartTime = null;
let totalScrollHeight = 0;
function initReadingTracker() {
// Wait for page to fully load
if (document.readyState !== 'complete') {
window.addEventListener('load', initReadingTracker);
return;
}
totalScrollHeight = document.documentElement.scrollHeight - window.innerHeight;
// Track scroll position
window.addEventListener('scroll', () => {
const scrollPosition = window.scrollY;
const progress = Math.min((scrollPosition / totalScrollHeight) * 100, 100);
// Send progress to extension
chrome.runtime.sendMessage({
type: 'readingProgress',
progress: Math.round(progress),
url: window.location.href
});
});
// Track time spent reading
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
if (!readingStartTime) {
readingStartTime = Date.now();
}
} else if (readingStartTime) {
const timeSpent = Date.now() - readingStartTime;
chrome.runtime.sendMessage({
type: 'timeSpentReading',
timeMs: timeSpent,
url: window.location.href
});
readingStartTime = null;
}
});
}
initReadingTracker();
This content script tracks both scroll progress and actual time spent reading, accounting for when the user switches tabs or minimizes the browser. This data can be useful for users who want to track their reading habits over time.
Testing Your Extension
Chrome provides excellent developer tools for testing and debugging extensions. To test your reading speed calculator extension, open Chrome and navigate to chrome://extensions/. Enable “Developer mode” using the toggle in the top right corner, then click “Load unpacked” and select your extension directory.
Once loaded, your extension icon should appear in the Chrome toolbar. Navigate to any web page with substantial text content, such as a news article or blog post. Click your extension icon to open the popup, adjust the WPM slider if desired, and click “Calculate Reading Time” to see the results.
Test with various types of content to ensure accuracy. Try long-form articles, short blog posts, documentation pages, and text-heavy websites. The word count should be reasonable and the reading time estimate should match your expectations based on the selected WPM rate. If you notice discrepancies, you may need to refine the text extraction function to better handle specific page structures.
Common issues to watch for include incorrectly counting numbers as words, including hidden text, or missing content in certain page layouts. The extractTextContent function we created removes common non-content elements, but you may need to adjust it based on specific sites that you find are not being processed correctly.
Publishing Your Extension
Once you have thoroughly tested your extension and are satisfied with its functionality, you can publish it to the Chrome Web Store. This process requires creating a developer account, preparing promotional assets, and following Google’s guidelines.
First, create a developer account at the Chrome Web Store developer dashboard. There is a one-time registration fee of $5. Then, package your extension into a ZIP file, including all necessary files: manifest.json, popup.html, popup.js, content.js (if applicable), and icons. Do not include the icons directory structure—include the icon files directly in the root of the ZIP.
When submitting your extension, provide clear descriptions using your target keywords naturally: “reading speed calculator,” “words per minute,” “reading time estimator,” and “Chrome extension.” These keywords help users find your extension when searching the Chrome Web Store. Include screenshots that show the extension in action and write compelling descriptions that highlight the value proposition.
Conclusion
Congratulations! You have built a complete reading speed calculator Chrome extension that provides valuable functionality to users. This extension demonstrates several important concepts in Chrome extension development, including using the Scripting API to access page content, creating responsive popup interfaces, storing user preferences, and implementing content scripts for page-level features.
The reading speed extension you created calculates reading time based on words per minute, allowing users to customize their WPM rate and choose between different reading modes. It accurately extracts text content from web pages while filtering out non-essential elements, provides instant word and character counts, and presents results in a clean, intuitive interface.
This project can be extended in many directions. You could add features like reading history tracking, the ability to save articles for later reading, integration with note-taking apps, or even social features that let users compare reading habits. The foundation you have built provides a solid starting point for adding these enhancements.
Building useful Chrome extensions is an excellent way to develop real skills in web development while creating tools that solve genuine problems. The reading speed calculator addresses a real user need—knowing how much time content will take to read—making it a valuable addition to any browser. As you continue your Chrome extension development journey, keep focusing on solving real problems and creating positive user experiences.