Skip to content
Reference 15 min read Recently updated

Browser Extensions Standards

Complete standards for building, testing, and shipping Chrome extensions in 2026 — Manifest V3, WXT framework, Chrome Web Store compliance, and privacy-first architecture.

chrome-extension manifest-v3 wxt svelte typescript cws privacy
← Back to resources
Shipping Checklist

Review & Shipping Checklist

0% complete · Saved in browser

In this post

Overview

This standard covers browser extension development — primarily Chrome extensions using Manifest V3. Extensions have unique constraints: strict permission models, content security policies, store review processes, and cross-version compatibility.

Prerequisites: General Standards (file structures, Git, a11y, privacy).

What this covers:

  • Chrome extensions (Manifest V3)
  • Cross-browser extensions (Chrome + Firefox + Edge)
  • Companion web dashboards (paired extensions)
  • Store listing optimization

Tech Stack (2026)

LayerPrimaryAlternative
FrameworkWXT + Svelte 5WXT + Preact for React developers
LanguageTypeScript 5.9 (strict)
StylingTailwind CSSShadow DOM + CSS (isolated UIs)
BuildWXT (Vite under the hood)Plasmo Framework
StateSvelte stores / Nanostores
Dashboard (paired web app)Next.js 16 + Prisma + Stripe
TestingVitest (unit) + Playwright (E2E with Chrome headless)

Why WXT over alternatives:

  • First-class Manifest V3 support
  • Auto-generated manifest.json from config
  • Built-in HMR for extension development (popup, options, content scripts)
  • Cross-browser builds from a single codebase
  • Active community and frequent updates

Why Svelte 5:

  • Minimal runtime overhead (adds ~2KB to extension bundle)
  • Runes-based reactivity eliminates complex state management for most use cases
  • Compiled output (no virtual DOM) — critical for performance-constrained extension environments

Project Scaffolding

File Structure (WXT + Svelte)

project-root/
├── src/
│   ├── entrypoints/
│   │   ├── popup/               # Extension popup UI
│   │   │   ├── App.svelte
│   │   │   ├── index.html
│   │   │   └── style.css
│   │   ├── options/             # Options/settings page
│   │   ├── background.ts        # Service worker (MV3)
│   │   ├── content.ts           # Content scripts (page injection)
│   │   └── sidepanel/           # Side panel (Chrome 114+)
│   ├── components/              # Shared UI components
│   ├── lib/
│   │   ├── api/                 # External API clients (Gmail, X, etc.)
│   │   ├── storage/             # Chrome storage wrapper with types
│   │   ├── utils/               # Pure utilities
│   │   └── types/               # TypeScript types
│   └── assets/                  # Icons, images
├── public/                      # Static assets (not processed by build)
├── wxt.config.ts                # WXT configuration
├── tsconfig.json
└── package.json

WXT Configuration Template

// wxt.config.ts
import { defineConfig } from 'wxt';

export default defineConfig({
  manifest: {
    name: 'My Extension',
    version: '0.1.0',
    description: 'Production-grade Chrome extension.',
    permissions: ['storage', 'identity'],
    host_permissions: ['https://api.example.com/*'],
    action: {
      default_popup: 'entrypoints/popup/index.html',
    },
  },
  vite: () => ({
    plugins: [],
  }),
});

Initial Setup Checklist

  • npm create wxt@latest with Svelte template
  • TypeScript strict mode
  • Tailwind CSS configured for WXT
  • Icon set created (16×16, 48×48, 128×128, optional 32×32)
  • manifest.json permissions minimized to strict necessity
  • Content security policy (CSP) reviewed
  • .env structure for API keys (if any)

Architecture & Design Patterns

Extension Architecture (Manifest V3)

Extension (WXT)
├── Service Worker (background.ts)
│   ├── Lifecycle: event-driven, terminates when idle
│   ├── Use: API proxying, alarms, messaging, state sync
│   ├── DON'T: DOM access, long-running computations
│   └── Persistence: chrome.storage.local/session (not global state)

├── Content Scripts (content.ts)
│   ├── Runs in page context (isolated world)
│   ├── Use: DOM manipulation, UI injection, page data extraction
│   ├── Messaging: chrome.runtime.sendMessage to service worker
│   └── Style: Shadow DOM to avoid conflicts with host page

├── Popup (popup/)
│   ├── Temporary UI (closes on focus loss)
│   ├── Keep lightweight — fetch heavy data from background
│   └── Max size: 600×600 recommendation

└── Options Page (options/)
    ├── Persistent settings interface
    ├── User preferences stored in chrome.storage.sync
    └── Accessible via right-click → Options or extension management

Communication Flow

Content Script → (chrome.runtime.sendMessage) → Service Worker

Service Worker → (chrome.runtime.sendMessage) → Popup/Options

Service Worker → (Fetch API) → External Server (if paired web app)

All communication is asynchronous. Use request/response patterns with unique IDs for tracking:

// content.ts
const response = await chrome.runtime.sendMessage({
  type: 'FETCH_LABELS',
  requestId: crypto.randomUUID(),
});

Permission Strategy

  • Minimum viable permissions — Start with zero, add only what’s proven necessary
  • Host permissions — Specific origins, not <all_urls> unless absolutely required
  • ActiveTab — Use instead of broad host permissions when interaction only needs the current tab
  • Storage — Use chrome.storage.local for large data, chrome.storage.sync for settings (limited to 100KB)
  • Optional permissions — Request at runtime, not install time, for sensitive capabilities

Performance Standards

Extension-Specific Targets

MetricTarget
Popup load time≤ 500ms (first paint)
Content script injection≤ 100ms after page load
Service worker wake time≤ 50ms
Background message latency≤ 20ms (same-process)
Bundle size (popup)≤ 100KB gzipped
Bundle size (content script)≤ 30KB gzipped

Optimization Tactics

  • Lazy content scripts — Use "run_at": "document_idle" to avoid blocking page load
  • Service worker warmup — Use chrome.alarms to keep the service worker alive when needed
  • Efficient messaging — Batch messages where possible; avoid per-element message passing
  • Minimal content script footprint — Inject only necessary DOM; prefer Shadow DOM for UI elements
  • Static assets — Bundle icons inline as base64 for popup to avoid extra network requests

Chrome Web Store Compliance

Submission Checklist

  • Privacy policy published at a public URL and linked in manifest
  • Permissions — each permission justified in the store listing
  • Data usage — clear disclosure of what data is collected and why
  • Single purpose — extension does one well-defined thing
  • Content security — no remote code execution (eval(), new Function())
  • Manifest V3 — MV2 is deprecated; all new submissions must be MV3
  • Icons — 16×16, 48×48, 128×128 (required), 32×32 (recommended)
  • Screenshots — 1280×800 or 640×400 minimum; show real functionality
  • Promotional tile — 440×280 small tile, optional 920×680 large tile
  • Description — clear, accurate, includes primary uses and limitations

Common Rejection Reasons

IssuePrevention
Insufficient permissions justificationIn the store description, explain why each permission is needed
No privacy policyPublish a privacy policy URL. Even if you collect nothing, state that.
Deceptive functionalityDon’t claim features the extension doesn’t perform
Low-quality UIFollow platform design patterns; test on multiple pages/sites
Broken on submissionTest on a clean Chrome profile before submitting

Review Timeline

  • Initial review: 1–3 business days (new extensions)
  • Updates: 1–2 business days
  • Expedited review: Available for critical fixes (limited use)
  • Appeals: 5–7 business days for policy violations

Review & Shipping Checklist

  • All permissions justified and minimized
  • Privacy policy published and linked in manifest
  • Content security policy (CSP) reviewed — no remote code execution
  • Service worker error handling: try/catch on all async operations
  • Storage schema versioned for future migrations
  • Icons created at all required sizes
  • Screenshots captured (1280×800 minimum)
  • Tested on a clean Chrome profile with no other extensions
  • Cross-browser tested (Chrome + Firefox + Edge if applicable)
  • Accessibility: popup navigable via keyboard, screen reader tested
  • Offline behavior handled gracefully
  • Error monitoring (if paired web app) configured
  • Store listing description written with SEO keywords

  • Manifest V3 maturity — Service worker limitations addressed via improved APIs
  • Side panel standard — Chrome 114+ side panel API enabling persistent UIs
  • AI-powered extensions — On-device AI (Chrome built-in AI API) for content analysis without server calls
  • Cross-browser standards — Manifest V3 converging across Chromium, Firefox, and Safari
  • Declarative Net Request — Replacing webRequest blocking for privacy and performance

Project Templates & Quick Starts

  • LabelKit — Reference: WXT + Svelte 5 + Gmail API extension
  • Xcelerate — Reference: Extension + Next.js 16 paired dashboard

References