The reason from chrome.runtime.onInstalled.
OptionalpreviousVersion: stringVersion being upgraded from; Chrome supplies this only on an update.
A promise that resolves once the send settles.
// sends `extension_upgraded` with { app_version: "1.9.0", previous_version: "1.8.0" }
await trackInstallOrUpgrade(chrome.runtime.OnInstalledReason.UPDATE, "1.8.0");
export async function trackInstallOrUpgrade(
reason: `${chrome.runtime.OnInstalledReason}`,
previousVersion?: string,
): Promise<void> {
if (__IS_E2E_BUILD__) return;
const { INSTALL, UPDATE } = chrome.runtime.OnInstalledReason;
if (reason !== INSTALL && reason !== UPDATE) return;
// Reloading an unpacked extension fires onInstalled with reason "update" and
// previousVersion equal to the version already running. Reporting that would count
// every dev reload as an upgrade.
if (reason === UPDATE && previousVersion === __APP_VERSION__) return;
const params: Record<string, string | number> = { app_version: __APP_VERSION__ };
if (previousVersion) params.previous_version = previousVersion;
return trackEvent(reason === INSTALL ? 'extension_installed' : 'extension_upgraded', params);
}
Reports a fresh install as
extension_installedor a version change asextension_upgraded, the latter carrying both the old and new version. Driven by the service worker'schrome.runtime.onInstalledlistener.Only
INSTALLandUPDATEare reported —CHROME_UPDATEandSHARED_MODULE_UPDATEmean the browser changed, not ChemPal. AnUPDATEwhosepreviousVersionmatches the running version is a reload of an unpacked extension rather than a real upgrade, and is reported as nothing.Also a no-op under the e2e suite's build (
__IS_E2E_BUILD__). Every e2e run loads the extension into a fresh Chrome profile, soonInstalledfires for real with reasoninstall— unlike trackEvent's other callers, this one runs in the background service worker, whose requests the e2e suite's page-level route interception can't see or abort, so it would otherwise reach production PostHog.