Chrome Extension Development Guide

Prerequisites and Setup

Loading Extensions into Chrome:

  • Navigate to: chrome://extensions/
  • Enable Developer mode
  • Click "Load unpacked extension"
  • Select folder containing manifest.json

WebStorm Configuration:

  • Download: Chrome TypeScript definitions from DefinitelyTyped repository
  • WebStorm Settings: Languages & Frameworks > JavaScript > Libraries
  • Add library and attach the declaration file

Chrome Notification Fix:

  • Visit: chrome://flags
  • Search: "notifications"
  • Set "Enable system notifications" to: Disabled
  • Relaunch browser

Chrome Extension Development (Manifest V3)

Basic Extension Structure

manifest.json:

{
  "manifest_version": 3,
  "name": "Sample Extension",
  "version": "1.0.0",
  "description": "Example extension description",
  "icons": {
    "32": "icon32.png",
    "48": "icon48.png",
    "128": "icon128.png"
  },
  "action": {
    "default_icon": {
      "16": "icon16.png",
      "32": "icon32.png"
    },
    "default_popup": "popup.html",
    "default_title": "Sample Extension"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "run_at": "document_end"
  }]
}

popup.html:


<html>
<head>
  <meta charset="UTF-8">
  <title>Sample Extension</title>
  <script src="popup.js"></script>
  <style>
    .container {
      width: 240px;
      height: 320px;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="container">
    <button id="actionBtn">Execute Action</button>
    <p id="output"></p>
  </div>
</body>
</html>

popup.js:

document.addEventListener('DOMContentLoaded', function() {
  const actionBtn = document.getElementById('actionBtn');
  const output = document.getElementById('output');
  
  actionBtn.addEventListener('click', () => {
    chrome.tabs.query({active: true, currentWindow: true}, tabs => {
      chrome.tabs.sendMessage(tabs[0].id, {type: "fetchData"}, response => {
        output.textContent = response?.data || "No response from content script";
      });
    });
  });
});

content.js:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.type === "fetchData") {
    sendResponse({
      data: `Document title from content script: ${document.title}`
    });
  }
});

Core Extension Mechanisms

Manifest Configuration

Essential manifest.json fields include manifest_version, name, version, action, content_scripts, permissions, and host_permissions.

Message Communication

Simple Message Passing:

// Sending message from content script
chrome.runtime.sendMessage({command: "process"}, function(response) {
  console.log(response.status);
});

// Receiving messages
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === "process") {
    sendResponse({status: "completed"});
  }
});

Long-lived Connections:

// Establishing connection
const port = chrome.runtime.connect({name: "dataChannel"});
port.postMessage({data: "sample data"});
port.onMessage.addListener(msg => {
  if (msg.query === "status") {
    port.postMessage({response: "active"});
  }
});

// Connection listener
chrome.runtime.onConnect.addListener(port => {
  port.onMessage.addListener(msg => {
    if (msg.data === "sample data") {
      port.postMessage({query: "status"});
    }
  });
});

Publishing and Distribution

  • Developer registration requires one-time $5 fee
  • Package extension as ZIP file
  • Upload via Chrome Web Store Developer Dashboard

Automatic Updates

manifest.json:

{
  "update_url": "https://example.com/extension/updates.xml"
}

updates.xml:

<?xml version="1.0" encoding="UTF-8"?>
<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
  <app appid="extensionid">
    <updatecheck codebase="https://example.com/extension/v2.crx" 
                 version="2.0" prodversionmin="106.0.5249.119"/>
  </app>
</gupdate>

Data Storage Options

chrome.storage API

manifest.json:

{
  "permissions": ["storage"]
}

Usage:

// Storing data
chrome.storage.local.set({userPref: value}, () => {
  console.log("Preference saved");
});

// Retrieving data
chrome.storage.local.get(["userPref"], result => {
  console.log("Current preference: " + result.userPref);
});

Cookie Management

manifest.json:

{
  "host_permissions": ["*://*.example.com/"],
  "permissions": ["cookies"]
}

Usage:

chrome.cookies.get({url: "https://example.com", name: "session"}, cookie => {
  console.log(cookie);
});

IndexedDB

const dbRequest = indexedDB.open("ExtensionDB", 1);
dbRequest.onsuccess = event => {
  const database = event.target.result;
};

Cross-Origin Requests

manifest.json:

{
  "host_permissions": [
    "https://*.api.com/",
    "http://*/"
  ]
}

Using fetch API:

fetch("https://api.example.com/data")
  .then(response => response.json())
  .then(data => console.log(data));

Extension Pages and Resources

// Opening extension page in new tab
chrome.tabs.create({url: chrome.runtime.getURL("dashboard.html")});

// Accessing extension resources
const resourceURL = chrome.runtime.getURL("images/icon.png");

Internationalization

manifest.json:

{
  "default_locale": "en"
}

messages.json:

{
  "extName": {
    "message": "Sample Extension",
    "description": "Extension name"
  }
}

Usage in JavaScript:

const extensionName = chrome.i18n.getMessage("extName");

Background Scripts

manifest.json:

{
  "background": {
    "service_worker": "background.js"
  }
}

background.js:

chrome.action.onClicked.addListener(tab => {
  chrome.tabs.create({url: "https://example.com"});
});

Options Page

manifest.json:

{
  "options_page": "options.html"
}

Content Security Policy

manifest.json:

{
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'none'"
  }
}

Other Browser Platforms

  • Edge: Submit to Microsoft Edge Add-ons store
  • Firefox: Submit to Mozilla Add-ons repository

Development Best Practices

  • Follow principle of least privilege for permissions
  • Use modern JavaScript modules in service workers
  • Implement proper error handling
  • Test across different browser versions

Tags: chrome-extension manifest-v3 content-scripts service-worker message-passing

Posted on Wed, 20 May 2026 06:38:45 +0000 by Ben Phelps