Analytics built for browser extensions.

One ~3 KB SDK for installs, active users, and custom events — across Chrome, Firefox, Edge, VS Code and more. Zero dependencies. No user tracking.

npm install extstat · free for 10,000 events / month

Why extstat

Up and running in three steps

  1. Create a project in the dashboard and copy your API key.
  2. Install & init the SDK in your extension's background script.
  3. Track events — they appear in your dashboard within seconds.
import { init } from "extstat";

const analytics = init({
  apiKey: "esk_your_project_key",   // from your dashboard
  endpoint: "https://ingest.extstat.dev/v1/e",
});

analytics.track("install");
analytics.track("feature_used", { feature: "export" });

That's the whole integration. The SDK batches events, persists them offline, and retries on its own.

Show more — events, examples & opt-out

What the dashboard measures

  • install · update · uninstall — your lifecycle metrics: unique installs, updates, and uninstalls (counted per device). See the snippet below — uninstall is special, since your code can't run when the extension is removed.
  • sessionSessions: total engagement volume (counts every event, not unique devices).
  • Active users (DAU/WAU) & unique clients — automatic, and defined plainly: DAU = unique clients active in the last day, WAU = the last 7 days ("active" = sent any event). extstat assigns a random, persistent client id — no fingerprinting.
  • Total events — everything you send.
  • Custom events — any other name + properties. They still feed the active-user metrics and totals; name them whatever fits your extension.

Track the full lifecycle

// background.js — your MV3 service worker

// Installs & updates fire from the lifecycle hook:
chrome.runtime.onInstalled.addListener(({ reason }) => {
  if (reason === "install") analytics.track("install");
  else if (reason === "update") {
    analytics.track("update", { version: chrome.runtime.getManifest().version });
  }
});

// Uninstall is the one event you can't track() — your code is gone on removal.
// Point Chrome at the SDK's uninstall URL; it records the "uninstall" for you:
analytics.uninstallUrl().then((url) => {
  if (url) chrome.runtime.setUninstallURL(url);
});

// A session = your extension becoming active. Fire on startup (and/or popup open):
chrome.runtime.onStartup.addListener(() => analytics.track("session"));

Track your own events

// Fire your own events whenever something happens. Properties
// (a flat object) let you slice the event in the dashboard later.
analytics.track("export_completed", { format: "csv", rows: 128 });

button.addEventListener("click", () => {
  analytics.track("upgrade_clicked", { plan: "pro" });
});

Let users opt out

const analytics = init({
  apiKey: "esk_your_project_key",
  endpoint: "https://ingest.extstat.dev/v1/e",
  disabled: userOptedOut, // one-line opt-out (wire to a setting)
  // respectDoNotTrack defaults to true — sends nothing under DNT
});

Simple pricing

Free

$0/month

  • 10,000 events / month
  • Unlimited projects
  • All metrics & date ranges
  • Privacy features included
Get started

Pro

Unlimited events

  • Everything in Free
  • No monthly event cap
  • For extensions at scale
Upgrade in-app