Firebase Analytics in a Manifest V3 Chrome Extension: Does It Work?
6 min readModerok team
Firebase Analytics in a Chrome extension: Firebase's own table marks it unsupported and the SDK reaches for window. The source lines, and the alternative.
No. Firebase Analytics does not work in a Manifest V3 Chrome extension, and no bundler setting fixes it. In Firebase's own supported-environments table, the Analytics row carries the not-supported marker in the Chrome Extensions column, where eight other products carry a checkmark (Firebase, as of September 2026), and the SDK's detection helper treats a browser extension as a mismatched environment (firebase-js-sdk, as of September 2026). Most other Firebase products do work in extensions. Analytics is not one of them.
TL;DR: Firebase's reference for
isSupported()says it "wraps four different checks", the first being "Check if it's not a browser extension environment" (Firebase, as of September 2026). ButgetAnalytics()does not call that helper: it reachesgetOrCreateDataLayer(), which indexeswindow, and the SDK's script loader callsdocument.head.appendChild(script)(helpers.ts, as of September 2026) with agoogletagmanager.comURL (constants.ts, as of September 2026). An MV3 service worker has neither, and Chrome bans the second outright (developer.chrome.com, as of September 2026). If you want extension lifecycle events without writing them, that is what Moderok is for.
The 30-second comparison
Every Firebase and Chrome cell below is what that page said when we opened it on 25 September 2026.
| Question | Firebase Analytics (web SDK) | Moderok |
|---|---|---|
| Listed as supported in Chrome extensions? | The Analytics row carries the not-supported marker in the "Chrome Extensions" column, as of September 2026 (supported environments) | Documented prerequisite is "A Manifest V3 extension (Chromium or Firefox 109+)" (getting started) |
| What the SDK reaches for at init | window[dataLayerName] and document.head.appendChild(script), as of September 2026 (helpers.ts) | chrome.storage.local (privacy) |
| Where the code comes from | The tag is fetched from GTAG_URL = 'https://www.googletagmanager.com/gtag/js', as of September 2026 (constants.ts) | npm install @moderok/sdk, or a copied dist/moderok.min.js (install) |
| How "extension" is detected | isBrowserExtension() returns typeof runtime === 'object' && runtime.id !== undefined, as of September 2026 (environment.ts) | Not applicable |
| Documented extension-specific entry point | firebase/auth/web-extension, for Authentication only, "supported on the Web SDK versions v10.8.0 and above", as of September 2026 (Chrome extension guide) | @moderok/sdk (install) |
| Install, update and daily-activity events without writing them | Not listed in the Analytics web setup guide, as of September 2026 (get started) | __install, __update, __first_open, __daily_ping, __error (events) |
Round 1What actually happens when you call getAnalytics()
The documented web setup is two imports and two calls (Firebase, as of September 2026):
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
Run that in an MV3 background service worker and two things go wrong, in this order.
First you get a warning. The analytics factory() opens with warnOnBrowserContextMismatch(), which pushes 'This is a browser extension environment.' onto a list and ends at logger.warn(err.message) (firebase-js-sdk, as of September 2026). Note what it does not do: it neither throws nor returns early. Initialization keeps going.
Then it breaks on a missing global. A few lines later factory() calls getOrCreateDataLayer(dataLayerName), which branches on if (Array.isArray(window[dataLayerName])) and assigns to window[dataLayerName] (firebase-js-sdk, as of September 2026). There is no window in a service worker, so that is a ReferenceError, not a graceful "analytics disabled".
The clean check exists, but you call it yourself. isSupported() is documented as wrapping "four different checks", the first "Check if it's not a browser extension environment" (Firebase, as of September 2026), and its implementation runs that check first (firebase-js-sdk, as of September 2026):
export async function isSupported(): Promise<boolean> {
if (isBrowserExtension()) {
return false;
}
...
isBrowserExtension() reads chrome.runtime (or browser.runtime) and returns typeof runtime === 'object' && runtime.id !== undefined (firebase-js-sdk, as of September 2026). chrome.runtime.id is defined in every extension context, popup and options page included, so moving the call into an extension page changes nothing.
Neither. Firebase Analytics in an extension is a warning followed by a crash, and the guard that would have said so cleanly is opt-in.
Round 2Why Firebase Analytics cannot run in a Chrome extension
Firebase Analytics on the web wraps the Google tag, and its loader says so in code. insertScriptTag() does document.createElement('script'), points it at `${GTAG_URL}?l=${dataLayerName}&id=${measurementId}`, and finishes with document.head.appendChild(script) (helpers.ts, as of September 2026). GTAG_URL is defined as 'https://www.googletagmanager.com/gtag/js' (constants.ts, as of September 2026).
That is a DOM insertion of a CDN-hosted script, and Chrome bans exactly that: "In Manifest V3, all of your extension's logic must be part of the extension package. You can no longer load and execute remotely hosted files according to Chrome Web Store policy", where "Any library hosted on a CDN" counts (developer.chrome.com, as of September 2026). Firebase describes the same wall: "Starting in Manifest V3, this isn't allowed and will be blocked by the extension platform" (Firebase, as of September 2026).
Chrome's policy. The platform rule came first and the SDK's environment warning followed it.
Round 3The rest of Firebase still works
"Firebase doesn't work in extensions" is wrong. In the Chrome Extensions column of the same table, as of September 2026, eight products carry a checkmark (Firebase AI Logic, Authentication, Cloud Firestore, Cloud Functions, Cloud Messaging, Cloud Storage, Realtime Database and Remote Config) and five carry the not-supported marker (Analytics, App Check, Firebase installations, Performance Monitoring and SQL Connect), with a note on Authentication reading "All Authentication features, except phone authentication and popup/redirect OAuth operations, are supported" (Firebase, as of September 2026).
Authentication even gets a dedicated entry point, firebase/auth/web-extension, which the guide says makes "signing in users from a Chrome extension similar to a web app" and is "only supported on the Web SDK versions v10.8.0 and above" (Firebase, as of September 2026). If you are already on Firebase for auth or Firestore, you keep that. You just cannot bolt Analytics onto it from inside the extension.
Firebase, for everything that is not Analytics.
Round 4The supported route, and what it costs you
Chrome's own how-to is unambiguous about the alternative: "Since Manifest V3, Chrome Extensions are not allowed to execute remote hosted code. This means you have to use the Google Analytics Measurement Protocol for tracking extension events" (developer.chrome.com, as of September 2026). That guide's manifest example asks for exactly "permissions": ["storage"], because you persist a client id yourself.
Note what that route is not: an SDK you install. It is HTTP you write and maintain, and you own the client id, the batching, the retry on a failed fetch, and a service worker that can be torn down mid-request. We walked that setup in GA4 Measurement Protocol in a Chrome extension.
Firebase, narrowly, if staying inside Google's analytics stack is a requirement. There is a documented path; it is just one you hand-build.
When Firebase is the right choice
If your extension is the small surface of a bigger product, Firebase is a good answer. Authentication, Cloud Firestore and Remote Config all carry a checkmark in that Chrome Extensions column (Firebase, as of September 2026), and if the meaningful user actions happen in your web app rather than in the extension, instrumenting the web app with Firebase Analytics is a defensible call. Firebase also wins when you need a backend and not just analytics. Moderok is not that: it has no database, auth or push, and running two vendors to avoid one is rarely worth it at small scale.
Where it stops working is when the extension is the product, and the numbers you care about are installs, updates, uninstalls, who opened it today, and which features get used.
Moderok's side of it
Moderok is built for the context Firebase Analytics excludes. Moderok.init() goes at the top level of the background service worker, before any await, so its install and update listeners "register on the first run" (init). It needs only the storage permission (manifest), has zero runtime dependencies, and its minified build measured 5,671 bytes gzipped on 2 August 2026. Installs, updates, first open, daily activity and uncaught errors are sent without you wiring them (automatic events). Custom events are yours to define:
import { Moderok } from "@moderok/sdk";
Moderok.init({ appKey: "mk_your_app_key" });
Moderok.track("feature_used", { theme: "dark" });
The roundup of Chrome extension analytics tools compares the wider field side by side.
Start with the getting started guide, or see what the dashboard shows on the product page.