<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ ai seo - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ ai seo - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 09:15:27 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ai-seo/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Chrome Extension That Analyzes Any Web Page Using JavaScript and Manifest V3 ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever visited a website and wondered how well is this page structured? Does it have a meta description? How many links or headings does it use? Usually, you’d open DevTools or an SEO auditing tool to find answers to these questions. But what ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-chrome-extension-using-javascript-and-manifest-v3/</link>
                <guid isPermaLink="false">6900f612596c2221585d95a4</guid>
                
                    <category>
                        <![CDATA[ chrome extension ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ai seo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ devtools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Hitesh Chauhan ]]>
                </dc:creator>
                <pubDate>Tue, 28 Oct 2025 16:57:54 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761670419000/13ac96ca-6e28-413f-a0e0-56ed353a007c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever visited a website and wondered how well is this page structured? Does it have a meta description? How many links or headings does it use?</p>
<p>Usually, you’d open DevTools or an SEO auditing tool to find answers to these questions. But what if you could analyze any web page instantly, without leaving your browser?</p>
<p>In this tutorial, you’ll learn how to build a Chrome extension that scans and analyzes any webpage for titles, meta descriptions, headings, and links.</p>
<p>By the end of this article, you’ll:</p>
<ul>
<li><p>Understand how Manifest V3 works in Chrome Extensions</p>
</li>
<li><p>Learn how to inject content scripts into web pages</p>
</li>
<li><p>Build a popup UI that fetches and displays structured data</p>
</li>
<li><p>Explore how this same foundation can be extended with AI-powered insights</p>
</li>
</ul>
<p>💡 This guide focuses on learning and education – no frameworks or build tools required. Just HTML, CSS, and vanilla JavaScript.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-understanding-how-chrome-extensions-work">Step 1: Understanding How Chrome Extensions Work</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-set-up-the-project-structure">Step 2: Set Up the Project Structure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-define-the-manifest-file">Step 3: Define the Manifest File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-create-the-popup-ui">Step 4: Create the Popup UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-write-the-content-script-contentjs">Step 5: Write the Content Script (content.js)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-connect-the-popup-and-content-script">Step 6: Connect the Popup and Content Script</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-load-and-test-your-extension">Step 7: Load and Test Your Extension</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-8-add-optional-enhancements">Step 8: Add Optional Enhancements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-9-publish-to-the-chrome-web-store">Step 9: Publish to the Chrome Web Store</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">🧰 Prerequisites</h2>
<p>Before starting this tutorial, make sure you have:</p>
<ul>
<li><p>A basic understanding of HTML, CSS, and JavaScript</p>
</li>
<li><p>A recent version of Google Chrome installed on your system</p>
</li>
<li><p>Familiarity with using Chrome DevTools (optional but helpful)</p>
</li>
<li><p>A code editor like VS Code or Sublime Text</p>
</li>
<li><p>A local folder where you can create and organize your extension files</p>
</li>
</ul>
<p>💡 Again, no frameworks or build tools are required. We’ll use only vanilla JavaScript and simple web technologies throughout this guide.</p>
<h2 id="heading-step-1-understanding-how-chrome-extensions-work">🧩 Step 1: Understanding How Chrome Extensions Work</h2>
<p>A Chrome extension is just a bundle of web technologies – HTML, CSS, and JS – that extends browser functionality.</p>
<p>Extensions can have multiple parts:</p>
<ul>
<li><p><strong>Manifest file</strong> (<code>manifest.json</code>): defines permissions, icons, and structure.</p>
</li>
<li><p><strong>Content scripts</strong>: run inside web pages and access the DOM.</p>
</li>
<li><p><strong>Background scripts</strong>: handle long-running or event-driven logic.</p>
</li>
<li><p><strong>Popup UI</strong>: what users see when they click your extension icon.</p>
</li>
</ul>
<p>Here’s a high-level flow of what we’ll build:</p>
<pre><code class="lang-plaintext">[Popup UI] &lt;—&gt; [Content Script] &lt;—&gt; [Web Page DOM]
</code></pre>
<p>When the user clicks “Analyze,” the popup will send a message to the content script. The script will then read the DOM and send back results like page title, description, headings, and links.</p>
<h2 id="heading-step-2-set-up-the-project-structure">🧠 Step 2: Set Up the Project Structure</h2>
<p>Create a new folder called <code>page-analyzer-extension</code>. Inside it, create these files:</p>
<pre><code class="lang-plaintext">page-analyzer-extension/
│
├── manifest.json
├── popup.html
├── popup.js
├── content.js
├── styles.css
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png
</code></pre>
<p>Icons are optional, but they make the extension look professional. You can use placeholders or generate them from <a target="_blank" href="https://favicon.io/">favicon.io</a>.</p>
<h2 id="heading-step-3-define-the-manifest-file">⚙️ Step 3: Define the Manifest File</h2>
<p>Create <code>manifest.json</code> and paste this in:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">3</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Page Analyzer"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Analyze any web page for its title, description, headings, and links."</span>,
  <span class="hljs-attr">"permissions"</span>: [<span class="hljs-string">"activeTab"</span>, <span class="hljs-string">"scripting"</span>],
  <span class="hljs-attr">"action"</span>: {
    <span class="hljs-attr">"default_popup"</span>: <span class="hljs-string">"popup.html"</span>,
    <span class="hljs-attr">"default_icon"</span>: {
      <span class="hljs-attr">"16"</span>: <span class="hljs-string">"icons/icon16.png"</span>,
      <span class="hljs-attr">"48"</span>: <span class="hljs-string">"icons/icon48.png"</span>,
      <span class="hljs-attr">"128"</span>: <span class="hljs-string">"icons/icon128.png"</span>
    }
  },
  <span class="hljs-attr">"content_scripts"</span>: [
    {
      <span class="hljs-attr">"matches"</span>: [<span class="hljs-string">"&lt;all_urls&gt;"</span>],
      <span class="hljs-attr">"js"</span>: [<span class="hljs-string">"content.js"</span>]
    }
  ]
}
</code></pre>
<p>Let’s break this down:</p>
<ul>
<li><p><code>manifest_version: 3</code>: the latest version with security and performance improvements</p>
</li>
<li><p><code>permissions</code>: allow the extension to access the active tab and run scripts</p>
</li>
<li><p><code>content_scripts</code>: define which JS files should automatically run in web pages</p>
</li>
</ul>
<h2 id="heading-step-4-create-the-popup-ui">🧩 Step 4: Create the Popup UI</h2>
<p>The popup appears when users click the extension icon.</p>
<p><code>popup.html</code>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Page Analyzer<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Page Analyzer<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Click below to analyze the current page:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"analyze"</span>&gt;</span>Analyze Page<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"popup.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><code>styles.css</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: system-ui, sans-serif;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">280px</span>;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#2563eb</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span> <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
}
<span class="hljs-selector-id">#results</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">13px</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.4</span>;
  <span class="hljs-attribute">word-wrap</span>: break-word;
}
</code></pre>
<h2 id="heading-step-5-write-the-content-script-contentjs">🧠 Step 5: Write the Content Script (<code>content.js</code>)</h2>
<p>This script will analyze the web page.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">analyzePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> title = <span class="hljs-built_in">document</span>.title || <span class="hljs-string">"No title found"</span>;
  <span class="hljs-keyword">const</span> description =
    <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'meta[name="description"]'</span>)?.content || <span class="hljs-string">"No description found"</span>;
  <span class="hljs-keyword">const</span> headings = <span class="hljs-built_in">Array</span>.from(<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"h1, h2, h3"</span>)).map(<span class="hljs-function">(<span class="hljs-params">h</span>) =&gt;</span>
    h.innerText.trim()
  );
  <span class="hljs-keyword">const</span> links = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"a"</span>).length;

  <span class="hljs-keyword">return</span> {
    title,
    description,
    headings,
    <span class="hljs-attr">linkCount</span>: links,
    <span class="hljs-attr">domain</span>: location.hostname,
  };
}

chrome.runtime.onMessage.addListener(<span class="hljs-function">(<span class="hljs-params">message, sender, sendResponse</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (message.action === <span class="hljs-string">"analyze"</span>) {
    sendResponse(analyzePage());
  }
});
</code></pre>
<p>What’s happening here:</p>
<ul>
<li><p>We extract the title, description, headings, and total link count</p>
</li>
<li><p>We return this data as a structured object</p>
</li>
<li><p>The script listens for messages from the popup and responds with the analysis</p>
</li>
</ul>
<h2 id="heading-step-6-connect-the-popup-and-content-script">⚡ Step 6: Connect the Popup and Content Script</h2>
<p>In <code>popup.js</code>, add the logic that triggers page analysis.</p>
<pre><code class="lang-js"><span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"analyze"</span>).addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> [tab] = <span class="hljs-keyword">await</span> chrome.tabs.query({ <span class="hljs-attr">active</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">currentWindow</span>: <span class="hljs-literal">true</span> });

  chrome.tabs.sendMessage(tab.id, { <span class="hljs-attr">action</span>: <span class="hljs-string">"analyze"</span> }, <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> resultContainer = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"results"</span>);

    <span class="hljs-keyword">if</span> (!response) {
      resultContainer.innerText = <span class="hljs-string">"Unable to analyze this page."</span>;
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">const</span> { title, description, headings, linkCount, domain } = response;
    resultContainer.innerHTML = <span class="hljs-string">`
      &lt;strong&gt;Domain:&lt;/strong&gt; <span class="hljs-subst">${domain}</span>&lt;br/&gt;
      &lt;strong&gt;Title:&lt;/strong&gt; <span class="hljs-subst">${title}</span>&lt;br/&gt;
      &lt;strong&gt;Description:&lt;/strong&gt; <span class="hljs-subst">${description}</span>&lt;br/&gt;
      &lt;strong&gt;Headings:&lt;/strong&gt; <span class="hljs-subst">${
        headings.length ? headings.join(<span class="hljs-string">", "</span>) : <span class="hljs-string">"No headings found"</span>
      }</span>&lt;br/&gt;
      &lt;strong&gt;Links:&lt;/strong&gt; <span class="hljs-subst">${linkCount}</span>
    `</span>;
  });
});
</code></pre>
<p>This uses the <strong>Chrome Tabs API</strong> to find the current tab and send a message to the content script. When the script responds, we update the popup with the results.</p>
<h2 id="heading-step-7-load-and-test-your-extension">🧪 Step 7: Load and Test Your Extension</h2>
<ol>
<li><p>Open chrome://extensions/</p>
</li>
<li><p>Enable Developer Mode</p>
</li>
<li><p>Click Load Unpacked</p>
</li>
<li><p>Select your project folder</p>
</li>
</ol>
<p>Now, pin your extension to the toolbar, open any website, and click “Analyze Page.”</p>
<p>You’ll instantly see:</p>
<ul>
<li><p>The page’s title</p>
</li>
<li><p>Meta description</p>
</li>
<li><p>Extracted headings (H1–H3)</p>
</li>
<li><p>Link count</p>
</li>
<li><p>Domain name</p>
</li>
</ul>
<p>🎉 Congratulations! You’ve built a working web page analyzer.</p>
<h2 id="heading-step-8-add-optional-enhancements">🧩 Step 8: Add Optional Enhancements</h2>
<p>Now that the basics work, here are some ways to level up your project.</p>
<h3 id="heading-1-add-ai-insights">🧠 1. Add AI Insights</h3>
<p>You can connect to an AI API (like OpenAI or Gemini) to summarize the page or evaluate SEO structure.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Example: pseudo-code for calling an AI API</span>
<span class="hljs-keyword">const</span> aiResponse = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.openai.com/v1/chat/completions"</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
  <span class="hljs-attr">headers</span>: { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${API_KEY}</span>`</span> },
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
      { <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"You are an SEO assistant."</span> },
      { <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">`Analyze the following page info: <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(pageData)}</span>`</span> }
    ]
  })
});
</code></pre>
<p>For example, after building this basic analyzer, I expanded it into a full-featured <a target="_blank" href="https://rankingsfactor.com/extension">RankingsFactor AI SEO Extension</a> which combines this same foundation with:</p>
<ul>
<li><p>AI-generated keyword suggestions</p>
</li>
<li><p>Metadata improvement recommendations</p>
</li>
<li><p>Automatic screenshot capture</p>
</li>
<li><p>Page freshness detection</p>
</li>
</ul>
<p>This demonstrates how a simple developer project can evolve into a powerful, production-ready tool.</p>
<h3 id="heading-2-detect-missing-seo-tags">🔍 2. Detect Missing SEO Tags</h3>
<p>You can check for missing tags like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> missingTags = [];
<span class="hljs-keyword">if</span> (!<span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'meta[name="description"]'</span>)) missingTags.push(<span class="hljs-string">"description"</span>);
<span class="hljs-keyword">if</span> (!<span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'meta[property="og:title"]'</span>)) missingTags.push(<span class="hljs-string">"og:title"</span>);
</code></pre>
<h3 id="heading-3-add-screenshot-or-report-export">🖼️ 3. Add Screenshot or Report Export</h3>
<p>Use the <code>chrome.tabs.captureVisibleTab()</code> API to take a screenshot, or generate a downloadable HTML/JSON report.</p>
<h2 id="heading-step-9-publish-to-the-chrome-web-store">🧭 Step 9: Publish to the Chrome Web Store</h2>
<p>Once you’ve tested your extension, visit <a target="_blank" href="https://chrome.google.com/webstore/devconsole">chrome.google.com/webstore/devconsole</a>. You’ll need to pay a one-time $5 developer registration fee, then you can upload your extension as a ZIP file. Make sure you write a clear, helpful description before submitting your extension for review.</p>
<h2 id="heading-final-thoughts">✅ Final Thoughts</h2>
<p>In this tutorial, you learned:</p>
<ul>
<li><p>How Chrome extensions communicate between scripts and web pages</p>
</li>
<li><p>How to safely extract DOM data</p>
</li>
<li><p>How to display structured information in a popup UI</p>
</li>
<li><p>How to extend browser tools with AI for smarter analysis</p>
</li>
</ul>
<p>Browser extensions are an incredible way to bring web automation, analysis, and creativity directly into your workflow. Whether you’re analyzing pages, improving accessibility, or experimenting with AI, you now have the foundation to build anything you imagine.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
