Skip to content
More languages coming soon

Developers / Guide

Install in a Chrome extension ​

Using a framework?

There are guides for WXT, Plasmo and CRXJS, and a WXT starter template that is already measured.

For Chromium browsers: Chrome, Edge, Brave, Opera, Arc. Firefox has its own guide — the SDK is the same, but the manifest and the background lifecycle differ enough that following the wrong page produces a failure that does not explain itself.

1. Install the package ​

bash
npm install @analyticstrend/extension

Beta versioning

The API is settled enough to build on, but AnalyticsTrend is in beta and breaking changes will land in minor versions until 1.0.0. Pin an exact version if that matters to you.

2. Initialise in the background service worker ​

Manifest V3 runs your background code as a service worker that the browser suspends after roughly thirty seconds of inactivity and restarts on demand. Call initBackground at the top level of that file, so it runs on every start.

Do not await it

Chrome will not run a service worker that uses top-level await. The extension installs, the background never executes, and nothing is sent, with no error anywhere you would look. initBackground returns its client immediately for exactly this reason.

js
// background.js
import { initBackground } from "@analyticstrend/extension";

const analytics = initBackground({
  writeKey: "wk_your_key_here",
  uninstallTracking: true,
});

analytics.track("extension_started");

From @analyticstrend/extension 0.6.0 every batch carries your manifest's version, so Versions works with no more code.

Your write key is on the Settings screen of your dashboard. It is public by design and safe to ship inside your extension: it authorises writing events and nothing else. It cannot read your data.

3. Declare the permissions ​

json
{
  "manifest_version": 3,
  "background": { "service_worker": "background.js", "type": "module" },
  "permissions": ["storage"]
}

storage is the only permission the SDK needs: it is where the queue and the anonymous id live. No host_permissions entry is required to reach the collector, because the collector answers cross-origin requests itself. Leaving it out keeps the install prompt free of a "read and change your data" warning, which reviewers and users both notice.

4. Track from a popup or content script ​

Only the background context owns the durable queue. A popup or content script sends its event there instead:

js
import { trackFromContentScript } from "@analyticstrend/extension";

trackFromContentScript("popup_opened", { source: "toolbar" });

If the background is not running at that moment the event is dropped rather than queued, because a content script has nowhere durable to keep it. That is the right trade for a page you do not control, but it means content-script events are best-effort where background events are not.

Your own opt-in switch ​

Chrome has no built-in choice for analytics, so an extension that asks first keeps the answer itself. Pass it as consent, and call consentChanged() when the person changes it:

js
const analytics = initBackground({
  writeKey: "wk_your_key_here",
  uninstallTracking: true,
  consent: async () => (await chrome.storage.local.get("shareUsage")).shareUsage === true,
});

chrome.storage.onChanged.addListener((changes) => {
  if ("shareUsage" in changes) analytics.consentChanged();
});

While it says no, nothing is sent or stored and the uninstall link is cleared. The reference has the details.

What happens when the service worker is suspended ​

Nothing is lost. Events are written to chrome.storage.local before any send is attempted, so a teardown mid-flush leaves the queue intact and the next start drains it. Batches the server already accepted are never sent twice.

Limit which extensions can send events ​

Once it works, you can list your extension's IDs, so copies of it, or someone reusing your write key, do not count. Content-script events go through the background, so they carry your extension's ID too. See Limit which sites can send events.

Verify it ​

Load the extension unpacked, open it, then look at the Events screen in your dashboard. Events appear in the raw table immediately; the Overview totals update on the hourly rollup, so daily active users will lag by up to an hour on a brand-new project.