# Chrome Web Store Scraper — Extensions, Users & Permissions (`kilndata/chrome-web-store-scraper`) Actor

Scrape Chrome Web Store extensions and themes by category, keyword or URL: users, rating, ratings count, category, version, last update, size, languages, manifest permissions and host access, trader (business) developer details, links. No login, no browser.

- **URL**: https://apify.com/kilndata/chrome-web-store-scraper.md
- **Developed by:** [Datakiln](https://apify.com/kilndata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 extension listings

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, users, ratings and permissions

Give it a category, a keyword or a list of extension URLs and it returns one record per extension or theme from the Chrome Web Store: name, number of users, average rating, rating count, category, version, last update, package size, languages, the permissions the extension asks for, and the developer's business details when the developer has published them.

No browser, no login, no API key. The store's public listing pages embed their data as JSON, and this actor reads that.

- **Permissions included.** API permissions, host permissions, optional permissions and the sites where the extension injects content scripts, taken from the public manifest data on the listing.
- **Three ways to pick extensions.** By category, by keyword in the extension's name, or by URL or 32-letter ID.
- **You pay only for records you receive.** Failed pages, pages skipped by robots.txt and invalid input are saved with a status, and never charged.
- **Stops at your spending limit.** Set a max cost per run and the actor stops when it is reached.
- **No personal data collected.** No reviews, no reviewer names, no user accounts.

This actor is independent. It is not affiliated with, endorsed by or sponsored by Google.

### Who is it for?

| Use | How |
|---|---|
| Extension developers | Track competitors in your category: users, rating, last update, version, permissions requested |
| Agencies and consultants | Build lists of extensions and their business developers for outreach or market reports |
| Security and compliance teams | Audit which extensions ask for `<all_urls>`, `cookies`, `tabs` or `webRequest`, and where content scripts run |
| Market research | Compare categories by user counts, rating counts and how recently extensions were updated |
| Monitoring | Run on a schedule and compare `version`, `updatedAt` and `permissions` between runs to spot changes |

### How it works

1. **Category.** The actor opens the store's category page and loads further pages through the store's own "load more" data call, 32 items at a time, until it has `maxResults` extensions.
2. **Keyword.** The store's `/search` page is disallowed for robots in its robots.txt, so the actor does not use it. It reads the store's official sitemap instead (about 370,000 items, 30 to 60 seconds) and keeps every extension whose URL name contains all your words. This is a name match, not the store's search ranking. See the limits below.
3. **URL or ID.** The listing page of each extension is fetched directly.
4. **Each listing page** is read once and turned into one flat record. Pages are fetched at a limited rate (120 per minute by default, 5 at a time), and the actor pauses all requests if the store answers with HTTP 429.

An extension found through more than one source is scraped, and charged, once.

### Input

Provide at least one of `categories`, `searchTerms` or `startUrls`.

| Field | Type | Default | Meaning |
|---|---|---|---|
| `categories` | list of text | empty (prefill: `productivity/developer`) | Category slugs, names or category URLs, for example `productivity/workflow`, `lifestyle/shopping`, `make_chrome_yours/privacy`, `themes`. Extensions come in the store's own order; the position is saved in `sourcePosition` |
| `searchTerms` | list of text | empty | Keywords such as `pdf` or `password manager`. An extension matches when its store URL name contains every word. Adds 30 to 60 seconds to the run |
| `startUrls` | list of text | empty | Extension or theme URLs (old `chrome.google.com/webstore` links work too), bare 32-letter IDs, or category URLs |
| `maxResults` | integer, 1 to 10,000 | 50 | Extensions to scrape for each category or search term. URLs and IDs you give directly are always scraped |
| `respectRobotsTxt` | boolean | true | Skip pages the store's robots.txt disallows. Skipped pages are not charged |
| `maxConcurrency` | integer, 1 to 20 | 5 | Pages fetched in parallel |
| `maxRequestsPerMinute` | integer, 10 to 600 | 120 | Upper limit of page requests per minute |
| `requestTimeoutSecs` | integer, 5 to 120 | 30 | How long to wait for a page before retrying |
| `maxRetries` | integer, 0 to 5 | 2 | Retries per page. An extension that still fails is listed with status `failed` and is not charged |
| `proxyConfiguration` | object | no proxy | Optional. The store works without a proxy. Turn on Apify Proxy only if you see many failed pages |

Example input:

```json
{
    "categories": ["productivity/developer"],
    "searchTerms": ["password manager"],
    "startUrls": [
        "https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh",
        "efaidnbmnnnibpcajpcglclefindmkaj"
    ],
    "maxResults": 50
}
```

### Output

One dataset item per extension (shortened; lists are cut). This one comes from a keyword run on `password manager`:

```json
{
    "type": "extension",
    "status": "ok",
    "id": "phlcnojkfolacibkjkfbkdhignoeicmo",
    "url": "https://chromewebstore.google.com/detail/phlcnojkfolacibkjkfbkdhignoeicmo",
    "name": "IDX Password Manager",
    "itemType": "Extension",
    "rating": null,
    "ratingCount": 0,
    "users": 161,
    "featured": false,
    "category": "productivity/workflow",
    "categoryName": "Workflow & Planning",
    "version": "6.0.1",
    "updatedAt": "2024-05-16T08:56:42.000Z",
    "createdAt": "2021-09-30T17:00:16.000Z",
    "size": "26.22MiB",
    "languages": ["English (United States)"],
    "developerName": "IDX",
    "developerIsTrader": true,
    "developerCountry": "US",
    "supportUrl": "https://www.idx.us/knowledge-center/faq",
    "privacyPolicyUrl": "https://www.idx.us/privacy",
    "manifestVersion": 3,
    "permissions": ["tabs", "activeTab", "storage", "notifications"],
    "hostPermissions": ["http://*/*", "https://*/*"],
    "contentScriptMatches": ["http://*/*", "https://*/*"],
    "minChromeVersion": "102.0",
    "foundVia": "search:password manager",
    "sourcePosition": 5,
    "scrapedAt": "2026-10-05T03:59:00.265Z"
}
```

The full record also has the summary, full description, icon, screenshots, promo video, `homepageUrl`, `optionalPermissions`, `relatedExtensions` (IDs), `developerLegalName` and `developerDuns`. The field list is in the dataset schema. The dataset has two ready-made views in the Console: Overview and Permissions.

Notes on specific fields:

- **`users`** is the figure the store shows, which the store rounds for large extensions (for example 21,000,000).
- **`developerName`, `developerLegalName`, `developerDuns`, `developerCountry`** are filled only when the developer declared itself a trader (a business) in the store, as EU rules require. Otherwise they are `null` and `developerIsTrader` is `false`. A developer who is a sole trader may have a person's name as legal name; handle that field with the care your local law requires.
- **`status`** is `ok`, `failed`, `skipped` or `invalid-input`. Only `ok` items are charged. `error` says why the others were not scraped.

### How much does it cost?

You pay per extension listing returned (event `extension-listing`), plus a tiny start fee per run. The pricing tab of the actor shows the current numbers.

| Apify plan | Price per 1,000 extension listings |
|---|---|
| Free | $3.00 |
| Starter (Bronze) | $2.50 |
| Scale (Silver) | $2.20 |
| Business (Gold) | $2.00 |

Actor Start: $0.00005 per run.

Examples, at the Free plan price:

| Run | Listings returned | Cost |
|---|---|---|
| Top 50 of one category | 50 | $0.15 |
| 3 categories, 200 each | 600 | $1.80 |
| 1,000 extensions by ID | 1,000 | $3.00 |
| Whole category of 5,000 | 5,000 | $15.00 |

At the Business (Gold) price the last row costs $10.00.

What is not charged: pages that fail after all retries, pages skipped by robots.txt, invalid input, extensions that no longer exist. A keyword search that matches nothing costs nothing either (apart from the start fee).

**Spending limit.** Set **Max cost per run** when you start the actor. The actor checks how many listings your limit still allows before it saves each one, and stops when the limit is reached. You never pay for more than you set.

### Limits you should know about

- **The store's HTML can change.** The actor reads data embedded in the listing page. If Google changes that format, fields can come back empty or whole pages can fail until the actor is updated. Failed pages are not charged.
- **Removed extensions.** An extension taken down from the store has no listing. It comes back as `failed` with the message that it may have been removed or the ID is wrong.
- **Keyword search is a name match.** It finds extensions whose store URL name contains your words. It does not search descriptions and does not follow the store's own ranking. An extension called "Clipper" will not show up for "pdf" even if it saves PDFs. Results are sorted with whole-word matches first, then shorter names. Sort by `users` afterwards if you want the biggest ones.
- **Category listing versus ID list.** A category run returns what the store lists in that category, in the store's order, up to `maxResults`. If you already know the extensions you care about, a list of IDs is faster, more predictable and cheaper, because no listing pages are loaded.
- **No reviews.** The store's reviews pages are disallowed for robots, so the actor only returns the average rating and the rating count.
- **Rounded user counts.** The store does not show exact numbers.
- **Some pages are skipped on purpose.** The privacy, support, related and report subpages are disallowed by robots.txt and are not fetched. The links to them are saved as plain URLs.
- **Large category runs are slow on purpose.** The default pace is 120 pages a minute. A run of 5,000 extensions takes well over 40 minutes.
- **Language.** Pages are requested in English (`hl=en`), so names, category names and descriptions come back in English where the developer supplied one.

### Terms of use and responsible use

The actor reads only public pages that the store shows to anyone without a login. It collects no reviews, reviewer names or user accounts. It identifies itself as a normal browser, checks robots.txt before every request (you can turn that off, but it is on by default), limits its speed, and backs off when the store answers 429.

That does not settle whether you may use the data. The Chrome Web Store has its own terms of service, and Google's terms may restrict automated access or reuse of store content. You are responsible for using the data in line with the store's terms and with the law where you live. If you are unsure, read the terms or ask a lawyer before you build a product or a mailing list on this data. Keep your run sizes and schedules reasonable.

### Integrations

Start it from the Apify Console, the API, schedules or webhooks, or from an AI agent through the Apify MCP server. Export the dataset as JSON, CSV, Excel or XML, or send it to Google Sheets, Make, Zapier or n8n through the standard Apify integrations.

### FAQ

**Does it need a Google account or an API key?** No. It reads public listing pages.

**Can I get the reviews text?** No. The store disallows robots on its reviews pages, and the actor does not collect reviewer names. You get the average rating and the number of ratings.

**Why did I get `developerName: null`?** The developer has not declared itself as a trader in the store. Many individual developers have not. The store shows no business details for them, so the actor has none to return.

**Why does a keyword search take a minute before anything happens?** The actor first reads the store's sitemap to find matching names. It does this once per run, whatever the number of keywords.

**Does a failed page cost me money?** No. Only records with status `ok` are charged. You can filter on `status` in the dataset.

**Can it track an extension over time?** Yes, in practice: schedule a run on a list of IDs and compare `version`, `updatedAt`, `users` and `permissions` between runs.

**Can it scrape Firefox, Edge or Opera add-ons?** No, only the Chrome Web Store.

### Feature requests and problems

Use the **Issues** tab of this actor in the Apify Store. For a problem, include the input you used and the run link, and say which fields were wrong or empty. For a new field or a new way to select extensions, say what you need it for. Reports like this are the fastest way to get a fix.

This actor is not affiliated with Google or the Chrome Web Store.

# Actor input Schema

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

Category slugs, names or URLs: productivity/workflow, productivity/developer, productivity/tools, productivity/education, productivity/communication, lifestyle/shopping, lifestyle/entertainment, lifestyle/games, lifestyle/social, lifestyle/news, lifestyle/travel, lifestyle/art, lifestyle/fun, lifestyle/household, lifestyle/well_being, make_chrome_yours/privacy, make_chrome_yours/accessibility, make_chrome_yours/functionality, themes. Extensions come in the store's own category order (position saved in "sourcePosition").

## `searchTerms` (type: `array`):

Keywords such as "pdf" or "password manager". An extension matches when its store URL name contains every word. Runs over the store's official sitemap (~370,000 items, adds 30–60 s to the run), so results are a name match, not Chrome Web Store search ranking. Sort by "users" afterwards.

## `startUrls` (type: `array`):

Extension or theme URLs (https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh, old chrome.google.com/webstore links work too), bare 32-letter IDs, or category URLs.

## `maxResults` (type: `integer`):

How many extensions to scrape for each category or search term. URLs and IDs given directly are always scraped. An extension found in several places is scraped (and charged) once.

## `respectRobotsTxt` (type: `boolean`):

Skip pages that the store's robots.txt disallows. Skipped pages are not charged.

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

How many pages are fetched in parallel. Keep it low to be polite to the store.

## `maxRequestsPerMinute` (type: `integer`):

Upper limit of page requests per minute.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a page before retrying.

## `maxRetries` (type: `integer`):

How many times a failing page is retried. Extensions that still fail are listed with status "failed" and are not charged.

## `proxyConfiguration` (type: `object`):

Optional. The store works without a proxy. Use Apify Proxy only if you see many failed pages.

## Actor input object example

```json
{
  "categories": [
    "productivity/developer"
  ],
  "searchTerms": [],
  "startUrls": [
    "https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh",
    "efaidnbmnnnibpcajpcglclefindmkaj"
  ],
  "maxResults": 5,
  "respectRobotsTxt": true,
  "maxConcurrency": 5,
  "maxRequestsPerMinute": 120,
  "requestTimeoutSecs": 30,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "categories": [
        "productivity/developer"
    ],
    "startUrls": [
        "https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh",
        "efaidnbmnnnibpcajpcglclefindmkaj"
    ],
    "maxResults": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("kilndata/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 = {
    "categories": ["productivity/developer"],
    "startUrls": [
        "https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh",
        "efaidnbmnnnibpcajpcglclefindmkaj",
    ],
    "maxResults": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("kilndata/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 '{
  "categories": [
    "productivity/developer"
  ],
  "startUrls": [
    "https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh",
    "efaidnbmnnnibpcajpcglclefindmkaj"
  ],
  "maxResults": 5
}' |
apify call kilndata/chrome-web-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kilndata/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/Xk7SGQ45HrZv9h6fJ/builds/n38yMGKcnMCBczbqt/openapi.json
