Building Your First Chrome Extension

Chrome extensions are one of the lowest-friction ways to ship a real, useful tool — no app store approval wait, no backend required for a simple one, and you can build and load one locally in about ten minutes.

The Manifest: Every Extension’s Entry Point

{
  "manifest_version": 3,
  "name": "Word Counter",
  "version": "1.0",
  "description": "Counts words on the current page",
  "permissions": ["activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html"
  }
}

A Popup That Runs a Script on the Page

<!DOCTYPE html>
<html>
<body style="width: 200px; padding: 10px;">
  <button id="count">Count Words</button>
  <p id="result"></p>
  <script src="/popup.js"></script>
</body>
</html>
document.getElementById('count').addEventListener('click', async () => {
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

    const [{ result }] = await chrome.scripting.executeScript({
        target: { tabId: tab.id },
        func: () => document.body.innerText.split(/\s+/).length,
    });

    document.getElementById('result').textContent = <code>${result} words on this page</code>;
});

Loading It Locally for Testing

1. Go to chrome://extensions
2. Enable "Developer mode" (top right toggle)
3. Click "Load unpacked" and select your extension's folder
4. The extension icon appears in the toolbar immediately

Manifest V3’s Restrictions

Manifest V3 replaced persistent background pages with short-lived service workers and restricted remote code execution for security reasons — a source of real friction for extensions that relied on the old model, but a meaningful security improvement for users, since it closes off a class of extensions that quietly ran arbitrary fetched code.