Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Error’d: Pickup Sticklers

      September 27, 2025

      From Prompt To Partner: Designing Your Custom AI Assistant

      September 27, 2025

      Microsoft unveils reimagined Marketplace for cloud solutions, AI apps, and more

      September 27, 2025

      Design Dialects: Breaking the Rules, Not the System

      September 27, 2025

      Building personal apps with open source and AI

      September 12, 2025

      What Can We Actually Do With corner-shape?

      September 12, 2025

      Craft, Clarity, and Care: The Story and Work of Mengchu Yao

      September 12, 2025

      Cailabs secures €57M to accelerate growth and industrial scale-up

      September 12, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025
      Recent

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025

      Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

      September 28, 2025

      The first browser with JavaScript landed 30 years ago

      September 27, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured
      Recent
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Build an Advice Generator Chrome Extension with Manifest V3

    How to Build an Advice Generator Chrome Extension with Manifest V3

    August 26, 2025

    In 2025, using Chrome without extensions is like using a smartphone without apps. It’s possible, but you’re missing out on a lot.

    And despite how essential extensions are, creating one is very simple – it’s just HTML, CSS, and JavaScript with browser APIs.

    In this tutorial, we are going to learn about Chrome extensions by building an Advice Generator extension with Manifest V3 (MV3), the latest and most secure architecture for Chrome Extensions. You can move along to see what we’ll build here.

    Table of Contents

    • What are the Key Components of a Chrome Extension?

    • How to Build an Advice Generator Chrome Extension

    • The Benefits of Manifest V3

    • How to Debug Your Chrome Extension

    • Conclusion

    What are the Key Components of a Chrome Extension?

    Chrome extensions are incredibly powerful tools that can add custom functionality directly into your Browser experience to transform how you use the web.

    Before we write any code, let’s understand some key components:

    • Every extension starts with a manifest file. This JSON file tells Chrome everything it needs to know about an extension: name, version, permissions, and files

    • The user interface is built with HTML, CSS, and JavaScript. It’s essentially a mini webpage that lives inside your browser

    • Finally, there’s the service worker which runs in the background and fetches data from external APIs. In Manifest V3, service workers have replaced background pages

    How to Build an Advice Generator Chrome Extension

    Here’s a look at what we’re going to build:

    381f422d-f83c-49a9-a007-051ddea6e8da

    This design is by Frontend Mentor.

    Prerequisites:

    To follow along with this tutorial, you need:

    • Basic understanding of HTML, CSS and JavaScript

    • A Chrome browser

    • A text editor

    When structuring an extension project, the only prerequisite is to place the manifest.json file in the extension’s root directory.

    Testing Your Chrome Extension (Load Unpacked)

    Before we start building, you’ll want to see your progress after each file to catch any issues early. Here’s how to load your extension into Chrome for testing:

    1. Go to chrome://extensions to open the Chrome Extensions page.

    2. In the top right corner of the Extensions page, toggle the Developer mode on.

    3. Click the Load unpacked button that appears.

    4. In the file dialog, go to the root folder of the extension and click Select Folder.

    Your extension should appear. If its icon does not appear in your browser’s toolbar immediately, click the puzzle icon in your toolbar and pin it.

    A screenshot showing how to pin a Chrome extension from a browser's toolbar

    Now let’s start by defining our extension’s identity in the manifest.json file.

    The Benefits of Manifest V3

    The manifest.json is the heart of a Chrome Extension. Written in JSON (JavaScript Object Notation), it provides Chrome with everything it needs to know about your extension.

    Think of it like a passport with visas and Chrome as the immigration officer verifying identity and access.

    An image depicting the analogy of the Manifest file as a passport and visa and Chrome as the immigration officer that ensures the right permissions.

    Manifest V3 (MV3), brings better performance, security, and reliability to extensions. MV3 uses service workers that activate only when needed, improving battery life and preventing extensions from slowing down your browser.

    Let’s break down each important field:

    • manifest_version is the most critical line. Give it a value of 3 to tell Chrome you’re using Manifest V3.

    • name, version, description define your extension’s basic identity.

    • action is a Manifest V3 field that controls what happens when someone clicks your extension’s default_icon in the toolbar. The default_popup points to your HTML file, so clicking the icon opens that page in a small popup window.

    • permissions tells Chrome what your extension needs access to. We’re using host permission https://api.adviceslip.com/* so our extension can fetch advice from that API. Without it, the extension would be blocked from making those requests. This might seem overly cautious, but it’s a security measure that protects users.

    • background points to your service worker script. The service_worker field tells Chrome that service-worker.js should run in the background.

    Step 1: Create a Manifest 3 File

    Going by the explanations of the various parts of the file above, here’s what our manifest.json file would look like:

    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Advice Generator"</span>,
      <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Get a fresh piece of advice whenever you need it!"</span>,
      <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
      <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">3</span>,
      <span class="hljs-attr">"action"</span>: {
        <span class="hljs-attr">"default_popup"</span>: <span class="hljs-string">"index.html"</span>,
        <span class="hljs-attr">"default_icon"</span>: <span class="hljs-string">"/icons/icon-dice.png"</span>
      },
      <span class="hljs-attr">"permissions"</span>: [
        <span class="hljs-string">"activeTab"</span>
      ],
      <span class="hljs-attr">"host_permissions"</span>: [
        <span class="hljs-string">"https://api.adviceslip.com/*"</span>
      ],
      <span class="hljs-attr">"background"</span>: {
        <span class="hljs-attr">"service_worker"</span>: <span class="hljs-string">"service-worker.js"</span>
      }
    }
    

    You might see activeTab in other extension examples. While we don’t strictly need it for this, it’s worth knowing about. It gives temporary access to whatever tab the user is on, but only when they click the extensions icon.

    The image below will be the result of running our manifest code above:

    A screenshot showing the Advice Generator Chrome extension after running the Manifest.json

    Step 2: Create the HTML and CSS Pages

    Now that our extension has its identity and permissions defined, let’s move on to building the user interface starting with an index.html page.

    <span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
    <span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>></span>
    <span class="hljs-tag"><<span class="hljs-name">head</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">title</span>></span>Advice Generator<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
        <span class="hljs-tag"><<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">"style.css"</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Manrope:wght@400;800&display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>></span>
    <span class="hljs-tag"></<span class="hljs-name">head</span>></span>
    <span class="hljs-tag"><<span class="hljs-name">body</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-card"</span>></span>
            <span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-id"</span>></span>ADVICE #<span class="hljs-tag"><<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-id-number"</span>></span><span class="hljs-tag"></<span class="hljs-name">span</span>></span><span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
            <span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-quote"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-quote"</span>></span>
                “It is easy to sit up and take notice, what's difficult is getting up and taking action.”
            <span class="hljs-tag"></<span class="hljs-name">p</span>></span>
            <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"divider"</span>></span>
                <span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"icons/pattern-divider.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Divider pattern"</span>></span>
            <span class="hljs-tag"></<span class="hljs-name">div</span>></span>
            <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"dice-button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"generate-advice-btn"</span>></span>
                <span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"icons/icon-dice.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Dice icon"</span>></span>
            <span class="hljs-tag"></<span class="hljs-name">button</span>></span>
        <span class="hljs-tag"></<span class="hljs-name">main</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"index.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
    <span class="hljs-tag"></<span class="hljs-name">body</span>></span>
    <span class="hljs-tag"></<span class="hljs-name">html</span>></span>
    

    Now, let’s bring the design to life with a style.css file in your root directory. We’ll set up the overall body styles, position the card, and style all the elements within it.

    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-comment">/* Define colors from the Frontend Mentor style guide */</span>
        <span class="hljs-attribute">--clr-light-cyan</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">193</span>, <span class="hljs-number">38%</span>, <span class="hljs-number">86%</span>);
        <span class="hljs-attribute">--clr-neon-green</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">150</span>, <span class="hljs-number">100%</span>, <span class="hljs-number">66%</span>);
        <span class="hljs-attribute">--clr-grayish-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">217</span>, <span class="hljs-number">19%</span>, <span class="hljs-number">35%</span>);
        <span class="hljs-attribute">--clr-dark-grayish-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">217</span>, <span class="hljs-number">19%</span>, <span class="hljs-number">25%</span>);
        <span class="hljs-attribute">--clr-dark-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">218</span>, <span class="hljs-number">23%</span>, <span class="hljs-number">16%</span>); 
        <span class="hljs-comment">/* Typography */</span>
        <span class="hljs-attribute">--ff-manrope</span>: <span class="hljs-string">'Manrope'</span>, sans-serif;
        <span class="hljs-attribute">--fw-regular</span>: <span class="hljs-number">400</span>;
        <span class="hljs-attribute">--fw-bold</span>: <span class="hljs-number">700</span>;
    }
    <span class="hljs-selector-tag">body</span> {
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
        <span class="hljs-attribute">font-family</span>: <span class="hljs-built_in">var</span>(--ff-manrope);
        <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-dark-blue);
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">justify-content</span>: center;
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
        <span class="hljs-attribute">min-width</span>: <span class="hljs-number">30rem</span>;
        <span class="hljs-attribute">box-sizing</span>: border-box;
    }
    <span class="hljs-selector-class">.advice-card</span> {
        <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-dark-grayish-blue);
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">60%</span>; 
        <span class="hljs-attribute">text-align</span>: center;
        <span class="hljs-attribute">position</span>: relative;
        <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-number">20px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
        <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">70px</span>; 
    }
    <span class="hljs-selector-class">.advice-id</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--clr-neon-green);
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.8em</span>;
        <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">4px</span>;
        <span class="hljs-attribute">text-transform</span>: uppercase;
        <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
    }
    <span class="hljs-selector-class">.advice-quote</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--clr-light-cyan);
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.75em</span>; 
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-built_in">var</span>(--fw-bold);
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.4</span>;
        <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1.2rem</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">15px</span>;
    }
    <span class="hljs-selector-class">.divider</span> {
        <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">35px</span>;
    }
    <span class="hljs-selector-class">.divider</span> <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">max-width</span>: <span class="hljs-number">90%</span>;
        <span class="hljs-attribute">height</span>: auto;
    }
    <span class="hljs-selector-class">.dice-button</span> {
        <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-neon-green);
        <span class="hljs-attribute">border</span>: none;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">2rem</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">2rem</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">justify-content</span>: center;
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">cursor</span>: pointer;
        <span class="hljs-attribute">position</span>: absolute;
        <span class="hljs-attribute">bottom</span>: -<span class="hljs-number">1rem</span>; 
        <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
        <span class="hljs-attribute">transition</span>: box-shadow <span class="hljs-number">0.3s</span> ease-in-out;
    }
    <span class="hljs-selector-class">.dice-button</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">40px</span> <span class="hljs-built_in">var</span>(--clr-neon-green);
    }
    <span class="hljs-selector-class">.dice-button</span> <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">2rem</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">2rem</span>;
    }
    

    The image below will be the result of running our HTML and CSS code above plus the initial manifest:

    An image of the Advice Generator Chrome extension design

    With the HTML and CSS done, our extension’s visual aspect is complete. Next, let’s give it life by writing the JavaScript that handles fetching new advice and updating the display.

    Step 3: Add a Service Worker

    In Manifest V3, the core background logic for an extension lives in its Service Worker. Unlike the persistent background pages of Manifest V2, in V3 Service Workers run only when needed, such as in response to a message from index.js or a browser event.

    Our service-worker.js will have these roles:

    • Listen for a request from index.js (when the user clicks the dice).

    • Fetch a new piece of advice from the Advice Slip API.

    • Send that advice back to index.js to be displayed.

    Create a file named service-worker.js in your extension’s root directory.

    chrome.runtime.onMessage.addListener(<span class="hljs-function">(<span class="hljs-params">request, sender, sendResponse</span>) =></span> {
      <span class="hljs-keyword">if</span> (request.action === <span class="hljs-string">"fetchAdvice"</span>) {
        fetchAdvice().then(<span class="hljs-function"><span class="hljs-params">adviceData</span> =></span> {
          sendResponse({ <span class="hljs-attr">advice</span>: adviceData });
        }).catch(<span class="hljs-function"><span class="hljs-params">error</span> =></span> {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching advice:"</span>, error);
          sendResponse({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Failed to fetch advice"</span> });
        });
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
      }
    });
    <span class="hljs-comment">// Function to fetch advice from the Advice Slip API</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchAdvice</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.adviceslip.com/advice"</span>);
        <span class="hljs-keyword">if</span> (!response.ok) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! status: <span class="hljs-subst">${response.status}</span>`</span>);
        }
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        <span class="hljs-keyword">return</span> data.slip; 
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Could not fetch advice:"</span>, error);
        <span class="hljs-keyword">throw</span> error; 
      }
    }
    

    Message Handling in Service Workers

    Since Service Workers don’t have direct access to the DOM of your index.html page (and vice versa), they communicate using message passing. As you can see in the code above, the user clicks the dice in index.html, and index.js will send a message to service-worker.js asking for new advice. The Service Worker will then fetch the advice and send it back in another message.

    chrome.runtime.onMessage.addListener listens for incoming messages and sendResponse replies.

    Our Service Worker is now ready to fetch advice. The next step is to make our index.js interact with it.

    Step 4: Add App Functionality

    First, we’ll create our index.js file. This script is responsible for all the user-facing logic. It will handle the user’s interaction (clicking the dice), send a message to our service-worker.js to get new advice, and then update the index.html with the fetched advice.

    Our index.js will perform the following steps:

    1. Reference the HTML elements where we’ll display the advice ID, quote, and dice.

    2. Set up an event listener for when the dice is clicked.

    3. Send a message to the service-worker.js to request new advice.

    4. Receive the advice back from service-worker.js and update the content on the index.html page.

    <span class="hljs-comment">// Get references to our HTML elements</span>
    <span class="hljs-keyword">const</span> adviceIdElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'advice-id-number'</span>);
    <span class="hljs-keyword">const</span> adviceQuoteElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'advice-quote'</span>);
    <span class="hljs-keyword">const</span> generateAdviceBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'generate-advice-btn'</span>);
    <span class="hljs-comment">// Function to request advice from the Service Worker</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestNewAdvice</span>(<span class="hljs-params"></span>) </span>{
      chrome.runtime.sendMessage({ <span class="hljs-attr">action</span>: <span class="hljs-string">"fetchAdvice"</span> }, <span class="hljs-function">(<span class="hljs-params">response</span>) =></span> {
        <span class="hljs-keyword">if</span> (chrome.runtime.lastError) {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error sending message:"</span>, chrome.runtime.lastError);
          adviceQuoteElement.textContent = <span class="hljs-string">"Error: Could not get advice."</span>;
          adviceIdElement.textContent = <span class="hljs-string">"---"</span>;
          <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-keyword">if</span> (response && response.advice) {
          adviceIdElement.textContent = response.advice.id;
          adviceQuoteElement.textContent = <span class="hljs-string">`“<span class="hljs-subst">${response.advice.advice}</span>”`</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (response && response.error) {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Service Worker error:"</span>, response.error);
          adviceQuoteElement.textContent = <span class="hljs-string">`Error: <span class="hljs-subst">${response.error}</span>`</span>;
          adviceIdElement.textContent = <span class="hljs-string">"---"</span>;
        }
      });
    }
    <span class="hljs-keyword">if</span> (generateAdviceBtn) {
      generateAdviceBtn.addEventListener(<span class="hljs-string">'click'</span>, requestNewAdvice);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Generate advice button not found!"</span>);
    }
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'DOMContentLoaded'</span>, requestNewAdvice);
    

    With index.js in place, our Advice Generator is now ready as you can see in the GIF below:

    A GIF showing the finished Advice Generator Chrome extension

    The next crucial step is to know how to debug your extension, should anything go wrong.

    How to Debug Your Chrome Extension

    Chrome provides excellent debugging tools to help troubleshoot extensions. Always follow these essential steps:

    • Reload your extension after making changes (especially to manifest.json or service-worker.js) by clicking the refresh icon on chrome://extensions.

    • Check your manifest.json for typos – missing commas or brackets will break everything.

    • Verify your API URL and make sure you have the right permissions listed in manifest.json.

    Debugging the Main HTML and JS Pages

    This is likely where you’ll encounter most of your initial JavaScript or HTML/CSS issues.

    1. Open the extension and right-click anywhere in the popup to Inspect.

    2. Check the Console tab for JavaScript errors from your index.js file.

    3. Use the Elements tab to inspect your HTML and tweak CSS styles in real-time.

    A GIF showing how to inspect the Elements and Console tabs of a Chrome extension

    Debugging the Service Worker – Crucial for MV3

    The Service Worker runs in the background and has its own separate DevTools.

    1. Go to chrome://extensions.

    2. Click the Service worker link underneath your extension or the Errors button.

    3. Check the Console and Network tabs for service worker and API errors respectively.

    A screenshot showing a Chrome extension with the service worker link and errors button

    Conclusion

    Congratulations, you’ve just built a Chrome extension using Manifest V3. You’ve created a user interface, implemented background processing with a service worker, and established communication between different parts of your extension. These skills are the building blocks for any Chrome extension, no matter how simple or complex.

    Here are some helpful resources:

    • MDN on Browser Extensions

    • Chrome Devs on Chrome Extensions

    Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & MoreÂ

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleRust Slices: Cutting Into References the Safe Way
    Next Article How WebGL and Three.js Power Interactive Online Stores

    Related Posts

    Development

    Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

    September 28, 2025
    Development

    Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

    September 28, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    How to Use a Resistive Soil Moisture Sensor

    Development

    Vision Foundation Models: Implementation and Business Applications

    Machine Learning

    HashFlare Ponzi Scheme: Founders Convicted in $577M Crypto Fraud

    Development

    Microsoft Windows Vulnerability Exploited to Deploy PipeMagic RansomExx Malware

    Development

    Highlights

    Cubify Anything: Scaling Indoor 3D Object Detection

    May 21, 2025

    We consider indoor 3D object detection with respect to a single RGB(-D) frame acquired from…

    Text-to-image basics with Amazon Nova Canvas

    May 29, 2025

    Building a Versatile Multi‑Tool AI Agent Using Lightweight Hugging Face Models

    July 22, 2025

    AI Has Flipped Software Development

    July 29, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.