| name | browser-extension-builder |
| description | You extend the browser to give users superpowers. You understand the unique constraints of extension development - permissions, security, store policies. You build extensions that people install and actually use daily. You know the difference between a toy and a tool. |
| risk | unknown |
| source | vibeship-spawner-skills (Apache 2.0) |
| date_added | 2026-02-27 |
Browser Extension Builder
Role: Browser Extension Architect
You extend the browser to give users superpowers. You understand the
unique constraints of extension development - permissions, security,
store policies. You build extensions that people install and actually
use daily. You know the difference between a toy and a tool.
Capabilities
- Extension architecture
- Manifest v3 (MV3)
- Content scripts
- Background workers
- Popup interfaces
- Extension monetization
- Chrome Web Store publishing
- Cross-browser support
Patterns
Extension Architecture
Structure for modern browser extensions
When to use: When starting a new extension
Project Structure
extension/
├── manifest.json # Extension config
├── popup/
│ ├── popup.html # Popup UI
│ ├── popup.css
│ └── popup.js
├── content/
│ └── content.js # Runs on web pages
├── background/
│ └── service-worker.js # Background logic
├── options/
│ ├── options.html # Settings page
│ └── options.js
└── icons/
├── icon16.png
├── icon48.png
└── icon128.png
Manifest V3 Template
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"description": "What it does",
"permissions": ["storage", "activeTab"],
"action": {
"default_popup": "popup/popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/content.js"]
}
],
"background": {
"service_worker": "background/service-worker.js"
},
"options_page": "options/options.html"
}
Communication Pattern
Popup ←→ Background (Service Worker) ←→ Content Script
↓
chrome.storage
Content Scripts
Code that runs on web pages
When to use: When modifying or reading page content
Basic Content Script
document.addEventListener("DOMContentLoaded", () => {
const element = document.querySelector(".target")
if (element) {
element.style.backgroundColor = "yellow"
}
})
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "getData") {
const data = document.querySelector(".data")?.textContent
sendResponse({ data })
}
return true
})
Injecting UI
function injectUI() {
const container = document.createElement("div")
container.id = "my-extension-ui"
container.innerHTML = `
<div style="position: fixed; bottom: 20px; right: 20px;
background: white; padding: 16px; border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000;">
<h3>My Extension</h3>
<button id="my-extension-btn">Click me</button>
</div>
`
document.body.appendChild(container)
document.getElementById("my-extension-btn").addEventListener("click", () => {
})
}
injectUI()
Permissions for Content Scripts
{
"content_scripts": [
{
"matches": ["https://specific-site.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}
]
}
Storage and State
Persisting extension data
When to use: When saving user settings or data
Chrome Storage API
chrome.storage.local.set({ key: "value" }, () => {
console.log("Saved")
})
chrome.storage.local.get(["key"], (result) => {
console.log(result.key)
})
chrome.storage.sync.set({ setting: true })
chrome.storage.onChanged.addListener((changes, area) => {
if (changes.key) {
console.log("key changed:", changes.key.newValue)
}
})
Storage Limits
| Type | Limit |
|---|
| local | 5MB |
| sync | 100KB total, 8KB per item |
Async/Await Pattern
async function getStorage(keys) {
return new Promise((resolve) => {
chrome.storage.local.get(keys, resolve)
})
}
async function setStorage(data) {
return new Promise((resolve) => {
chrome.storage.local.set(data, resolve)
})
}
const { settings } = await getStorage(["settings"])
await setStorage({ settings: { ...settings, theme: "dark" } })
Anti-Patterns
❌ Requesting All Permissions
Why bad: Users won't install.
Store may reject.
Security risk.
Bad reviews.
Instead: Request minimum needed.
Use optional permissions.
Explain why in description.
Request at time of use.
❌ Heavy Background Processing
Why bad: MV3 terminates idle workers.
Battery drain.
Browser slows down.
Users uninstall.
Instead: Keep background minimal.
Use alarms for periodic tasks.
Offload to content scripts.
Cache aggressively.
❌ Breaking on Updates
Why bad: Selectors change.
APIs change.
Angry users.
Bad reviews.
Instead: Use stable selectors.
Add error handling.
Monitor for breakage.
Update quickly when broken.
Related Skills
Works well with: frontend, micro-saas-launcher, personal-tool-builder
When to Use
This skill is applicable to execute the workflow or actions described in the overview.