Privacy-first · cross-browser
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
Why extstat
Everything you need, nothing you don’t.
Drop-in analytics that respect your users and your bundle — purpose-built for the extension ecosystem.
Cross-store, one SDK
Chrome, Firefox, and Edge (MV3), plus VS Code and Figma. Write once; measure everywhere.
Tiny & zero-dependency
~2.9 KB, no dependencies, and safe inside an MV3 service worker. Bundle size is a feature.
Privacy-first by design
No personal data, no cookies, no fingerprinting. Honors Do Not Track and a one-line opt-out.
The metrics that matter
Installs, Daily and weekly active users — the unique people who open your extension each day and week., unique clients, and your own events — filterable by date range.
Up and running in three steps
- Create a project in the dashboard and copy your API key.
- Install & init the SDK in your extension's background script.
- 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
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.session— Sessions: 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
Pro
Unlimited events
- Everything in Free
- No monthly event cap
- For extensions at scale
- Priority support