# Chrome Web Store Scraper — Extensions, Reviews & Ideas (`oswaldocarabano/chrome-web-store-scraper`) Actor

Scrape the Chrome Web Store: extensions with users, rating, version, last update, launch date, permissions and developer; reviews with developer replies; developers; and category snapshots with an opportunity score to find extension ideas. No login. Errors never charged.

- **URL**: https://apify.com/oswaldocarabano/chrome-web-store-scraper.md
- **Developed by:** [Oswaldo Carabano](https://apify.com/oswaldocarabano) (community)
- **Categories:** Developer tools, E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 extension profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Chrome Web Store Scraper — Extensions, Reviews & Extension Ideas

Extract **Chrome Web Store extensions** with their full profile — users, rating, number of ratings, version, **last update**, **first publication date**, size, languages, **permissions**, **data the developer declares it collects**, in-app purchases, Featured and established-publisher badges, the developer and their EU trader status — plus **reviews** with the developer's reply, **developers** with all their extensions found, and a **category snapshot with an opportunity score** to spot extension ideas worth building.

No login, no account, no API key, no browser. Duplicate rows, removed extensions and error rows are **never charged**.

> This actor is not affiliated with, endorsed by, or connected to Google or the Chrome Web Store. It reads public data only.

### What you get

| Output type | One row per | Highlights |
|---|---|---|
| `extensions` (default) | extension in the categories or searches you choose | Users, rating, ratings count, version, last update, **first published**, days since update, **abandoned** flag (2+ years), size, languages, minimum Chrome version, manifest version, **API and host permissions**, all-sites access, **declared data collection**, in-app purchases, Featured / established publisher, developer, trader status, website, support and privacy links, screenshots, related extensions |
| `extension-details` | link or id you paste | The same full profile for specific extensions |
| `reviews` | review | Stars, text, date, edited flag, helpful and unhelpful votes, extension version used, language, **developer reply** and its date. Filter by stars and language, most recent or most helpful first |
| `category-snapshot` | category or search | Total and median users, median rating, **share rated under 4 stars**, **share not updated in 2 years**, launches in the last 12 months, Manifest V2 share, in-app-purchase share, top 10 extensions, **opportunity gaps** and the **opportunity score** |
| `developers` | developer | Extensions found in the run, total users, weighted rating, categories, Featured and abandoned counts, website, public business contact (EU-declared traders only) |

### Find extension ideas

- **Popular but disliked:** `maxRating: 3.5`, `minUsers: 50000` — an opening for a better product.
- **Abandoned with real users:** `abandonedOnly: true`, `minUsers: 10000` — users stuck with an unmaintained tool.
- **Still on Manifest V2:** filter the `manifestVersion` column — extensions that need a rebuild.
- **What users complain about:** `outputType: reviews`, `reviewsStars: ["1", "2"]` on the leaders of a category.
- **Which categories are open:** `outputType: category-snapshot` on several categories and compare `opportunityScore`.

### Opportunity score

Each `category-snapshot` row carries `opportunityScore` (0–100), computed only from the extensions in that snapshot, with a published, deterministic formula (same input → same score):

- **40% demand** = log10(1 + total users) / 9, capped at 1 (a category with a billion users scores 1)
- **25% dissatisfaction** = share of rated extensions under 4 stars
- **20% staleness** = share not updated in more than 730 days
- **15% openness** = 1 / (1 + N / 50), where N is the real size of the category or search when the store tells it (`populationCount`, with `opennessBasis: "category"`): the number of results the store reports for a **search**, or every extension when the listing ran out. The store gives no total for a **category**, so for categories larger than the sample (and for filtered snapshots) N is the sample size (`opennessBasis: "sample"`)

`opportunityComponents` gives the four parts. **Compare category scores at the same `snapshotSampleSize`:** demand is summed over the sample, and for categories openness is too (0.333 with the default 100), so it only separates small categories and searches. Measured on 17 Oct 2026: the store's result count for a search was within 1–4% of the distinct results it actually returns (pdf 462 vs 446, notion 477 vs 472, crm 629 vs 623). Over the 18 categories with the default sample of 100 (store order): scores from 36.1 (Household) to 57.2 (Workflow & Planning). `opportunityGaps` lists up to 10 extensions with 10,000+ users that are rated under 4 stars (with 20+ ratings) or abandoned. It is arithmetic on public data, not a prediction.

### Filters

- **Categories** (the 18 extension categories) and **search texts** (the store returns up to about 400–780 results per search: pdf 427, email 751, ai 773)
- **Category order:** recommended (store default), popular, highest rated
- **Users**, **rating** and **number of ratings** ranges, **Featured only**, **established publishers only** — checked on the listing, so skipped extensions cost nothing
- **Updated after / before**, **abandoned only**, **EU traders only** — checked on each profile (also when picking extensions for reviews); a run checks up to 25 profiles per requested row (at least 300) and the status message says when it stops
- **Reviews:** stars, language, written since, most recent or most helpful, max per extension

Pasting extension links with the default output type runs `extension-details` for exactly those; filters are not applied to pasted links (the log and the run summary say so, as for any option that has no effect).

### Data quality, measured

Measured on 17 Oct 2026 over **50,000 extensions** of all 18 categories in one run on the Apify platform (about 3,400 per category, all of the smaller ones; "filled" = not null and not empty):

| Extension field | Filled |
|---|---|
| Version, last update, first published, size, languages, manifest version, minimum Chrome version, badges | 99–100% |
| Users | 96.5% |
| Rating · ratings count (extensions nobody rated have none) | 65.2% |
| Screenshots · privacy policy · support site · website | 99.1% · 60% · 37.4% · 31.2% |
| API permissions · content-script sites · host permissions | 81.7% · 61.6% · 55.8% |
| Declared data categories (empty = declares none) | 27.9% |
| Developer name · legal name | 88.4% · 20.2% |
| Public business email / phone (EU traders, 11.2% of extensions) | 11.1% / 11.1% |

Extension rows had **44.1 filled fields on average** (of 58). Popular extensions are filled better than the long tail: on the top of each category, ratings reach about 98%.

Reviews (1,876 in 50 test runs): text, stars, dates, votes and language 100%; reviewer name 99.8%; extension version 96.4%; developer reply 5.4%.

Default input `{}`: 20 extensions in 2–4 seconds (measured on 17 Oct 2026, 4 runs on the Apify platform, 512 MB).

Speed, read live: the 50,000-extension run took 1 h 54 min (about 7 profiles per second, 7% from the cache, peak memory 266 MB). Reviews are faster: 1,000 in about 7 seconds.

In 50 test runs on the Apify platform (17 Oct 2026, all output types, filters, links, edge cases and a spending cap) **50 of 50 succeeded**, with charges equal to rows delivered in every run and 0 duplicates.

### How it compares

Compared with the other Chrome Web Store actors in the Apify Store, as declared in their own dataset schemas (17 Oct 2026):

| | This actor | Typical alternatives |
|---|---|---|
| Fields per extension | 59 | 9–31 |
| Extension + reviews + developers + category summary in one actor | Yes | Usually one of them |
| First published date, abandoned flag, declared data collection, in-app purchases | Yes | Not in their schemas |
| Reviews filtered by stars and language, with developer reply | Yes | Some |
| Opportunity score per category | Yes | No |
| Price per extension profile | $1.00 per 1,000 | free to $5.00 per 1,000; those with 20+ fields: $3.00–$5.00 |
| Error rows and removed extensions charged | Never | Varies |

### Pricing

Pay per event:

- **Extension profile:** $0.001 ($1.00 per 1,000)
- **Review:** $0.0001 ($0.10 per 1,000)
- **Category snapshot:** $0.005 per category or search
- **Developer:** $0.001
- **Actor start:** $0.00001

Error rows, duplicates within a run and removed extensions are never charged. Set a maximum cost per run and the actor stops cleanly when it is reached.

### Input example

```json
{
  "outputType": "extensions",
  "categories": ["productivity/workflow"],
  "sortBy": "popular",
  "minUsers": 10000,
  "maxRating": 3.8,
  "maxItems": 100
}
```

### FAQ

**How fresh is the data?** By default a profile that any run of this actor fetched in the last 24 hours is reused from a shared cache (`maxCacheAgeHours`); those rows carry `cachedAt` and cost the same. In our 50 test runs, which repeated many inputs, 66% of extension rows came from the cache; in the 50,000-extension run, 7%. Set `maxCacheAgeHours` to 0 to read every profile live. The store itself refreshes users and ratings about once a day.

**Is "users" the number of installs?** It is the number the store shows (weekly active users as counted by Google), rounded by the store for large extensions.

**Why do developer emails appear only for some extensions?** By default you get the business contact (email, phone, address, D-U-N-S) that the store shows for developers who declared themselves traders under EU law. The store also shows an email for many other developers, some of whom are private individuals: their email and phone are returned only if you turn on `includeNonTraderContacts` (off by default), and their postal address never is.

**Do you return reviewer photos or emails?** No. Only the public display name, the review and the developer's reply; contact details inside texts are removed.

**What happens with a removed extension?** You get one `extension-not-found` row explaining it, not charged.

**Can I get the whole catalog?** Run every category with a high `maxItems`; the largest category returned 7,284 different extensions. Duplicates across categories are removed within a run.

**Support:** open an issue on the actor page.

# Actor input Schema

## `outputType` (type: `string`):

One row type per run. <b>extensions</b>: full profile of every extension in the categories or searches below (users, rating, version, last update, first publish date, size, permissions, data-collection disclosures, developer). <b>extension-details</b>: the same profile for the links or ids you paste. <b>reviews</b>: user reviews of the pasted extensions, or of the top extensions of the categories/searches. <b>category-snapshot</b>: one summary row per category or search, with the opportunity score. <b>developers</b>: one row per developer found, with their extensions and total users. Pasting links with "extensions" switches to extension-details.

## `categories` (type: `array`):

Chrome Web Store extension categories. Empty, with no search and no links, runs productivity/tools (left empty on purpose: a preselected category would be added to your searches). The largest category returned 7,284 different extensions (17 Oct 2026).

## `searchQueries` (type: `array`):

Keywords as typed in the store search box, for example "email tracker". The store returns up to about 400–780 results per search (measured: pdf 427, email 751, ai 773). Letters, digits, spaces and basic punctuation only.

## `extensionUrls` (type: `array`):

Chrome Web Store pages, for example https://chromewebstore.google.com/detail/grammarly/kbfnbcaeplbcioakkpcpgfkobkghlhen, old chrome.google.com/webstore links, or just the 32-letter id. Only the id is read. Entries that are not store links get one error row that is not charged; removed extensions get an "extension-not-found" row, also free.

## `maxItems` (type: `integer`):

Rows delivered (and charged) at most. Duplicates, removed items and error rows are never charged. Empty = 20 extensions; with pasted links, every link; with reviews, links × reviews per extension; with snapshots, one per category or search.

## `sortBy` (type: `string`):

Order of the category listing, as on the store. Search results always keep the store relevance order.

## `minUsers` (type: `integer`):

Only extensions with at least this many users. Checked on the listing, before the profile is requested, so skipped extensions cost nothing.

## `maxUsers` (type: `integer`):

Only extensions with at most this many users (find small, growing niches).

## `minRating` (type: `number`):

Average stars, 0–5. Extensions without ratings never match.

## `maxRating` (type: `number`):

For example 3.5 finds popular extensions that users dislike (an opening for a better product).

## `minRatingCount` (type: `integer`):

Only extensions with at least this many ratings.

## `updatedAfter` (type: `string`):

Date like 2026-01-01.

## `updatedBefore` (type: `string`):

Date like 2024-01-01: extensions nobody maintains.

## `abandonedOnly` (type: `boolean`):

Not updated in more than 2 years (730 days).

## `featuredOnly` (type: `boolean`):

Extensions with the store's Featured badge (follows recommended practices).

## `establishedPublisherOnly` (type: `boolean`):

Publishers with the store's "good record with no history of violations" badge.

## `traderOnly` (type: `boolean`):

Developers who declared themselves traders under EU law (businesses, with public contact details).

## `includeDeveloperContacts` (type: `boolean`):

Email, phone, address and D-U-N-S that the store shows for developers declared as EU traders. Developers who did not declare themselves traders may be individuals: their contact details are never returned.

## `includeNonTraderContacts` (type: `boolean`):

Off by default. The store also shows an email (and sometimes a phone) for developers who did NOT declare themselves EU traders; some of them are private individuals. Turn this on only if you have a lawful reason to process that contact data. Their postal address is never returned.

## `maxReviewsPerExtension` (type: `integer`):

For outputType reviews.

## `reviewsSort` (type: `string`):

Most recent or most helpful first.

## `reviewsStars` (type: `array`):

For example \[1, 2] for complaints. Empty = all.

## `reviewsLanguage` (type: `string`):

Language code such as en, es, de or pt-BR. Empty = every language.

## `reviewsSince` (type: `string`):

Date like 2026-01-01. With "Most recent" the run stops paging at that date.

## `snapshotSampleSize` (type: `integer`):

For outputType category-snapshot: how many extensions of each category or search (in listing order) the snapshot summarizes.

## `maxCacheAgeHours` (type: `integer`):

An extension profile fetched by any run of this actor in the last N hours is reused from a shared cache (default 24; such rows carry cachedAt and cost the same). The store updates users and ratings about once a day. 0 = every profile is read live.

## `maxConcurrency` (type: `integer`):

Requests in flight at once. 8 delivered 20 profiles in about 1.5 s in tests.

## Actor input object example

```json
{
  "outputType": "extensions",
  "maxItems": 20,
  "sortBy": "recommended",
  "abandonedOnly": false,
  "featuredOnly": false,
  "establishedPublisherOnly": false,
  "traderOnly": false,
  "includeDeveloperContacts": true,
  "includeNonTraderContacts": false,
  "maxReviewsPerExtension": 100,
  "reviewsSort": "recent",
  "snapshotSampleSize": 100,
  "maxCacheAgeHours": 24,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `results` (type: `string`):

The rows of this run: extensions, reviews, category snapshots or developers, depending on the outputType you chose.

## `errors` (type: `string`):

Every error of the run with its reason and what to do. Always present, empty when nothing failed.

## `summary` (type: `string`):

Counts of delivered, charged, duplicate, filtered and error rows for this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("oswaldocarabano/chrome-web-store-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "maxItems": 20 }

# Run the Actor and wait for it to finish
run = client.actor("oswaldocarabano/chrome-web-store-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxItems": 20
}' |
apify call oswaldocarabano/chrome-web-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,oswaldocarabano/chrome-web-store-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/KvFJ2FaRX3iO2Kfdd/builds/irSARyzqffNKmDCNl/openapi.json
