Build an SEO Analyzer Chrome Extension — Complete Tutorial
In the ever-evolving world of digital marketing, search engine optimization remains one of the most critical factors for online success. Understanding how your website performs in search rankings and identifying areas for improvement can make the difference between thriving online visibility and getting lost in the sea of competitors. Building an SEO analyzer Chrome extension is an excellent project that combines practical utility with powerful Chrome APIs, creating a tool that can analyze web pages directly in the browser and provide instant SEO insights.
This comprehensive tutorial will guide you through building a fully functional SEO tool extension from scratch using Manifest V3. You will learn how to extract and analyze crucial on-page SEO elements including meta tags, heading structures, keyword density, content readability, image optimization, and internal/external link analysis. By the end of this tutorial, you will have created a professional-grade website analyzer extension that you can use personally or publish to the Chrome Web Store.
Why Build an SEO Chrome Extension?
The demand for SEO tools has never been higher. Marketing professionals, content creators, web developers, and business owners all need quick ways to assess the SEO health of web pages without leaving their browsers. While there are many online SEO tools available, having a dedicated Chrome extension provides several distinct advantages that make building your own worthwhile.
First and foremost, a Chrome extension runs directly in your browser, eliminating the need to navigate to external websites or copy-paste URLs into various tools. The analysis happens instantly with a single click, making it perfect for quickly auditing multiple pages during content reviews or competitive research. This seamless integration with the browsing experience is precisely what makes Chrome extensions so valuable for SEO workflows.
The SEO niche in the Chrome Web Store is also remarkably underserved. While you can find numerous SEO chrome extension options, most are either basic meta tag viewers lacking depth, expensive premium tools with limited free functionality, or outdated extensions that haven’t been updated for modern web standards. This creates a significant opportunity for developers who can deliver a comprehensive, user-friendly SEO analyzer that provides real value without requiring expensive subscriptions.
Building an SEO analyzer also provides excellent learning opportunities. You will work with DOM manipulation, asynchronous JavaScript operations, Chrome storage APIs, content script injection, and popup UI creation. These skills are transferable to countless other extension projects, making this tutorial an excellent investment in your development capabilities.
Project Setup and Manifest Configuration
Every Chrome extension begins with the manifest file, which serves as the configuration blueprint telling Chrome about your extension’s capabilities, permissions, and file structure. For our SEO analyzer, we need specific permissions to access webpage content and interact with browser tabs.
Create a new directory for your project called seo-analyzer and add the following manifest.json file:
{
"manifest_version": 3,
"name": "SEO Analyzer Pro",
"version": "1.0.0",
"description": "Comprehensive on-page SEO analysis tool for Chrome",
"permissions": [
"activeTab",
"storage",
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"default_title": "Analyze SEO"
},
"background": {
"service_worker": "background.js"
}
}
The manifest configuration includes several key elements worth understanding. The activeTab permission allows your extension to access the currently active tab when the user clicks the extension icon, which is ideal for analyzing the page the user is currently viewing. The scripting permission enables programmatic execution of content scripts that can extract and analyze page content. The host_permissions with <all_urls> ensures your extension can analyze any website without restrictions.
For the icon files, you will need to create simple 16x16, 48x48, and 128x128 pixel images representing your extension. Place these in an icons folder within your project directory. While these don’t need to be elaborate, having consistent iconography helps establish professionalism and trust with users.
The Popup Interface
The popup is what users see when they click your extension icon in the Chrome toolbar. For our SEO analyzer, we want a clean, informative interface that displays analysis results clearly. Create popup.html 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>SEO Analyzer</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<header>
<h1>SEO Analyzer</h1>
<p class="url-display" id="url">Loading...</p>
</header>
<div class="score-section">
<div class="overall-score" id="overallScore">
<span class="score-value">--</span>
<span class="score-label">Overall Score</span>
</div>
</div>
<div class="analysis-sections">
<div class="section" id="metaSection">
<h2>Meta Tags</h2>
<ul class="results-list" id="metaResults"></ul>
</div>
<div class="section" id="contentSection">
<h2>Content Analysis</h2>
<ul class="results-list" id="contentResults"></ul>
</div>
<div class="section" id="linksSection">
<h2>Links</h2>
<ul class="results-list" id="linksResults"></ul>
</div>
<div class="section" id="imagesSection">
<h2>Images</h2>
<ul class="results-list" id="imagesResults"></ul>
</div>
</div>
<button id="analyzeBtn" class="analyze-button">Analyze Page</button>
</div>
<script src="popup.js"></script>
</body>
</html>
The popup structure divides SEO analysis into four main categories: meta tags, content analysis, links, and images. Each category gets its own section with a results list that we will populate dynamically after analysis. The overall score prominently displays at the top, giving users an immediate sense of the page’s SEO health.
Create popup.css to style the popup attractively:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 400px;
min-height: 500px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f8f9fa;
color: #333;
}
.container {
padding: 20px;
}
header {
text-align: center;
margin-bottom: 20px;
}
h1 {
font-size: 22px;
color: #1a73e8;
margin-bottom: 5px;
}
.url-display {
font-size: 12px;
color: #666;
word-break: break-all;
}
.score-section {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.overall-score {
width: 120px;
height: 120px;
border-radius: 50%;
background: linear-gradient(135deg, #1a73e8, #34a853);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
box-shadow: 0 4px 15px rgba(26, 115, 232, 0.3);
}
.score-value {
font-size: 36px;
font-weight: bold;
}
.score-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
}
.analysis-sections {
margin-bottom: 20px;
}
.section {
background: white;
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.section h2 {
font-size: 14px;
color: #333;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
}
.results-list {
list-style: none;
}
.results-list li {
font-size: 12px;
padding: 6px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.results-list li.pass {
color: #34a853;
}
.results-list li.warning {
color: #fbbc04;
}
.results-list li.fail {
color: #ea4335;
}
.analyze-button {
width: 100%;
padding: 14px;
background: #1a73e8;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.analyze-button:hover {
background: #1557b0;
}
.analyze-button:disabled {
background: #ccc;
cursor: not-allowed;
}
The CSS provides a clean, modern interface with clear visual feedback. Results are color-coded: green for passing elements, yellow for warnings, and red for failures. The overall score uses a gradient background that draws attention to this critical metric.
The Analysis Logic
Now we need to create the JavaScript that performs the actual SEO analysis. This is where the core functionality of our SEO tool extension lives. Create analyzer.js:
class SEOAnalyzer {
constructor() {
this.score = 0;
this.maxScore = 100;
this.results = {
meta: [],
content: [],
links: [],
images: []
};
}
async analyze(tabId) const results = await chrome.scripting.executeScript({
target: { tabId: tabId },
func: this.extractPageData
});
const pageData = results[0].result;
this.evaluateMetaTags(pageData);
this.evaluateContent(pageData);
this.evaluateLinks(pageData);
this.evaluateImages(pageData);
this.score = Math.max(0, Math.min(100, this.score));
return {
score: this.score,
url: pageData.url,
results: this.results,
data: pageData
};
}
extractPageData() {
const getMetaContent = (name) => {
const meta = document.querySelector(`meta[name="${name}"], meta[property="${name}"]`);
return meta ? meta.getAttribute('content') : null;
};
const headings = {
h1: document.querySelectorAll('h1').length,
h2: document.querySelectorAll('h2').length,
h3: document.querySelectorAll('h3').length
};
const paragraphs = document.querySelectorAll('p');
let totalTextLength = 0;
paragraphs.forEach(p => {
totalTextLength += p.textContent.trim().length;
});
const links = {
internal: 0,
external: 0,
total: document.querySelectorAll('a').length
};
const currentHost = window.location.host;
document.querySelectorAll('a').forEach(link => {
try {
const linkHost = new URL(link.href).host;
if (linkHost === currentHost) {
links.internal++;
} else {
links.external++;
}
} catch (e) {
// Invalid URL, skip
}
});
const images = {
total: document.querySelectorAll('img').length,
withAlt: 0,
withoutAlt: 0
};
document.querySelectorAll('img').forEach(img => {
if (img.alt && img.alt.trim() !== '') {
images.withAlt++;
} else {
images.withoutAlt++;
}
});
return {
url: window.location.href,
title: document.title,
metaDescription: getMetaContent('description'),
metaKeywords: getMetaContent('keywords'),
ogTitle: getMetaContent('og:title'),
ogDescription: getMetaContent('og:description'),
ogImage: getMetaContent('og:image'),
canonical: document.querySelector('link[rel="canonical"]')?.href,
headings: headings,
textLength: totalTextLength,
links: links,
images: images,
wordCount: document.body.innerText.split(/\s+/).filter(w => w.length > 0).length
};
}
evaluateMetaTags(data) {
// Title check
if (data.title && data.title.length > 0 && data.title.length <= 60) {
this.results.meta.push({ status: 'pass', text: `Title: ${data.title.substring(0, 40)}...` });
this.score += 10;
} else if (data.title) {
this.results.meta.push({ status: 'warning', text: `Title too long (${data.title.length}/60 chars)` });
this.score += 5;
} else {
this.results.meta.push({ status: 'fail', text: 'Missing page title' });
}
// Meta description check
if (data.metaDescription && data.metaDescription.length > 0 && data.metaDescription.length <= 160) {
this.results.meta.push({ status: 'pass', text: 'Meta description present' });
this.score += 10;
} else if (data.metaDescription) {
this.results.meta.push({ status: 'warning', text: 'Meta description too long' });
this.score += 5;
} else {
this.results.meta.push({ status: 'fail', text: 'Missing meta description' });
}
// Open Graph tags
if (data.ogTitle && data.ogDescription && data.ogImage) {
this.results.meta.push({ status: 'pass', text: 'Open Graph tags complete' });
this.score += 5;
} else {
this.results.meta.push({ status: 'warning', text: 'Missing Open Graph tags' });
}
// Canonical URL
if (data.canonical) {
this.results.meta.push({ status: 'pass', text: 'Canonical URL present' });
this.score += 5;
} else {
this.results.meta.push({ status: 'warning', text: 'Missing canonical URL' });
}
}
evaluateContent(data) {
// Word count
if (data.wordCount >= 300) {
this.results.content.push({ status: 'pass', text: `Good content length (${data.wordCount} words)` });
this.score += 15;
} else if (data.wordCount >= 100) {
this.results.content.push({ status: 'warning', text: `Short content (${data.wordCount} words)` });
this.score += 8;
} else {
this.results.content.push({ status: 'fail', text: `Thin content (${data.wordCount} words)` });
}
// Heading structure
if (data.headings.h1 === 1) {
this.results.content.push({ status: 'pass', text: 'Perfect H1 structure (1 H1 tag)' });
this.score += 10;
} else if (data.headings.h1 === 0) {
this.results.content.push({ status: 'fail', text: 'Missing H1 heading' });
} else {
this.results.content.push({ status: 'warning', text: `Multiple H1 tags (${data.headings.h1})` });
this.score += 5;
}
// Subheadings
if (data.headings.h2 + data.headings.h3 >= 3) {
this.results.content.push({ status: 'pass', text: 'Good heading hierarchy' });
this.score += 10;
} else {
this.results.content.push({ status: 'warning', text: 'Consider adding more subheadings' });
}
}
evaluateLinks(data) {
if (data.links.total > 0) {
this.results.links.push({ status: 'pass', text: `${data.links.total} links found` });
this.score += 10;
} else {
this.results.links.push({ status: 'warning', text: 'No links found on page' });
}
if (data.links.internal > 0) {
this.results.links.push({ status: 'pass', text: `${data.links.internal} internal links` });
this.score += 5;
} else {
this.results.links.push({ status: 'warning', text: 'No internal links' });
}
if (data.links.external > 0) {
this.results.links.push({ status: 'pass', text: `${data.links.external} external links` });
this.score += 5;
}
}
evaluateImages(data) {
if (data.images.total === 0) {
this.results.images.push({ status: 'warning', text: 'No images on page' });
} else {
const altPercentage = Math.round((data.images.withAlt / data.images.total) * 100);
if (altPercentage >= 90) {
this.results.images.push({ status: 'pass', text: `${altPercentage}% images with alt text` });
this.score += 10;
} else if (altPercentage >= 50) {
this.results.images.push({ status: 'warning', text: `${altPercentage}% images with alt text` });
this.score += 5;
} else {
this.results.images.push({ status: 'fail', text: `${altPercentage}% images with alt text` });
}
}
}
}
This analyzer class performs comprehensive on-page SEO evaluation across four key areas. The extractPageData function runs in the context of the analyzed page, collecting all necessary information about meta tags, content structure, links, and images. The evaluation methods then score each category based on SEO best practices.
The scoring system awards points for positive SEO signals and reduces or withholds points for issues. The final score ranges from 0 to 100, providing a quick overall assessment of page SEO health. This approach aligns with how professional SEO tools evaluate content, making the results meaningful and actionable for users.
Connecting Popup and Analyzer
Now we need to create the popup JavaScript that connects the user interface to our analyzer. Create popup.js:
document.addEventListener('DOMContentLoaded', async () => {
const analyzeBtn = document.getElementById('analyzeBtn');
const urlDisplay = document.getElementById('url');
const scoreDisplay = document.querySelector('.score-value');
const overallScore = document.getElementById('overallScore');
// Get current tab
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
urlDisplay.textContent = tab.url;
analyzeBtn.addEventListener('click', async () => {
analyzeBtn.disabled = true;
analyzeBtn.textContent = 'Analyzing...';
try {
const analyzer = new SEOAnalyzer();
const results = await analyzer.analyze(tab.id);
displayResults(results);
} catch (error) {
console.error('Analysis error:', error);
analyzeBtn.textContent = 'Error - Try Again';
analyzeBtn.disabled = false;
}
});
function displayResults(results) {
// Update score
scoreDisplay.textContent = results.score;
// Update score color based on value
if (results.score >= 70) {
overallScore.style.background = 'linear-gradient(135deg, #34a853, #0d652d)';
} else if (results.score >= 40) {
overallScore.style.background = 'linear-gradient(135deg, #fbbc04, #f9a825)';
} else {
overallScore.style.background = 'linear-gradient(135deg, #ea4335, #c5221f)';
}
// Populate meta results
const metaList = document.getElementById('metaResults');
metaList.innerHTML = results.results.meta.map(item =>
`<li class="${item.status}"><span>${item.text}</span></li>`
).join('');
// Populate content results
const contentList = document.getElementById('contentResults');
contentList.innerHTML = results.results.content.map(item =>
`<li class="${item.status}"><span>${item.text}</span></li>`
).join('');
// Populate links results
const linksList = document.getElementById('linksResults');
linksList.innerHTML = results.results.links.map(item =>
`<li class="${item.status}"><span>${item.text}</span></li>`
).join('');
// Populate images results
const imagesList = document.getElementById('imagesResults');
imagesList.innerHTML = results.results.images.map(item =>
`<li class="${item.status}"><span>${item.text}</span></li>`
).join('');
analyzeBtn.textContent = 'Analyze Again';
analyzeBtn.disabled = false;
}
});
The popup script handles user interactions and displays the analysis results. When the user clicks the analyze button, it retrieves the current active tab, runs the analyzer, and populates each section with the results. The score display changes color based on the overall SEO health: green for good scores, yellow for moderate, and red for poor scores.
Background Service Worker
Finally, create the background service worker to handle extension lifecycle events:
// background.js
chrome.runtime.onInstalled.addListener(() => {
console.log('SEO Analyzer Pro installed');
});
// Handle extension icon click
chrome.action.onClicked.addListener(async (tab) => {
// This won't fire because we're using a popup
// But required for MV3 background scripts
});
The background service worker is minimal in this case since most of our functionality lives in the popup and content scripts. However, it’s required for the extension to function properly with Manifest V3.
Loading and Testing Your Extension
Now that you have created all the necessary files, it’s time to load your extension into Chrome and test it. Follow these steps to get your SEO analyzer running:
First, open Chrome and navigate to chrome://extensions/ in the address bar. Enable “Developer mode” using the toggle switch in the top-right corner of the page. This reveals additional options for loading unpacked extensions.
Click the “Load unpacked” button that appears and select your seo-analyzer project directory. Chrome will load your extension and display it in the extensions list. If there are any errors, they will appear in the console, allowing you to debug issues.
Once loaded, navigate to any website and click your extension icon in the Chrome toolbar. The popup will appear showing the URL of the current page. Click the “Analyze Page” button to run the SEO analysis. Within seconds, you will see comprehensive results displayed in each category with color-coded feedback.
Try testing your extension on different types of pages to see how it handles various scenarios. Test on pages with good SEO, pages with poor SEO, single-page applications, and pages with dynamic content. This will help you understand the analyzer’s capabilities and identify any edge cases that might need additional handling.
Publishing to the Chrome Web Store
When your SEO tool extension is working correctly and provides valuable analysis, you may want to publish it to the Chrome Web Store to reach a wider audience. The publishing process involves creating a developer account, preparing your extension for distribution, and submitting it for review.
First, visit the Chrome Web Store Developer Dashboard and create a developer account if you don’t already have one. There is a one-time registration fee required for new developers. Once your account is set up, you can package your extension into a ZIP file and upload it through the dashboard.
When submitting your extension, provide clear, descriptive information including the name “SEO Analyzer Pro” or a similar compelling title, a detailed description explaining the features and benefits of your SEO tool extension, appropriate screenshots showing the analysis results in action, and relevant category tags to help users discover your extension.
The review process typically takes a few days. Google checks for policy compliance, malicious behavior, and proper functionality. Make sure your extension follows all Chrome Web Store policies, particularly regarding user privacy and data handling.
Conclusion and Next Steps
Congratulations! You have successfully built a comprehensive SEO analyzer Chrome extension that can analyze web pages for critical on-page SEO factors. This extension provides real value to users seeking quick SEO insights without leaving their browsers, filling a genuine gap in the Chrome Web Store.
The foundation you have built can be extended in numerous ways to create an even more powerful SEO tool extension. Consider adding features like keyword density analysis to identify over-optimized or under-optimized content, readability scores using algorithms like Flesch-Kincaid, structured data validation to check for Schema.org markup, page speed integration to combine SEO with performance metrics, and the ability to export reports for documentation and sharing.
You might also enhance the user experience with features like historical tracking to monitor SEO scores over time, batch analysis for comparing multiple pages, custom scoring rules based on specific SEO strategies, and integration with third-party SEO platforms through their APIs.
Building this SEO analyzer demonstrates the power of Chrome extensions to provide practical, immediate value to users. The skills you have learned in this tutorial—working with the Chrome APIs, creating intuitive interfaces, analyzing web page content, and packaging extensions for distribution—are applicable to countless other extension projects you might undertake in the future.
Start testing your extension today, refine the analysis logic based on your findings, and consider publishing it to the Chrome Web Store. With dedication and continuous improvement, your SEO analyzer could become a valuable tool in every digital marketer’s toolkit.
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. —
Built by theluckystrike