Chrome Extension Analytics Comparison: Moderok vs GA4 vs Umami vs PostHog
6 min readModerok team
A chrome extension analytics comparison of Moderok, the GA4 Measurement Protocol, Umami and PostHog, judged by what actually runs in an MV3 service worker.
Any useful chrome extension analytics comparison turns on one runtime: the Manifest V3 background service worker. Of these four, Moderok and PostHog are the two whose documentation describes running inside it. The GA4 Measurement Protocol is an HTTP endpoint with no client SDK, and its reference says "The api_secret is private. Don't expose it in the client-side code of your website or app" (Google, as of September 2026). Umami's npm package is documented for the server side (Umami, as of September 2026).
TL;DR: A service worker has no DOM, no
localStorage, and no remotely hosted code. Google documents the Measurement Protocol for "sending events from your server" and Umami's browser tracker is a page snippet (Google and Umami, both as of September 2026), so in an extension both reduce tofetch()calls you write. PostHog's extension guide prescribes memory persistence and a distinct id you store yourself (PostHog, as of September 2026). Moderok's SDK targets that runtime and instruments installs, updates, first opens, daily activity and errors without you wiring them.
The 30-second comparison
Every row is what that project's own documentation said when we opened it on 16 September 2026.
| Tool | What its docs say about getting data out of a background context | Source (as of September 2026) |
|---|---|---|
| Moderok | Install the package, add the storage permission, call Moderok.init() in your background entry point | docs.moderok.dev/guide/getting-started |
| GA4 Measurement Protocol | POST to www.google-analytics.com/mp/collect with measurement_id and api_secret query params, and a body carrying client_id plus an events array | developers.google.com |
| Umami (browser tracker) | "Copy the code and insert it into the <head> section of your website." | docs.umami.is/docs/collect-data |
| Umami (send API) | POST /api/send with payload.website, payload.name and a type; "you need to send a proper User-Agent HTTP header or your request won't be registered" | docs.umami.is/docs/api/sending-stats |
| PostHog | In service workers "localStorage and sessionStorage are not available", so use persistence: 'memory', disable_external_dependency_loading, and a bootstrap.distinctID read from chrome.storage | posthog.com/docs/advanced/browser-extension |
Round 1What installs at all
Chrome's Manifest V3 migration guide is blunt about the rule every page-oriented tool runs into: "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", and it names "any library hosted on a CDN" as prohibited (developer.chrome.com).
That rules out Umami's copy-paste path. Its documented browser install is a snippet in the <head> of a page, and the tracker's job once loaded is to read page context: the tracker functions reference describes umami.track() with no arguments as collecting hostname, language, referrer, screen dimensions, title and URL (Umami, as of September 2026). None of those exist in a service worker. Umami does publish an npm client, described on its own page as allowing you "to send data to Umami on the server side" (Umami, as of September 2026), not as an extension SDK. GA4 has no snippet problem here: the Measurement Protocol is documented for "sending events from your server", not as a client library (Google, as of September 2026).
PostHog does document an extension path, and is specific about what it costs: memory persistence in the worker, disable_external_dependency_loading: true so nothing is pulled from its CDN, and a connect-src entry in your manifest CSP (PostHog, as of September 2026). More on that trade in Moderok vs PostHog.
Moderok's SDK assumes the service worker is home. Moderok.init() is called from your background entry point, the package has zero runtime dependencies, and the minified build measured 5,671 bytes gzipped on 2 August 2026.
Moderok, with PostHog the only other tool that documents a way in.
Round 2Who supplies the user id
GA4's Measurement Protocol requires a client_id in every request body, described in the reference as matching the id generated by your site's Google Analytics tag (Google, as of September 2026). There is no tag in an extension, so you generate and persist that value yourself. The same page's warning about keeping api_secret out of client-side code is the sharper problem: an extension bundle is client-side code that anyone can unzip. The full setup and its limits are in GA4 Measurement Protocol in a Chrome extension.
Umami's send API lists payload.id as a session identifier among its payload fields, and the same page says the request needs "a proper User-Agent HTTP header or your request won't be registered" (Umami, as of September 2026). Know that second part before you build on it: you cannot set that header on the fetch() call itself, because MDN notes that although User-Agent is no longer a forbidden request header, "Chrome still silently drops the header from Fetch requests" (MDN).
PostHog hands the problem back explicitly: read a distinct id out of chrome.storage and pass it as bootstrap.distinctID in every context (PostHog, as of September 2026).
Moderok creates a random analytics profile id and persists it through chrome.storage. It may also recover that id through browser sync, so treat it as a profile rather than a per-device counter. There is no identify() call in the SDK, and custom event properties stay under your control, so anything sensitive you send is still yours to disclose.
Moderok. GA4 and PostHog both document an identifier you have to supply; Moderok's SDK creates and stores one.
Round 3The events an extension actually has
An extension's interesting moments are installs, updates, uninstalls, and whether anyone came back today. None are page views.
With GA4 or Umami you build each one: listen to chrome.runtime.onInstalled, define "daily active", write the request, handle the retry when the worker dies mid-flight. PostHog's extension guide covers persistence and identity across contexts rather than extension lifecycle events, so that wiring is still yours to author (PostHog, as of September 2026).
Moderok sends __install, __update, __first_open, __daily_ping and __error without a track() call (automatic events), and an opt-in trackUninstalls option sets the uninstall URL for you. Its queue is capped and debounced, and retryable failures are persisted and retried with backoff. That is not a guarantee of delivery, and nothing in a service worker can be.
Moderok.
Round 4Cost and where the data lives
PostHog's pricing page lists 1M events a month free for analytics, resetting monthly (PostHog, as of September 2026).
On running it yourself, the two projects say different things. Umami documents a self-hosted install needing "a server with Node.js version 18.18 or newer" and PostgreSQL v12.14 or newer (Umami, as of September 2026). PostHog's self-host page says "self-hosted deployments are officially unsupported" and that "we don't offer any sort of guarantees around it working in certain ways on your infrastructure, and you assume all responsibility and risk" (PostHog, as of September 2026).
Umami, for anyone whose real requirement is keeping the database on their own hardware.
When GA4, Umami, or PostHog is the right choice
GA4 is right when the extension is a satellite of a website already reporting into a GA4 property. Google documents the Measurement Protocol for "sending events from your server", with the api_secret caveat above (Google, as of September 2026); we compared the two in Moderok vs Google Analytics.
Umami is right when you want a small, privacy-minded stack on your own server and the extension is a minor part of it. A short /api/send wrapper is not much code, and the docs list an /api/batch endpoint taking an array of those requests (Umami, as of September 2026).
PostHog is right when you already run it for a web app and the extension is one surface among several. It publishes a browser extension guide (PostHog, as of September 2026), so you are not starting from a blank page.
Making this chrome extension analytics comparison for your own extension
Ignore feature lists and ask three questions. Does the documentation describe a background service worker, or only a page? Who creates and stores the user identifier? What happens to a queued event when Chrome kills the worker mid-request? Every difference above falls out of those three.
If the answers keep landing on "I would build that part myself", that is the part Moderok already built: start with the getting started guide, or look at what the dashboard shows. For the wider field, see the roundup of Chrome extension analytics tools.