Skip to content
HTMLCSSJavaScript

How to Create a Chrome Extension: Build It and Publish It

February 1, 2025 Updated September 29, 2026 7 min read

This guide on how to create a Chrome extension goes all the way to a published listing, not just to a working folder on your machine. Most of what you read about Chrome extension development stops at a working folder; the first part — the manifest, the popup, loading it locally — is the easy half. The part that stops people is the Chrome Web Store, so that gets the detail it deserves.

Everything here comes from shipping three of them: Convert Case, JSON Formatter+ and Image Finder.

What a Chrome extension actually is

A folder with a JSON file in it. That is genuinely all — HTML, CSS and JavaScript, plus a manifest.json that tells Chrome what the files are for. There is no build step, no framework and no compilation unless you choose to add one.

New extensions must use Manifest V3. Manifest V2 is gone, so any tutorial you find with "manifest_version": 2 in it will not load and every V2 answer on Stack Overflow is now wrong.

1. Set up the project

Code
my-extension/
├── manifest.json      ← the only required file
├── popup.html         ← what opens when the icon is clicked
├── popup.js
├── styles.css
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png

Those three icon sizes are not optional if you intend to publish. 16 is the toolbar, 48 is the extensions page, 128 is the Web Store listing, and the store rejects a submission missing the 128.

2. Write the Chrome extension manifest

This is the file that makes the folder an extension. A complete, working Manifest V3 file:

Code
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "description": "One clear sentence, under 132 characters.",

  "icons": {
    "16":  "icons/icon16.png",
    "48":  "icons/icon48.png",
    "128": "icons/icon128.png"
  },

  "action": {
    "default_popup": "popup.html",
    "default_title": "My Extension"
  },

  "permissions": ["storage", "activeTab"],

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

  "content_scripts": [
    {
      "matches": ["https://*/*"],
      "js": ["content.js"]
    }
  ]
}

Two fields decide how hard your review will be. permissions should be the shortest list that works — activeTab instead of tabs, and never <all_urls> if a narrower match will do. And description is what people read in the store, so write it for them, not for search.

3. Build the popup

Code
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <button id="go">Do the thing</button>
  <p id="result"></p>
  <script src="popup.js"></script>
</body>
</html>

Inline scripts are blocked by the content security policy in V3. An onclick attribute will not fire and the console will tell you why, so all behaviour goes in a separate file:

Code
// popup.js
document.getElementById('go').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.title,
  });

  document.getElementById('result').textContent = result;
});

The popup is a normal web page with one difference: it is destroyed the moment it closes. Nothing in a variable survives, so anything you need to keep goes in chrome.storage.

Code
await chrome.storage.sync.set({ theme: 'dark' });
const { theme } = await chrome.storage.sync.get('theme');

storage.sync follows the user across their signed-in Chrome installs; storage.local stays on the machine and holds more.

4. Load and test it locally

  1. Open chrome://extensions
  2. Turn on Developer mode, top right
  3. Click Load unpacked and choose your folder
  4. The extension appears, with any manifest error printed underneath it

After a code change, press the reload arrow on the extension’s card. Content scripts need the page reloaded too. Changing the manifest sometimes needs the extension removed and loaded again — if a change appears to do nothing, that is usually why.

5. Debug it

Each part of an extension has its own console, which is the single most confusing thing for people arriving from normal web development:

PartWhere its console is
PopupRight-click the popup → Inspect
Service workerchrome://extensions → your extension → “service worker”
Content scriptThe page’s own DevTools console
Options pageRight-click it → Inspect

A console.log in your service worker will never appear in the page’s console. People lose an afternoon to this.

6. Publish to the Chrome Web Store

This is where most guides stop and where the actual work starts.

The one-off fee

A developer account costs five US dollars, once, not per extension. It is paid at the Chrome Web Store Developer Dashboard and it is not refundable, so pay it when you are close to submitting rather than at the start.

What you have to have ready

  • A ZIP of the folder — zip the contents, not the folder itself, or the manifest ends up one level too deep and the upload is rejected
  • A 128×128 icon, and at least one 1280×800 screenshot
  • A description, and a short summary under 132 characters
  • A privacy policy URL, if your extension touches any user data at all
  • A justification for every permission, written in plain words

The privacy policy catches people out. It is required if you handle user data in any sense, and “any sense” is read broadly — which is why the three extensions above each have their own policy page. A page on your own site is enough; it does not need a lawyer, it needs to be honest about what the extension does and does not collect.

Review

Submission puts the extension in a review queue. Simple extensions with narrow permissions typically clear it quickly; anything asking for broad host access, reading page content, or handling personal data takes materially longer and is looked at by a person.

Plan for the wait. Do not promise anyone a launch date based on the day you submit.

Why extensions get rejected

  • Permissions you do not visibly use. The most common rejection by far. If the manifest asks for tabs and nothing in the code needs it, that is a rejection — remove it.
  • A description that does not match the behaviour. Reviewers install it and check.
  • Missing or unreachable privacy policy, when any data is handled.
  • Remote code. V3 forbids loading and running code from a URL. Everything executable ships inside the package.
  • Keyword stuffing in the listing. A description written for store search rather than for people.
  • Single-purpose rule. An extension that does several unrelated things is asked to become several extensions.

Common questions

Do I need a framework to make a Chrome extension?

No. Every Chrome extension tutorial that reaches for a framework first is making it harder than it is: plain HTML, CSS and JavaScript is the normal way to build an extension, and for anything small it is the better way — no build step means nothing to configure and nothing to go wrong between your code and what ships.

Can I develop a Chrome extension without publishing it?

Yes. Load unpacked works indefinitely on your own machine, and it is how you would share something with a small team. You only need the store for public distribution and automatic updates.

What is the difference between a content script and a service worker?

A content script runs inside the page and can read and change its DOM, but has limited access to extension APIs. A service worker runs in the background with full API access but cannot touch the page. They talk to each other with chrome.runtime.sendMessage, and knowing which one needs to do what is most of extension architecture.

Will this work in Edge, Brave or Opera?

Yes — they are all Chromium, and the same package runs in all of them. Firefox uses a compatible but not identical API under the browser namespace rather than chrome, so it needs small changes.

Views: 390

TheEasyMaster

Author at The Easy Master.

Previous
HTML Interview Questions and Answers (2025)
Next
React Native StyleSheet Cheat Sheet: Every Property You Use

Related posts

Browser DevTools Cheat Sheet: Chrome DevTools की Complete Hinglish Guide

The tutorial teaches it; the cheat sheet is for when you just need reminding.