- Chrome Web Store
- Analytics
- Competitors
Chrome Web Store stats API: how to get any extension's users, rating and version programmatically
There is no official Chrome Web Store stats API. What the store exposes, how to collect users, rating and version responsibly, and how to keep daily snapshots.
- Author
- Extenify Team
- Published
- Reading time
- 11 min read

On this page
"Is there a Chrome Web Store stats API?" usually means one of two things: a developer wants their own extension's numbers in a dashboard or a Slack message, or they want to follow a competitor's users and rating over time. The short answer is that Google does not offer a public stats API for either. The Chrome Web Store API is a publishing API, and the numbers you see on a listing page are not available from any documented endpoint.
That does not mean you are stuck. This guide maps every source of Chrome Web Store data that does exist, shows how precise each one is, and walks through a small, polite collector that reads users, rating and version from public listings and stores a daily snapshot in MongoDB. All code runs on Node.js 22 or later with no dependencies beyond the MongoDB driver.
Key takeaways
- There is no official Chrome Web Store stats API. The Chrome Web Store API (v2) uploads, publishes and reports review status for your own items, but returns no users, installs or ratings.
- Your own full stats (installs, uninstalls, weekly users, impressions) are in the Developer Dashboard, which exports every report as CSV.
- For any public extension, the listing page shows users, rating, rating count, version and last update. Large user counts are rounded and rating counts are abbreviated, so expect steps, not smooth curves.
- Google's terms forbid automated access that ignores robots.txt. The store's robots.txt allows
/detail/pages but disallows/searchand every listing's/reviewspath.- Firefox has a real public API. The addons.mozilla.org API returns average daily users and exact rating counts for any add-on.
Is there an official Chrome Web Store stats API?
No. The Chrome Web Store API "lets you programmatically publish and manage your Chrome Web Store items", and its v2 methods are exactly that: upload a package, publish, cancel a submission, set a deploy percentage and fetch status. The status response, documented under fetchStatus, contains the review state, the version and deploy percentage of each revision, and the takenDown and warned flags. It only works for items your account publishes. Our guide to Chrome Web Store review time shows how to use it to log review durations.
Here is everything that is actually available, and what each source can tell you:
| Source | Whose items | Users | Rating | Version | Official? |
|---|---|---|---|---|---|
| Developer Dashboard CSV exports | Yours | Weekly users, installs, uninstalls, impressions | No | Weekly users by version | Yes, manual export |
Chrome Web Store API v2 (fetchStatus) |
Yours | No | No | Yes, plus review state | Yes |
| Google Analytics 4 store integration | Yours | Listing views and installs as events | No | No | Yes |
| Public listing page | Any | Rounded user count | Average and abbreviated count | Version and update date | Public page, no API |
| Chrome's update service | Any | No | No | Latest served version and package size | Used by Chrome, undocumented for third parties |
| addons.mozilla.org API v5 | Any Firefox add-on | Average daily users | Exact average and count | Yes | Yes |
For your own extension, start with the dashboard exports and add your own telemetry. Our guides to measuring retention and uninstall rate and adding Google Analytics 4 to a Manifest V3 extension cover both. The rest of this post is about public data, which is the only way to watch anyone else's extension.
What the public listing shows, and how precise it is
Every listing at chromewebstore.google.com/detail/<id> shows the same handful of numbers. Here is what four of them showed on October 5, 2026:
| Extension | Users shown | Rating | Ratings shown | Version | Updated |
|---|---|---|---|---|---|
| AdBlock | 65,000,000 users | 4.5 | 290.3K | 6.47.0 | September 29, 2026 |
| uBlock Origin Lite | 21,000,000 users | 4.5 | 3.6K | 2026.930.1227 | September 30, 2026 |
| Dark Reader | 7,000,000 users | 4.7 | 13.2K | 4.9.133 | September 24, 2026 |
| A small extension | 79 users | 5 | 1 | 2.6.1 | October 4, 2026 |
Three things stand out, and they shape how you should use the data:
- User counts are rounded for large extensions. Small extensions show an exact number, large ones a round figure. When a developer asked about this in the Chromium Extensions group, the reply was that the count reflects weekly active users and moves in larger brackets as it grows. A big extension can gain or lose a lot of users without the public number changing at all.
- Rating counts are abbreviated. "13.2K ratings" hides up to a hundred ratings in the last digit. The average is shown to one decimal place, so a rating moves in visible steps of 0.1.
- The user count is weekly users, not installs. It can lag for weeks and can be hidden entirely when Google detects suspicious activity. Our guide to why Chrome extension weekly users drop explains what moves it.
So public data is excellent for trends, release tracking and rating changes, and coarse for exact user growth of large extensions. That is still far better than not tracking at all, because most of the useful signals are big changes: a new version, a rating that slips from 4.5 to 4.3, a rival that disappears.
Collect listing data responsibly
Before writing a collector, read the rules. Google's Terms of Service prohibit "using automated means to access content from any of our services in violation of the machine-readable instructions on our web pages (for example, robots.txt files that disallow crawling, training, or other activities)". The Chrome Web Store's robots.txt disallows /search, /detail/*/reviews, /detail/*/related and a few other paths, and allows the listing pages themselves.
In practice that means:
- Fetch listing pages only. Do not crawl search results or review pages.
- Fetch each item once a day. The numbers do not change faster than that in any way you can see, so more requests add load and no information.
- Identify yourself, space out requests and cache results. A descriptive User-Agent and a few seconds between items is enough for a list of dozens of extensions.
- Expect the markup to change. Nothing about the page structure is promised. Write the parser defensively and alert yourself when a field comes back empty, instead of silently storing nulls.
This parser reads the visible text of a listing rather than relying on class names, which change more often than the wording:
// cws-listing.mjs: read the public numbers from one Chrome Web Store listing.
// Usage: node cws-listing.mjs <extension-id>
const USER_AGENT = 'acme-listing-tracker/1.0 (+https://acme.example/bot)';
export async function fetchListing(id) {
// hl=en keeps number and date formats predictable.
const res = await fetch(`https://chromewebstore.google.com/detail/${id}?hl=en`, {
headers: { 'user-agent': USER_AGENT },
});
if (!res.ok) throw new Error(`HTTP ${res.status} for ${id}`);
return parseListing(await res.text());
}
export function parseListing(html) {
// A removed item still answers 200, with the generic store title.
const title = html.match(/<meta property="og:title" content="([^"]*)"/)?.[1] ?? '';
if (!title.endsWith(' - Chrome Web Store')) return { available: false };
// Visible text only: drop scripts, styles and tags, collapse whitespace.
const text = html
.replace(/<script[\s\S]*?<\/script>/g, ' ')
.replace(/<style[\s\S]*?<\/style>/g, ' ')
.replace(/<[^>]+>/g, ' ')
.replace(/&/g, '&')
.replace(/\s+/g, ' ');
const users = text.match(/([\d,]+) users?\b/)?.[1];
const rating = text.match(/([\d.]+) out of 5/)?.[1];
const ratingCount = text.match(/([\d.]+K?) ratings?\b/)?.[1];
const release = text.match(/Version (\S+) Updated ([A-Z][a-z]+ \d{1,2}, \d{4})/);
return {
available: true,
name: title.replace(/ - Chrome Web Store$/, ''),
users: users ? Number(users.replace(/,/g, '')) : null,
rating: rating ? Number(rating) : null,
ratingCount: ratingCount ?? null, // large counts come abbreviated, like "13.2K"
version: release?.[1] ?? null,
updated: release?.[2] ?? null,
};
}
if (process.argv[2]) console.log(await fetchListing(process.argv[2]));
Running it against Dark Reader returns:
{
available: true,
name: 'Dark Reader',
users: 7000000,
rating: 4.7,
ratingCount: '13.2K',
version: '4.9.133',
updated: 'September 24, 2026'
}
Two details in that code matter more than they look. The hl=en parameter fixes the language, because the page formats numbers and dates for the visitor's locale. And the available check exists because a removed extension does not return a 404. When we requested the original uBlock Origin, one of the Manifest V2 extensions removed from the store by August 31, 2026 according to the Manifest V2 timeline, the store answered 200 with a generic "Chrome Web Store" page. Without the check, a removed rival looks like an extension with no data, not one that is gone.
Get the latest version from the update service
If all you need is the version, there is a lighter source: the update service that Chrome itself calls to check for new versions. It returns a few hundred bytes of XML instead of a full page. It is not documented as a public API, so treat it like the listing page: once a day, per item, with a fallback.
// latest-version.mjs: ask Chrome's update service which version it serves.
export async function latestChromeVersion(id) {
const x = encodeURIComponent(`id=${id}&uc`);
const url =
'https://clients2.google.com/service/update2/crx' +
`?response=updatecheck&acceptformat=crx3&prodversion=141.0.0.0&x=${x}`;
const xml = await (await fetch(url)).text();
const check = xml.match(/<updatecheck\b[^>]*>/)?.[0] ?? '';
const status = check.match(/status="([^"]+)"/)?.[1];
if (status !== 'ok') return { status }; // "noupdate" when nothing is served
return {
status,
version: check.match(/version="([^"]+)"/)?.[1],
size: Number(check.match(/size="(\d+)"/)?.[1]),
};
}
For uBlock Origin Lite this returned { status: 'ok', version: '2026.930.1227', size: 9649043 }, matching the listing. For the removed uBlock Origin it returned { status: 'noupdate' }. The package size is a nice extra: a version whose size jumps by several megabytes usually means a new bundled library or a new feature worth a look.
Firefox has an official API
If you also publish on Firefox, you do not need any of the above there. The addons.mozilla.org API is public and documented. One request returns average_daily_users ("The average number of users for the add-on (updated daily)"), weekly_downloads, an exact rating average and count, and the current version:
curl -s https://addons.mozilla.org/api/v5/addons/addon/ublock-origin/ \
| jq '{users: .average_daily_users, rating: .ratings.average, ratings: .ratings.count, version: .current_version.version}'
On October 5, 2026, that returned 11,247,514 average daily users, a 4.80 average from 22,180 ratings, and version 1.75.0. Note that AMO counts daily users while Chrome shows weekly users, so the two numbers are not comparable. Compare each store's trend with itself, as our guide to tracking one extension across Chrome, Edge and Firefox explains.
Store daily snapshots and compute changes
Numbers are only useful as history. Store one document per item per day, keyed so that running the job twice on the same day overwrites instead of duplicating:
// snapshot.mjs: run once a day. Stores one document per item per day.
import { MongoClient } from 'mongodb';
import { fetchListing } from './cws-listing.mjs';
const ITEMS = ['eimadpbcbfnmbkopoojfekhnkhdbieeh', 'ddkjiahejlhfcafbddmgiahcphecmpfh'];
const client = new MongoClient(process.env.MONGODB_URI);
const snapshots = client.db('store_stats').collection('listing_snapshots');
await snapshots.createIndex({ store: 1, itemId: 1, day: 1 }, { unique: true });
const day = new Date().toISOString().slice(0, 10); // UTC calendar day
for (const itemId of ITEMS) {
try {
const listing = await fetchListing(itemId);
await snapshots.updateOne(
{ store: 'chrome', itemId, day },
{ $set: { ...listing, fetchedAt: new Date() } },
{ upsert: true },
);
} catch (error) {
console.error(`${itemId}: ${error.message}`); // keep going, retry tomorrow
}
await new Promise((resolve) => setTimeout(resolve, 5_000)); // be gentle
}
await client.close();
Then compare the two newest snapshots of each item and report what changed:
// changes.mjs: compare the two most recent snapshots of each item.
import { MongoClient } from 'mongodb';
const client = new MongoClient(process.env.MONGODB_URI);
const snapshots = client.db('store_stats').collection('listing_snapshots');
for (const itemId of await snapshots.distinct('itemId', { store: 'chrome' })) {
const [today, before] = await snapshots
.find({ store: 'chrome', itemId })
.sort({ day: -1 })
.limit(2)
.toArray();
if (!today || !before) continue;
if (before.available && !today.available) console.log(`${itemId}: listing is gone`);
if (today.version !== before.version) console.log(`${itemId}: ${before.version} -> ${today.version}`);
if (today.users !== before.users) console.log(`${itemId}: users ${before.users} -> ${today.users}`);
if (today.rating !== before.rating) console.log(`${itemId}: rating ${before.rating} -> ${today.rating}`);
}
await client.close();
The day string sorts correctly as text, the unique index makes reruns safe, and the compound index also serves the "latest two" query. Send the output to wherever your team already reads alerts. Our post on store change alerts your team will actually read has advice on which of these changes deserve a same-day ping and which belong in a weekly digest.
Once this runs for a few weeks, the usual extras follow: a chart per item, the same collector for Edge and Firefox, retries for days the page failed to parse, rank tracking for a few category pages, and a way to view it all without opening a database shell.
Or skip the scraper
If you would rather not maintain parsers for three stores, that is the job Extenify does. Paste any Chrome Web Store, Edge Add-ons or Firefox Add-ons URL into the Chrome Web Store stats dashboard and it records users, rating, reviews, version and category rank every day, merges the same extension across stores, and sends a daily alert to email, Slack, Telegram, Discord or Teams when something moves. It works for your own extensions and for competitors, because it only reads public listing data. Tracking one extension is free, and the pricing page shows the paid plans, which add more tracked extensions, longer history and CSV export.
Frequently asked questions
Is there an API to get a Chrome extension's user count?
Not an official one. The Chrome Web Store API only covers publishing and review status for your own items. Your own weekly users are in the Developer Dashboard, exportable as CSV. For any other extension, the public listing page is the source, and its user count is rounded for large extensions.
Is scraping the Chrome Web Store allowed?
Google's terms prohibit automated access that violates machine-readable instructions such as robots.txt. The store's robots.txt allows listing pages under /detail/ and disallows search, review pages and a few other paths. Fetching listing pages at a low rate stays within those instructions; crawling search or reviews does not.
Can I get Chrome Web Store reviews through an API?
No official API returns reviews, and the store's robots.txt disallows the /reviews path of every listing. The listing page shows the average rating and the rating count, which is enough to detect a rating change. For reading reviews, use the dashboard for your own items.
Why is the user count on the listing different from my dashboard?
The listing shows weekly users rounded into brackets, and it can lag behind the dashboard for weeks. The dashboard is the precise number for your own extension. Use the listing only to compare against other extensions or to watch for large changes.
How do I get my own extension's installs and uninstalls automatically?
There is no API for them. Export the Installs and Uninstalls report from the Developer Dashboard as CSV, or record install and uninstall events yourself with runtime.onInstalled and runtime.setUninstallURL.
Summary
There is no Chrome Web Store stats API, but there is enough data to work with. Use the Developer Dashboard and your own telemetry for exact numbers on your extension, the Chrome Web Store API for review state, the public listing for users, rating and version of any extension, Chrome's update service for a lightweight version check, and the addons.mozilla.org API for Firefox. Collect once a day, respect robots.txt, store a snapshot per item per day, and alert on the changes that matter: a new version, a rating step, a listing that disappears.
Image credits
- Cover photo: Wall-mounted network rack with a switch and router by Mohammed Kateregga on the WordPress Photo Directory, CC0.


