Skip to content
More languages coming soon

Reference

Extension SDK reference ​

@analyticstrend/extension. Chromium and Firefox, one package.

initBackground(options) ​

Call at the top level of your background script, on every start. Returns a client immediately. Do not await it: Chrome will not run a service worker that uses top-level await, and the extension then sends nothing.

js
const analytics = initBackground({
  writeKey: "wk_...",
  uninstallTracking: true,
});
OptionTypeDefaultNotes
writeKeystringrequiredFrom your dashboard's Settings screen. Public by design.
endpointstringhttps://analyticstrend.comA collector other than AnalyticsTrend's own.
appVersionstringthe manifest's versionYour extension's version, for Versions. From 0.6.0 the manifest's is sent when you give none.
uninstallTrackingbooleanfalseRegisters the uninstall URL on every start. Required for correct behaviour on Firefox — see below.
onError(error) => voidnoneDiagnostic only. Never throws, never changes behaviour.
respectGlobalPrivacyControlbooleantrueWhile the browser sends Global Privacy Control, nothing is sent or stored. Set false only on a considered legal position. See below.
clearDataOnGlobalPrivacyControlbooleanfalseAlso delete the stored identifier and queue when the signal appears. Ignored when the signal is not respected.
consent() => boolean | Promise<boolean>noneYour extension's own on/off switch. Asked before every event and send; anything but true, an error or a rejected promise counts as off. See below.

Returns { track, flush, enabled, consentChanged }, synchronously. Its message listener is attached before the function returns, so an event from a content script that wakes a suspended background is not lost. Events are sent about five seconds after they are tracked, backing off while the collector is failing, and whatever is still queued is sent on the next background start.

Why uninstallTracking belongs here ​

Chrome remembers an uninstall URL across service-worker restarts; Firefox forgets it when the event page unloads. Registering from initBackground means it happens on every background start on both browsers, so the difference stops mattering. Registering from an onInstalled handler instead works on Chrome forever and stops working on Firefox within a minute.

Global Privacy Control ​

From 0.3.0, the SDK checks for Global Privacy Control before every event, alongside Firefox's data-collection consent, and sends nothing while it is present. It is best effort: the signal is meant for websites, and not every browser exposes it to an extension's background.

The identifier is created only once collection is allowed. The uninstall URL is cleared the moment collection stops being allowed, by the signal or by withdrawn consent, and registered again when it resumes. await client.enabled() resolves to whether anything is being counted. The two options work as they do in the web SDK.

Firefox's location toggle ​

From 0.4.0, if your manifest declares locationInfo as an optional data-collection permission and the person has turned it off, events are still sent, each batch marked location: false, and the collector works no country or region out of the request. The uninstall link carries the same choice. It is checked at every send, so a change of mind applies without a restart, and hasLocationConsent(api) tells you the current answer. An extension that does not declare it, and every Chrome extension, is unaffected. See the Firefox install guide for the manifest.

From 0.5.0, consent lets your extension's own setting decide, on any browser. Chrome has no built-in choice for analytics, so this is how an extension asks first there.

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

// After the person changes the setting:
analytics.consentChanged();

It is asked before every event and every send, alongside Firefox's consent and Global Privacy Control, and all of them have to allow it. While it says no, events are dropped rather than queued, no identifier is created, and the uninstall link is cleared. Anything but true, an error or a rejected promise counts as no. consentChanged() makes the uninstall link follow a change straight away; it sends nothing.

client.track(name, props?) ​

Queues an event. Returns a promise that resolves once the event is persisted.

js
analytics.track("session_saved", { itemCount: 12 });

Do not await this on a path a person is waiting on. Queue operations are serialised, so a track issued during a slow send waits for that send to finish. It is designed to be called and forgotten.

The name must match ^[a-z0-9_]{1,64}$. An invalid name is reported through onError and never enters the queue, so it cannot affect events queued beside it.

client.flush() ​

Sends everything queued. Always resolves, never rejects, even when the network is down — which is what makes it safe to call from a timer without a catch.

You rarely need it. initBackground flushes at startup, and the queue sends itself once it reaches 50 events.

trackFromContentScript(name, props?) ​

Sends an event from a content script or popup to the background context, which owns the queue.

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

Returns immediately and never throws. If no background listener is live — the service worker is still starting, or the extension is reloading — the event is dropped rather than queued, because a content script has nowhere durable to keep it.

enableUninstallTracking(options) ​

Registers the uninstall URL directly. Prefer uninstallTracking: true on initBackground.

js
enableUninstallTracking({ writeKey, anonymousId, endpoint });

If you do call it yourself, call it unconditionally on every background start, never inside onInstalled.

getBrowserApi() ​

Returns Firefox's browser namespace or Chromium's chrome, whichever exists. Throws with a clear message outside an extension context.

getOrCreateAnonymousId(api) ​

Reads the stored identifier, generating and persisting one on first call.

This is a check-then-act. Calling it concurrently from two contexts can generate two identifiers, of which one wins. Within normal use there is no race, because only initBackground calls it and a browser runs one background context at a time.

What the SDK guarantees ​

  • Nothing is lost to a teardown. Events are persisted before any send, so a suspended service worker mid-flush costs nothing.
  • Nothing is sent twice. Progress is recorded after every batch, so a restart resumes rather than replaying.
  • The queue is bounded. At 500 events the oldest are dropped, keeping the most recent behaviour rather than a stale prefix.
  • Retries back off. After a failed send the automatic retry waits 30 seconds, so an offline browser does not make one request per event.