# Chrome Web Store Extensions Scraper (`scrapyx/chrome-webstore-extensions-scraper`) Actor

Chrome extension records: name, rating, install count, version, size, developer and contact email, languages, screenshots — and the complete extension manifest with its permissions and host permissions. Look up by ID, or discover by search, category or collection.

- **URL**: https://apify.com/scrapyx/chrome-webstore-extensions-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

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 Extensions Scraper

Chrome extension records — name, rating, install count, version, size,
developer and contact email, languages, screenshots, and **the complete
extension manifest with its permissions**.

### Why use this actor

- **You get the manifest.** Every row carries the extension's real
  `manifest.json`, parsed, with `permissions` and `host_permissions` broken out
  as lists you can filter on. That is the answer to "which of these extensions
  can read every page I visit?" — and it comes back even on search results,
  without opening a single extension page.
- **Developer name and contact email** on every record.
- **Look up as many extensions as you like.** Paste ids or store URLs; there is
  no cap on that path. Search and category pages are limited to their first
  page by Google itself, and the output says so rather than quietly returning
  the same ten rows over and over.
- **Rounded numbers are labelled as rounded.** Google publishes install counts
  as buckets (20,000,000 — not 20,143,882), so the field is named
  `installCountApprox` and flagged. Nobody should build a market-share model on
  it by accident.
- **No account, no API key, no login.**

### How it works

1. You give it extension ids or URLs, search terms, or category/collection
   pages.
2. It reads the structured record Google already embeds in each page — no
   screen-scraping of layout, so a redesign does not break it.
3. For discovered extensions it optionally opens each one's page to add the
   version, size, languages, developer and long description.
4. Results land in your dataset as JSON, CSV or Excel, with a summary row per
   query.

### Input

```json
{
  "extensionIds": ["ddkjiahejlhfcafbddmgiahcphecmpfh"],
  "searchTerms": ["adblock"],
  "listingUrls": ["https://chromewebstore.google.com/category/extensions/productivity/workflow"],
  "includeDetails": true,
  "includeRawPayload": false,
  "maxItemsPerQuery": 200,
  "maxConcurrency": 4,
  "minRequestInterval": 0.6,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

| Field | Type | Description |
|---|---|---|
| `extensionIds` | array | The 32-letter id from a store URL, or the full URL. **The only input with no result cap.** |
| `searchTerms` | array | Store search. Google serves 10 results per term and no more. |
| `listingUrls` | array | A category page (~32 extensions) or collection page (~16). First page only. |
| `includeDetails` | boolean | Open each discovered extension's own page for version, size, languages, developer and the long description. One request per extension. Default `true`. |
| `includeRawPayload` | boolean | Attach Google's untouched data array to every row — the only complete copy of what was sent, since the source has no field names. Roughly doubles row size. Default `false`. |
| `maxItemsPerQuery` | integer | Cap per search term or listing URL. `0` = no cap, though Google's first-page limit still applies. Default `200`. |
| `maxConcurrency` | integer | Requests in flight. Default `4`. |
| `minRequestInterval` | number | Seconds between request starts. Default `0.6`. |
| `proxyConfiguration` | object | Apify Proxy. Datacenter is the default and is sufficient. |

### Output

Three record types share one dataset, told apart by `recordType`.

#### `EXTENSION`

```json
{
  "_input": "id=ddkjiahejlhfcafbddmgiahcphecmpfh",
  "_source": "S1-detail-dsdata",
  "_scrapedAt": "2026-09-16T04:47:36Z",
  "recordType": "EXTENSION",
  "extensionId": "ddkjiahejlhfcafbddmgiahcphecmpfh",
  "name": "uBlock Origin Lite",
  "extensionUrl": "https://chromewebstore.google.com/detail/ddkjiahejlhfcafbddmgiahcphecmpfh",
  "rating": 4.49859075535513,
  "ratingCount": 3548,
  "installCountApprox": 20000000,
  "categoryPath": "make_chrome_yours/privacy",
  "shortDescription": "An efficient content blocker. Blocks ads, trackers, miners, and more…",
  "fullDescription": "uBO Lite (uBOL) is an efficient MV3-based content blocker…",
  "version": "2026.914.1325",
  "size": "9.23MiB",
  "minimumChromeVersion": "122.0",
  "supportUrl": "https://github.com/uBlockOrigin/uBOL-issues",
  "privacyPolicyUrl": "https://github.com/gorhill/uBlock/wiki/Privacy-policy",
  "developerName": "Raymond Hill (gorhill)",
  "developerEmail": "ubo@raymondhill.net",
  "firstPublishedAt": "2022-09-08T13:10:25Z",
  "lastUpdatedAt": "2026-09-14T14:48:01Z",
  "manifestVersion": 3,
  "permissions": ["activeTab", "alarms", "declarativeNetRequest", "offscreen", "scripting", "storage", "unlimitedStorage", "userScripts"],
  "hostPermissions": ["<all_urls>"],
  "manifest": { "…the full manifest.json, parsed…" },
  "languages": ["Deutsch", "English", "Filipino", "… 57 more"],
  "iconUrl": "https://lh3.googleusercontent.com/…",
  "screenshotUrls": ["https://lh3.googleusercontent.com/…"]
}
```

| Field | Description |
|---|---|
| `extensionId` / `extensionUrl` | The id and a direct store link. |
| `name` / `shortDescription` / `fullDescription` | Listing copy. |
| `rating` / `ratingCount` | Average score and how many ratings it rests on. |
| `installCountApprox` | **A rounded bucket**, not an exact figure. |
| `categoryPath` | e.g. `make_chrome_yours/privacy`. |
| `version` / `size` / `minimumChromeVersion` | Release detail *(detail pass)*. |
| `developerName` / `developerEmail` | Publisher and contact *(detail pass)*. |
| `firstPublishedAt` / `lastUpdatedAt` | ISO 8601 UTC. |
| `manifest` / `manifestRaw` / `manifestVersion` | The extension's real manifest, parsed and raw. |
| `permissions` / `hostPermissions` | Pulled out of the manifest so you can filter on them. |
| `languages` / `languageCodes` | Supported locales *(detail pass)*. |
| `iconUrl` / `bannerUrl` / `tileUrl` / `screenshotUrls` | Imagery. |
| `websiteUrl` / `supportUrl` / `privacyPolicyUrl` | Publisher links. |
| `rawCard` | Google's untouched array, when `includeRawPayload` is on. |
| `_detailError` | Present only when an extension's own page could not be read. |

#### `SEARCH_SUMMARY`

| Field | Description |
|---|---|
| `surface` | `detail`, `search` or `listing`. |
| `requested` / `extensionsReturned` / `failures` | What the query did. |
| `upstreamServesFixedFirstPage` | `true` for search and listing — Google's own cap, not this actor's. |
| `installCountIsApproximate` | Always `true`. |
| `decodedFromPositionalArray` | Always `true` — see Known limits. |

#### `ERROR`

| `_error` | Meaning |
|---|---|
| `invalid_input` | A malformed extension id, or a URL that is not a Chrome Web Store page. |
| `not_found` | The extension page carried no record — removed, unpublished, or a wrong id. |
| `unexpected_shape` | The page loaded but the data was not where this actor expects it. |
| `fetch_failed` | Network or server trouble after retries. |

### Known limits

- **Search returns 10 results, categories about 32.** That is Google's own
  first-page limit; the store loads more over a private channel this actor does
  not use. For coverage, feed extension ids directly — that path has no cap.
- **Install counts are rounded** to public buckets.
- **Reviews are not included** — only the rating and the number of ratings.
- **Google publishes these records without field names**, as bare positional
  arrays. This actor decodes the positions it can justify and leaves the rest
  untouched; turn on `includeRawPayload` to see everything that was sent. If
  Google ever reorders the array, the actor fails with an error rather than
  reporting wrong numbers.

# Actor input Schema

## `extensionIds` (type: `array`):

The 32-letter id from a Chrome Web Store URL, e.g. 'ddkjiahejlhfcafbddmgiahcphecmpfh' — a full store URL works too. This is the only input with no result cap: search and category pages are limited by Google to their first page, extension lookups are not.

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

Search the store, e.g. 'adblock', 'password manager'. Google serves 10 results per search and no more — its 'show more' loads over a private channel this actor does not use — so each term returns up to 10 extensions.

## `listingUrls` (type: `array`):

Paste a Chrome Web Store category or collection page, e.g. https://chromewebstore.google.com/category/extensions/productivity/workflow. Category pages serve about 32 extensions, collections about 16 — again, the first page only.

## `includeDetails` (type: `boolean`):

ON by default. Search and category cards already carry the name, rating, install count, category, website and the full extension manifest — but not the version, size, supported languages, developer name and email, or the long description. Those need the extension's own page, one request each.

## `includeRawPayload` (type: `boolean`):

Attach Google's own untouched data array to every row. Google publishes these records with no field names at all — just positions — so this is the only complete copy of what was actually sent. Useful for auditing or for reading a field this actor does not decode. Roughly doubles row size.

## `maxItemsPerQuery` (type: `integer`):

Cap on extensions returned per search term or listing URL. 0 means no cap — though Google's own first-page limit applies regardless.

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

Requests in flight. This matters most when looking up many extension ids, or during the detail pass. Pages are 600 KB–1 MB each.

## `minRequestInterval` (type: `number`):

Shortest gap between two request starts, across all workers. The honest speed control. No rate limiting was observed during testing.

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

Apify Proxy settings. Datacenter is the default and is sufficient — every page type answered normally to a plain unproxied request during testing.

## Actor input object example

```json
{
  "extensionIds": [
    "ddkjiahejlhfcafbddmgiahcphecmpfh"
  ],
  "includeDetails": true,
  "includeRawPayload": false,
  "maxItemsPerQuery": 200,
  "maxConcurrency": 4,
  "minRequestInterval": 0.6,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "extensionIds": [
        "ddkjiahejlhfcafbddmgiahcphecmpfh"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/chrome-webstore-extensions-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 = { "extensionIds": ["ddkjiahejlhfcafbddmgiahcphecmpfh"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/chrome-webstore-extensions-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 '{
  "extensionIds": [
    "ddkjiahejlhfcafbddmgiahcphecmpfh"
  ]
}' |
apify call scrapyx/chrome-webstore-extensions-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/chrome-webstore-extensions-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/LsCdXiHNVVh1RQgQu/builds/8cB4wrLtaYf4fY5FO/openapi.json
