Analytics for browser extensions
Installs are not usage.
The Chrome Web Store counts who took your extension. Extlytics shows who actually opens it, which features they reach for, and which version they are still on — with no IP address stored anywhere.
- 1.8 KB SDK, gzipped
- Zero dependencies
- MV3 native
Two things worth reading first
Every claim on this page has a receipt.
Not testimonials — Extlytics has no customers yet and will not invent any. These are the two published statements the product is built on top of.
Their own documentation
The Users stats only captures installations; it doesn’t monitor whether users are active or not.
A review rejection
Creating a worker using a blob URL violates the script-src policy we intend to apply to MV3 extensions.
Why this exists
Manifest V3 broke every analytics library you know.
MV3 forbids remotely-hosted code. That single rule breaks the mainstream analytics SDKs, because they load or generate code at runtime — and an extension carrying one is an extension that can be rejected, at review, on your timetable, under your listing.
No dynamic code. Provably.
No eval, no new Function, no blob:
worker, no remote URL — and no runtime dependency that might one day
introduce one. A build gate reads the emitted artifact and fails if any of
them appears.
1.8 KB, and it is a budget.
The SDK ships inside your product, so its weight is a cost your users pay. The size gate is set at 3 KB gzipped and the build fails above it — which is why it is still 1.8.
It cannot break your extension.
Every failure inside the SDK is swallowed. A bug we ship is a bug you fix by passing a fresh store review — so the SDK is written to be boring: frozen wire format, no dependency, every error caught.
How it works
Three lines in your service worker.
The SDK queues events in chrome.storage.local and flushes them
on chrome.alarms — so nothing is sent while your user is
waiting for anything, and a flush that fails is retried rather than lost.
It asks for storage and alarms, plus a host
permission for the ingest endpoint. Nothing else, and nothing a store
reviewer has to form an opinion about.
// Zero dependencies, 1.8 KB gzipped, no dynamic code.
import { extlytics } from '@extlytics/sdk';
extlytics.init({
key: 'wk_live_…',
version: chrome.runtime.getManifest().version,
// 'stateless' is the default: no identifier is
// stored, so there is no cohort to join.
mode: 'stateless',
});
// A feature somebody reached for — not a page view.
extlytics.track('session_restored');
-
1
Install and initialise
One import and one call, with your write key. No bundler configuration, because there is nothing to configure — the package has no dependencies.
-
2
Name the things you care about
A short event name and, optionally, the version it happened on. Not a page view — there are no pages. The unit is a feature somebody reached for.
-
3
Read the dashboard
The edge drops the IP, ingest samples and writes, an hourly job aggregates, and the dashboard reads the aggregates — never the raw events.
The boundary
No IP address is stored. Anywhere.
Not hashed, not truncated, not kept for ninety days and then dropped. The edge resolves a coarse country and discards the address before ingest ever sees it — so there is no column to leak, no table to subpoena and no retention policy to trust us on.
What arrives
Everything below is in the frozen wire format, and CI compares against it.
- The event names you chose, and when they happened
- Your extension’s version
- A coarse country, resolved at the edge and never the address it came from
- The sample rate every figure was computed at
That is the whole list. Ingest has no parameter that could carry an IP address — not an ignored one, not a nullable one. The column does not exist, so the promise is a shape rather than a policy.
What never arrives
At any setting. There is no switch for these, and no plan that adds one.
- IP addresses — discarded at the edge, stored nowhere
- Page URLs, page content, or anything read from a tab
- The other extensions installed alongside yours
- Cookies, fingerprints, or any cross-site identifier
stateless is the default and stores no identifier at all.
cohort — the mode that makes retention curves possible
— requires an affirmed lawful basis, and the database refuses the row
without one. It is a constraint, not a checkbox.
Enforced, not promised
Four things a build check refuses to let through.
Each of these is a promise that would be worth nothing as a sentence on a website. Each is a gate on every change, and each has been watched to fail — a gate nobody has seen fail is a wish.
| Gate | What it stops | Why it matters to you |
|---|---|---|
audit:bundle |
Dynamic code reaching the emitted artifact | The thing that gets a listing rejected at review |
audit:size |
The bundle growing past 3 KB gzipped | Weight inside your product is a cost your users pay |
test:contract |
A wire change that breaks already-shipped SDKs | Otherwise every customer owes a store review at once |
test:browser |
A shipped SDK that cannot actually send | The failure every mocked test in the world would miss |
Planned pricing
Two plans, neither of them on sale yet.
These are the plans as designed. Nothing here can be bought today, and the figures may move before launch — if they do, this page moves with them.
Free
Always$0
- 1,000 monthly active users
- 50,000 events a month
- 14 days of history
- Engagement, feature usage and version adoption
Enough to answer “does anybody open this?” for a real extension, rather than enough to see the shape of a dashboard.
Pro
Planned$9 / month
- 25,000 monthly active users
- 1,000,000 events a month
- 365 days of history
- Version comparison and deeper retention
The upgrade boundary is history and depth, not an event wall. Over budget, the sampler samples deterministically — it never rejects an event and it never bills you an overage you did not choose.
Worth saying plainly: nobody has been asked what this is worth yet. Willingness to pay is untested, the validation week was skipped by decision, and the question gets answered by the first real customer rather than by a survey. That is recorded here rather than hidden.
Where it stands
Built, tested, and waiting on the unglamorous part.
Extlytics is not a landing page in front of an idea. The pipeline runs end to end, and what is left between here and a sign-up form is configuration and one store account.
Core
- SDK, edge, ingest, rollups and retention
- Events, features, version adoption and tracking health
- All four CI gates green on every change
- The SDK driven inside a real MV3 extension in real Chrome
Paid path
- Plans, entitlements and the usage meter
- Licence activation, billing screen and webhooks
- Version comparison and feature-anchored retention
- Password reset, email verification and outbound mail
Before sign-up opens
- A real transactional mail provider wired in
- Billing credentials and the webhook signature confirmed
- A Chrome Web Store publisher account, and the example extension submitted
- A data-processing agreement, reviewed by somebody who is not us
Questions
The things you would ask before shipping our code.
When can I actually use it?
There is no date, because a date we could not keep would be the first thing this page got wrong. Leave your address below and you will hear once, when sign-up opens — not a newsletter.
Will this get my extension rejected?
The SDK contains no dynamic code of any kind, which is the rule that gets
analytics libraries rejected under MV3. It needs only storage
and alarms, plus a host permission for the ingest endpoint
— and the build refuses to emit an artifact that breaks the rule.
What happens if I go over the free limits?
The sampler starts sampling deterministically, and every figure on screen carries the rate it was computed at. Nothing is rejected, nothing is silently dropped, and no overage is billed to you.
Do my users have to consent to this?
In stateless mode — the default — no identifier is
stored, so there is no cohort and no profile. cohort mode,
which makes retention curves possible, requires you to affirm a lawful
basis, and the database refuses the configuration without one. What you owe
your own users is your call to make; the compliance disclosure the dashboard
generates is a pure function of the mode you chose.
Is the SDK open?
The service is proprietary, and the SDK carries an explicit redistribution grant — without one you could not legally ship the thing you are paying for. The wire format it speaks is frozen and published, and CI compares against it on every change.
Who is behind it?
WaaFaa — the same team behind the other extensions and tools on this site. Support is one address, answered by the person who wrote the code: waafaaofficial@gmail.com.
Hear about it once, when it opens.
One email when sign-up opens, and nothing else. No newsletter, no drip sequence, and the address is not passed to anybody — which would be a strange way to start, on this of all products.
Prefer to wait quietly? This page is the status page. It changes when the product does.