Chrome Extension Uninstall Rate: What Is Normal and How to Measure It
7 min readModerok team
How to define a Chrome extension uninstall rate that means something, from picking the denominator to cohorting by install date and measuring it yourself.
Google does not publish a benchmark Chrome extension uninstall rate, and the Chrome Web Store dashboard does not compute one: it reports installs and uninstalls as two separate daily counts and leaves the division to you. The rate stays undefined until somebody names a denominator, so a percentage quoted without one tells you nothing about your extension. Define it for yourself and measure it the same way every week. The tempting version, today's uninstalls divided by today's installs, is the one that misleads.
TL;DR: Chrome Web Store gives you two daily flows, installs and uninstalls, and no rate. Same-day uninstalls divided by same-day installs moves with your growth rate, not with user satisfaction. The rate worth tracking is cohorted: of the users who installed in a given week, what fraction removed the extension within N days. The store's retention view groups users by country, language, OS and item version, not by install date, so install-date cohorts are something you attach yourself with
chrome.runtime.setUninstallURL.
Why there is no normal Chrome extension uninstall rate
Chrome's metrics documentation describes the two numbers in two bullets: "Track acquisition using the daily install report." and "Monitor user churn using the daily uninstalls analytics." The figures include "new and returning users" and can be filtered by country, language, operating system or time period (Analyze your store listing metrics, Chrome for Developers, as of September 2026). When Google reorganized the dashboard, it says, the old Stats tab was split "into 3 separate pages" for installs and uninstalls, impressions, and weekly users (Revamping Analytics in the Chrome Web Store Developer Dashboard).
There is a retention view, but it groups users by attributes rather than by when they arrived. The metrics page says: "You can monitor weekly user retention for different groups of users, categorized by country, language, operating system, and item version." It is not an install-date cohort, and the install and uninstall reports themselves are plain daily counts with no ratio attached. Any uninstall rate you quote is one you constructed.
Three different things people call an uninstall rate
| Definition | Formula | What it actually tracks |
|---|---|---|
| Same-day ratio | uninstalls on day d / installs on day d | Your growth rate more than your retention |
| Cohort rate | uninstalls from the users who installed in window W, within N days / size of W | Retention of one acquisition vintage |
| Base churn | uninstalls in a period / installed base at the start of the period | How fast your existing base erodes |
The same-day ratio is the one the dashboard tempts you into, since both numbers live on the same Installs and Uninstalls page. Its problem holds by definition: the uninstalls recorded on a day can only come from people who installed on or before it, the entire existing base, while the denominator counts only that day's arrivals. If installs are climbing fast, the denominator inflates and the ratio flatters you. If installs go flat after a promotion ends, unchanged retention suddenly reads as a spike. A number that moves when your marketing changes and holds still when your product changes is not a product metric.
The cohort rate answers the question you actually have: are the people arriving this week sticking around? Base churn is for forecasting, and needs an installed-base estimate the store does not give you. Weekly Users is the closest thing on the dashboard, with the caveat Chrome states outright: "The Users stats only captures installations; it doesn't monitor whether users are active or not." Why Installs and Weekly Users refuse to reconcile is its own post.
How to measure your Chrome extension uninstall rate
You can export "all the reports described below as CSV files" from the dashboard, which is enough for the same-day ratio and a rough base churn. It is not enough for an install-date cohort rate. The dimensions Chrome documents for slicing these reports are country, language, operating system and time period, plus item version on the retention view; install date is not among them. The uninstall report tells you how many removals happened on a date, not whether they came from yesterday's installs or last March's.
Cohorting therefore requires a signal you own. Chrome gives you one hook: chrome.runtime.setUninstallURL, a URL the browser visits after the extension is removed. The constraints are documented: "Maximum 1023 characters" and "This URL must have an http: or https: scheme" (chrome.runtime). The URL is the only thing you control, so everything you want to know has to be in its query string at the moment you set it.
The URL is fixed when you set it, so a tenure value written at install time still says zero days when the user leaves six months later. Tenure has to be refreshed. This needs "storage" in your manifest permissions, since it leans on chrome.storage.local:
chrome.runtime.onInstalled.addListener(async ({ reason }) => {
if (reason === "install") {
await chrome.storage.local.set({ installedAt: Date.now() });
}
await refreshUninstallUrl();
});
chrome.runtime.onStartup.addListener(refreshUninstallUrl);
async function refreshUninstallUrl() {
const { installedAt } = await chrome.storage.local.get("installedAt");
const url = new URL("https://example.com/uninstalled");
url.searchParams.set("version", chrome.runtime.getManifest().version);
// Users who installed before this shipped have no stored date: label them.
url.searchParams.set(
"tenure",
installedAt ? String(Math.floor((Date.now() - installedAt) / 86_400_000)) : "unknown",
);
const href = url.toString();
if (href.length > 1023) {
console.warn("[uninstall] URL exceeds 1023 chars, not set", href.length);
return;
}
try {
await chrome.runtime.setUninstallURL(href);
} catch (err) {
console.warn("[uninstall] setUninstallURL rejected", err);
}
}
Two details there do real work. The installedAt fallback: users already on your extension never fired onInstalled with reason install under this code, so they have no stored install date, ever. Returning early for them would stop any uninstall ping for your whole pre-existing base. Tenure cohorts start with the release that ships this; everyone older sits in one unknown bucket. The second is that both failure branches log. A length check that trips on a first run registers no URL at all, and one that trips later leaves the previous run's URL reporting stale values. Chrome's docs note the promise "will be rejected" for an invalid URL, and a rejection inside a listener goes nowhere uncaught.
onStartup fires when a profile with the extension installed first starts up, which means a browser that stays open for days does not refresh, whatever the machine does. For day-level resolution, drive the refresh from a chrome.alarms alarm instead (add "alarms" to permissions too), which survives the MV3 service worker being torn down the way setInterval does not (how to run periodic tasks in MV3).
The uninstall rate you measure is a floor
Whatever you compute, treat it as a lower bound. Chrome's API reference documents the URL requirements, not the cases where the URL is never visited, so reason from the mechanism: the signal is a page load the browser performs on your behalf after a removal. Anything that makes the extension disappear without that page load leaves no record, whether a removal that takes the browser or profile with it, or a machine offline at that moment. The mechanics, and the Firefox differences, are in tracking uninstalls with setUninstallURL.
Observed uninstalls and real churn are therefore different quantities. Pair the uninstall signal with an activity signal: an installation that reported activity daily for a month and has been silent for two weeks has churned in every sense that matters, ping or no ping. A daily heartbeat event gives you that second view; the two together bracket the truth.
What to do with the number once you have it
Cohorted by tenure, the shape tells you where to look first. Departures clustered in the first day or two send you to audit the install moment: what the listing promises against what the extension does on first run, what the permission prompt asks for, whether onboarding dead-ends. Departures spread evenly across long tenures send you to the roadmap instead. Neither shape proves a cause; they point at different investigations. The absolute percentage means little in isolation; the same percentage, measured the same way before and after a change, is what supports a decision.
Moderok records an __install event when Chrome fires onInstalled with reason install, and with trackUninstalls: true it sets the uninstall URL for you and ties the removal back to the same anonymous profile id, which is the join you would otherwise build by hand. The configuration and its limits, including the same 1023-character ceiling, are in the uninstall tracking docs; the product overview covers what else lands on the dashboard alongside uninstalls and net churn.