Published February 27, 2026 · 16 min read

How to Build a Chrome Extension in 2026 (Beginner Guide)

Chrome extensions are one of the most accessible entry points into software development. With basic HTML, CSS, and JavaScript knowledge, you can build a functional extension in an afternoon. Chrome has over 3 billion users, so even a niche extension can reach a meaningful audience.

This guide walks you through every step: project structure, manifest.json configuration (Manifest V3), building a popup, writing content scripts, adding background service workers, and publishing to the Chrome Web Store. No prior extension experience required.

Table of Contents

  1. Anatomy of a Chrome Extension
  2. Step 1: Create manifest.json (Manifest V3)
  3. Step 2: Build the Popup UI
  4. Step 3: Write Content Scripts
  5. Step 4: Add Background Service Workers
  6. Step 5: Test and Debug Locally
  7. Step 6: Publish to the Chrome Web Store
  8. Manifest V2 vs V3 Comparison
  9. FAQ

Anatomy of a Chrome Extension

Every Chrome extension is a folder containing a few specific files. At minimum, you need a manifest.json file that tells Chrome what your extension does and what permissions it needs. From there, you can add a popup (the small window that appears when you click the extension icon), content scripts (JavaScript that runs on web pages), and background service workers (scripts that handle events and long-running logic).

FilePurposeRequired
manifest.jsonExtension metadata, permissions, file referencesYes
popup.htmlUI shown when clicking the extension iconNo
popup.jsJavaScript for popup interactivityNo
content.jsRuns on web pages, can read/modify page DOMNo
background.jsService worker for events, alarms, messagingNo
styles.cssStyles for popup or injected contentNo
icons/Extension icons (16px, 48px, 128px)Recommended

Step 1: Create manifest.json (Manifest V3)

The manifest file is the heart of every Chrome extension. It declares the extension name, version, permissions, and which files to load. Chrome now requires Manifest V3 for all new extensions. Here is a complete starter manifest:

{
  "manifest_version": 3,
  "name": "My First Extension",
  "version": "1.0.0",
  "description": "A simple Chrome extension built from scratch.",
  "permissions": ["activeTab", "storage"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "background": {
    "service_worker": "background.js"
  }
}

Key Fields Explained

manifest_version: 3 — Required. Chrome no longer accepts Manifest V2 for new submissions.
permissions — Declare what APIs your extension needs. activeTab gives access to the current tab when the user clicks your icon. storage lets you save data locally.
action — Defines the popup that appears when the user clicks the extension icon in the toolbar.
content_scripts — Scripts injected into web pages. The matches pattern controls which pages they run on.
background.service_worker — A service worker that runs in the background and responds to events.

The popup is a small HTML page that appears when users click your extension icon. It is a regular HTML file with CSS and JavaScript. The only difference from a normal web page is the size constraint (typically 300-400px wide) and the fact that inline scripts are blocked by Chrome's Content Security Policy.

Create popup.html

Build a simple popup with a heading, a button, and a result area. Keep the design minimal. The popup should load instantly and provide a clear action for the user. Link your CSS and JS as external files (no inline scripts in Manifest V3).

<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 320px; padding: 16px; font-family: sans-serif; }
    h1 { font-size: 18px; margin-bottom: 12px; }
    button { background: #ff5f1f; color: #fff; border: none;
             padding: 10px 20px; border-radius: 6px; cursor: pointer; }
    #result { margin-top: 12px; color: #333; }
  </style>
</head>
<body>
  <h1>My Extension</h1>
  <button id="btn">Count Words on Page</button>
  <p id="result"></p>
  <script src="popup.js"></script>
</body>
</html>

Create popup.js

The popup script communicates with content scripts via Chrome's messaging API. When the user clicks the button, send a message to the content script running on the active tab and display the response.

document.getElementById('btn').addEventListener('click', async () => {
  const [tab] = await chrome.tabs.query({
    active: true, currentWindow: true
  });
  const response = await chrome.tabs.sendMessage(
    tab.id, { action: 'countWords' }
  );
  document.getElementById('result').textContent =
    `Word count: ${response.count}`;
});

Step 3: Write Content Scripts

Content scripts run in the context of web pages. They can read and modify the DOM, extract data, inject UI elements, and communicate with the popup and background scripts. They run in an isolated world, meaning they share the page DOM but not the page's JavaScript variables.

Create content.js

This content script listens for messages from the popup and responds with the word count of the current page's visible text.

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'countWords') {
    const text = document.body.innerText || '';
    const count = text.split(/\s+/).filter(w => w.length > 0).length;
    sendResponse({ count });
  }
});

Content Script Permissions

Content scripts can access the DOM but cannot use most Chrome APIs directly. They communicate with background scripts and popups via chrome.runtime.sendMessage() and chrome.runtime.onMessage. For sensitive operations (storage, network requests, alarms), route messages through the background service worker.

Step 4: Add Background Service Workers

In Manifest V3, background pages are replaced by service workers. Service workers are event-driven: they start when an event occurs and terminate when idle. They do not have access to the DOM but can use all Chrome extension APIs.

Create background.js

A background service worker that runs when the extension is installed, listens for tab updates, and manages extension state.

chrome.runtime.onInstalled.addListener(() => {
  console.log('Extension installed');
  chrome.storage.local.set({ totalCounts: 0 });
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'saveCount') {
    chrome.storage.local.get(['totalCounts'], (result) => {
      const updated = (result.totalCounts || 0) + request.count;
      chrome.storage.local.set({ totalCounts: updated });
      sendResponse({ totalCounts: updated });
    });
    return true; // Keep message channel open for async response
  }
});

Service Worker Lifecycle

Service workers in Manifest V3 do not run persistently. They wake up for events and go back to sleep. This means you cannot rely on global variables staying in memory. Use chrome.storage for any data that needs to persist between service worker activations. This is the biggest change from Manifest V2 background pages.

Step 5: Test and Debug Locally

Load Your Extension

Open Chrome and navigate to chrome://extensions/. Enable "Developer mode" in the top right. Click "Load unpacked" and select your extension folder. Your extension icon should appear in the toolbar immediately.

Debug the Popup

Right-click the extension icon and select "Inspect popup" to open DevTools for the popup. You can see console logs, set breakpoints, and debug JavaScript just like a normal web page.

Debug Content Scripts

Open DevTools on any web page (F12), go to the Sources tab, and find your content script under the "Content scripts" section. You can set breakpoints and step through the code.

Debug the Service Worker

On the chrome://extensions/ page, find your extension and click "Inspect views: service worker." This opens DevTools for the background service worker where you can see logs and debug events.

Step 6: Publish to the Chrome Web Store

Once your extension works correctly in developer mode, you can publish it to the Chrome Web Store for anyone to install.

StepDetailsCost
Create Developer AccountSign up at the Chrome Web Store Developer Dashboard$5 one-time fee
Prepare Store AssetsIcon (128px), screenshots (1280x800), description, categoryFree
Package ExtensionZip your extension folder (exclude .git and node_modules)Free
Upload and SubmitUpload zip, fill in listing details, submit for reviewFree
Review ProcessGoogle reviews for policy compliance. Takes 1-7 business daysFree

Publishing Checklist

Before submitting: (1) Remove all console.log statements. (2) Request only the minimum permissions your extension actually uses. (3) Write a clear, honest description. (4) Include at least two screenshots showing the extension in action. (5) Set up a support email or website. (6) Test on Chrome Stable, Beta, and Dev channels if possible.

Manifest V2 vs V3 Comparison

If you find older tutorials online, they likely use Manifest V2. Here are the key differences to be aware of.

FeatureManifest V2Manifest V3
BackgroundPersistent background pagesEvent-driven service workers
Content Security PolicyRelaxed (inline scripts allowed)Strict (no inline scripts)
Network RequestswebRequest (blocking)declarativeNetRequest (rules-based)
Remote CodeAllowed (eval, remote scripts)Not allowed
PermissionsBroad permissions on installGranular, runtime permissions encouraged
Store AcceptanceNo longer accepted for new submissionsRequired for all new extensions

Format Your Code Faster

Use our free Code Formatter to clean up your HTML, CSS, and JavaScript before publishing your extension.

Get the Free Code Formatter

Frequently Asked Questions

Do I need to know JavaScript to build a Chrome extension?

Basic JavaScript is required for anything interactive. If your extension is purely a popup with static information, you only need HTML and CSS. But most useful extensions involve content scripts or background logic, which require JavaScript. You do not need to be an expert. If you can write event listeners, manipulate the DOM, and handle async functions, you have enough JavaScript knowledge to build a solid extension.

How long does Chrome Web Store review take?

New submissions typically take 1 to 7 business days for review. Updates to existing extensions are usually faster, often within 1-3 days. Extensions requesting sensitive permissions (like access to all URLs or browsing history) may take longer due to additional scrutiny. Keep your permissions minimal to speed up the review process.

Can I monetize a Chrome extension?

Yes. Common monetization strategies include: freemium models (basic features free, premium features paid), one-time purchase via the Chrome Web Store payments API, subscription via your own payment system (Stripe, Gumroad), and affiliate links within the extension popup. The Chrome Web Store no longer supports its built-in payments, so most developers use external payment providers like Stripe or LemonSqueezy.

Share on X