Firefox
Firefox distribution goes through addons.mozilla.org (AMO). The kit builds a Firefox-specific package from the same codebase, with the Chromium-only permissions and APIs filtered out.
Build and package
Section titled “Build and package”pnpm build:firefoxpnpm zip:firefoxbuild:firefox is the local test build, zip:firefox the AMO upload
zips.
Load a test build via about:debugging → This Firefox → Load Temporary
Add-on. The add-on’s ID is browser_specific_settings.gecko.id in
wxt.config.ts, and it is permanent once AMO has it. The setup wizard
replaces the kit’s own (extension@extensionstart.com, which every
clone would share and AMO would refuse) with a unique one, a GUID in
braces. Change it to the name@your-domain form before your first
upload if you prefer, never after.
What is different in the Firefox build (handled per-browser in
wxt.config.ts):
- Permissions are filtered to
storageandidentity;offscreenandsidePaneldon’t exist on Firefox and AMO lint rejects unknown permissions. - On the Firebase stack, no offscreen document means Google sign-in on
Firefox requires
WXT_GOOGLE_OAUTH_CLIENT_ID(the web-auth-flow path; see Sign-in). - Chrome-only APIs are guarded in code (
browser.sidePanel?.…). strict_min_versionis 140 (142 on Android), the first Firefox with built-in data consent (below).
Data collection
Section titled “Data collection”Since November 3, 2025, AMO requires every new add-on to declare what it
sends off the device, in Firefox’s own data types; Firefox shows the
list at install. The kit declares it in wxt.config.ts
(browser_specific_settings.gecko.data_collection_permissions):
| Data type | Kind | Why |
|---|---|---|
personallyIdentifyingInfo | required | the account’s email (and name), when the user signs in |
authenticationInfo | required | the sign-in itself: credentials and tokens go to Firebase or Supabase Auth |
technicalAndInteraction | optional | billing only: the paywall’s usage record (POST /gate/events) |
Firefox lets the user decline an optional type at install, and
technicalAndInteraction can only be optional. A Firefox user who
declines it sends no usage events (entrypoints/background/usage-events.ts
asks the browser first); the paywall’s local counters work either way.
Update the list when your product sends more: page text to an AI
service is websiteContent, visited URLs browsingActivity, and so on
(the data types).
Data a feature keeps only on the device (chrome.storage) needs none.
An add-on that sends nothing at all declares required: ["none"].
Upload source code with the zip
Section titled “Upload source code with the zip”AMO reviews are human and stricter than CWS about build pipelines. Because the code is bundled and minified, you must upload the source code alongside the extension zip, plus instructions that reproduce the build.
pnpm zip:firefox produces both zips in apps/extension/.output/:
the extension package and a -sources.zip with the source tree. Upload
the sources zip when the AMO flow asks “Do you need to submit source
code?” → Yes.
Reviewer notes template
Section titled “Reviewer notes template”Paste into “Notes for Reviewers” and adjust versions. On Supabase, write Supabase where it says Firebase, and the PKCE flow for the implicit flow:
This extension is built from the included sources with WXT (Vite).
Build environment:- Node 22.12 or newer, pnpm 12 (the exact version is pinned in the packageManager field of package.json; pnpm 11 or newer switches to it on its own)
Reproduce the build:1. unzip the sources2. pnpm install --frozen-lockfile3. pnpm zip:firefox4. compare .output/*-firefox.zip with the submitted package
Notes:- No remote code: all executed JS ships in the bundle. Remote requests fetch JSON data only (announcements, prices, plan state) from our own Firebase backend.- Minification is Vite's default minifier (Oxc); no obfuscation.- Sign-in uses browser.identity.launchWebAuthFlow with Firebase Auth (OAuth implicit flow; no client secret in the bundle).If you kept billing: add one line saying premium features require a subscription and include a test account (email/password sign-in is the easiest to hand a reviewer).
AMO-specific gotchas
Section titled “AMO-specific gotchas”- Versions are immutable: you can’t replace an uploaded version. Fix and bump.
- CI already runs AMO’s linter (
addons-linter) against the Firefox build, so lint-class surprises surface before you submit. - AMO asks for a privacy policy whenever data leaves the machine (auth qualifies); reuse the privacy disclosures content.
- Updates auto-publish after review; there is no staged rollout on AMO.