Step-by-Step Guide to Building a Chrome Extension

This guide walks through building a Chrome extension from scratch, covering manifest configuration, UI pages, content and background scripts, required permissions, development tools, debugging techniques, packaging, publishing to the Chrome Web Store, and common feature implementations such as page interaction, messaging, and request interception.

Subtle Storm
Subtle Storm
Subtle Storm
Step-by-Step Guide to Building a Chrome Extension

Chrome Extension Fundamentals

Extensions are defined by a manifest.json that specifies name, version, permissions, icons and resources. Core components are Content Scripts (injected into pages, can manipulate DOM and listen to events), Background Scripts (service workers handling browser events such as tab creation or bookmark updates), Popup/Options pages (UI shown when the extension icon is clicked), and Browser/Page Actions (toolbar button interactions).

Project Structure

├── manifest.json          # core configuration
├── icons/                # icon files (16, 48, 128)
├── popup.html            # UI shown on icon click
├── popup.js              # logic for popup
├── background.js         # background service worker
├── content-script.js     # script injected into web pages
└── options.html          # optional settings page

Development Environment

Code editor: VS Code or WebStorm.

Chrome browser for loading and debugging extensions.

Optional bundlers (Webpack, Parcel) for complex projects.

Step‑by‑Step Implementation

1. Create manifest.json

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "description": "A simple Chrome extension.",
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "action": { "default_popup": "popup.html" },
  "permissions": ["storage", "activeTab"],
  "background": { "service_worker": "background.js" },
  "content_scripts": [{
    "matches": ["https://*/*"],
    "js": ["content-script.js"]
  }]
}

2. Build the popup UI

<!DOCTYPE html>
<html><body>
  <h1>My Extension</h1>
  <button id="btn">Click Me</button>
  <script src="popup.js"></script>
</body></html>
document.getElementById('btn').addEventListener('click', () => {
  chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
    chrome.tabs.sendMessage(tabs[0].id, {action: "changeColor"});
  });
});

3. Add a content script

// content-script.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "changeColor") {
    document.body.style.backgroundColor = "#ff0000";
  }
});

4. Define a background service worker

// background.js (Manifest V3)
chrome.runtime.onInstalled.addListener(() => {
  console.log("Extension installed!");
});

5. Declare permissions and use storage

Permissions such as "tabs" or "bookmarks" are listed in the permissions array of manifest.json. Persistent data can be stored with the chrome.storage API (requires the "storage" permission):

// Save data
chrome.storage.local.set({key: "value"});
// Retrieve data
chrome.storage.local.get(["key"], (result) => {
  console.log(result.key);
});

Debugging and Hot‑Reload

Content scripts are debugged via the page’s DevTools.

Background scripts are inspected from chrome://extensions → Service worker → Console.

Popup/Options pages are inspected by right‑clicking the extension icon and selecting “Inspect”.

After code changes, click the reload button on the chrome://extensions page to hot‑reload the extension.

Packaging and Publishing

On chrome://extensions click “Pack extension” to generate a .zip or .crx file. Upload the package through the Chrome Web Store developer console, provide description, screenshots and category, and submit for review (typically 1‑7 days).

Common Feature Implementations

Interact with the page

chrome.scripting.executeScript({
  target: {tabId},
  files: ['injected-script.js']
});

Cross‑extension messaging

// Send a message
chrome.runtime.sendMessage(extensionId, {message: "hello"});
// Receive a message
chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {});

Network request interception (requires permission)

chrome.webRequest.onBeforeRequest.addListener(
  (details) => { /* handle logic */ },
  {urls: ["<all_urls>"]},
  ["blocking"]
);

Reference Resources

Official Chrome Extension documentation.

Chrome Extension Samples repository.

Chrome DevTools for debugging.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DebuggingJavaScriptChrome ExtensionPackagingweb developmentManifest V3Content ScriptChrome Web Store
Subtle Storm
Written by

Subtle Storm

The micro era's marvels are boundlessly subtle.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.