# Chrome Extension Lookup & Permission Audit (Web Store) (`ftrytech/chrome-extension-lookup`) Actor

Chrome Web Store extensions by id, URL or category: users, rating, version, update date, permissions and host access with a risk level, and what changed since your last run. Pages robots.txt allows, no search, no reviews, no personal data. For security teams, extension makers and AI agents.

- **URL**: https://apify.com/ftrytech/chrome-extension-lookup.md
- **Developed by:** [FtryTech](https://apify.com/ftrytech) (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 records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Extension Lookup & Permission Audit (Web Store)

Get Chrome Web Store extensions as clean JSON. Each row has users, rating, version, update and publish dates, size, languages, category and the Store's badges. It also has **the permissions and host access the extension asks for, with a risk level**. Look extensions up by id or URL, or read the top extensions of any Store category. Run it on a schedule, and each row says **what changed since your last run**: a new version, new permissions, more users, a lost badge.

By **FtryTech**.

### What it reads

Each extension's public Chrome Web Store page (`chromewebstore.google.com/detail/<id>`) and the Store's category pages. The Store's `robots.txt` allows these pages. It disallows search and the reviews tab, so **this Actor does not search and does not read reviews**. It reads the extensions you name, or the ones a category page lists. The Actor reads `robots.txt` at the start of every run and stops if the rules change. It fetches one page at a time, about a second apart. There is no login, no cookies, no proxy and no browser.

The permissions come from the extension's own manifest, which the Store page includes. The Actor returns what the manifest asks for, never the manifest text.

**No personal data.** A Store page also shows the publisher's e-mail, street address and phone. The Actor never returns them. The publisher's name, website, support and privacy-policy links are kept only when the name reads as an organisation (a company, foundation or project). When the publisher may be a private person, these fields are `null`.

### Who it is for

- **Security and IT teams:** audit the extensions your people use. Find every extension that can read all websites or your cookies. Schedule a run on your allow-list and get told when an extension adds a permission.
- **Extension makers:** watch your competitors' versions, users, ratings and badges. Use `includeRelated` to find the extensions the Store shows next to yours.
- **Market research:** read the top 32 of any category, by relevance or rating.
- **AI agents:** one call answers "what does this extension access, and is it safe?" Every field has a default, and an empty answer is an explicit row, never a silent empty dataset.

### Input

Every field is optional. With no input, the Actor reads one sample extension (uBlock Origin Lite).

```json
{
  "extensions": [
    "ddkjiahejlhfcafbddmgiahcphecmpfh",
    "https://chromewebstore.google.com/detail/grammarly-ai-writing-assi/kbfnbcaeplbcioakkpcpgfkobkghlhen"
  ],
  "categories": ["productivity/workflow"],
  "categorySort": "highestRated",
  "maxPerCategory": 10,
  "includeRelated": false,
  "includeDescription": false,
  "trackChanges": true,
  "changeFilter": "all_rows",
  "stateKey": "my-allow-list"
}
```

| Field | Default | Meaning |
|---|---|---|
| `extensions` | one sample extension | Extension or theme ids (32 letters, a to p) or Store URLs, old or new, one per line (up to 1,000). The sample is used only when you name no category either. |
| `categories` | none | Also read the top extensions of these categories, e.g. `productivity/developer`, `make_chrome_yours/privacy` (18 categories). |
| `categorySort` | `mostRelevant` | `mostRelevant` (the Store's default) or `highestRated`. |
| `maxPerCategory` | `20` | The most extensions read from each category, from the top (at most 32). |
| `includeRelated` | `false` | Add a row for each extension the Store lists as related (about 12 per extension). |
| `includeDescription` | `false` | Add the full listing text. |
| `trackChanges` | `true` | Remember each extension and report what changed on the next run. |
| `changeFilter` | `all_rows` | `all_rows`, `any_change` (only changed or new extensions) or `version_or_permissions` (only a new version or changed permissions, and new extensions). |
| `stateKey` | `default` | The memory's name. Use one per watch list you schedule. |

### Output

Each row has a `type`.

**`extension`**

```json
{
  "type": "extension",
  "input": "kbfnbcaeplbcioakkpcpgfkobkghlhen",
  "source": "input",
  "categoryRank": null,
  "extensionId": "kbfnbcaeplbcioakkpcpgfkobkghlhen",
  "name": "Grammarly: AI Writing Assistant and Grammar Checker App",
  "itemType": "extension",
  "category": "productivity/communication",
  "rating": 3.87,
  "ratingCount": 43163,
  "users": 40000000,
  "featured": true,
  "establishedPublisher": true,
  "publishedAt": "2012-10-22T10:17:01.000Z",
  "lastUpdated": "2026-10-22T15:54:11.000Z",
  "version": "14.1341.0",
  "size": "17.61MiB",
  "sizeBytes": 18465423,
  "languageCount": 1,
  "minimumChromeVersion": "98",
  "manifestVersion": 3,
  "permissions": ["scripting", "sidePanel", "tabs", "notifications", "cookies", "identity", "storage"],
  "optionalPermissions": ["nativeMessaging", "clipboardRead"],
  "hostPermissions": ["http://*/*", "https://*/*"],
  "broadHostAccess": true,
  "sensitivePermissions": ["cookies", "identity", "scripting", "tabs"],
  "riskLevel": "high",
  "publisher": "Grammarly, Inc.",
  "publisherIsTrader": true,
  "publisherId": "u7431803589585a11dd7aea578e1005d0",
  "website": "http://grammarly.com/",
  "url": "https://chromewebstore.google.com/detail/kbfnbcaeplbcioakkpcpgfkobkghlhen",
  "firstCheck": false,
  "previousCheckAt": "2026-10-18T06:00:00.000Z",
  "changes": [{ "field": "version", "before": "14.1338.0", "after": "14.1341.0" }]
}
```

Rows also carry `shortDescription`, `languages`, `optionalHostPermissions`, `contentScriptMatches`, `supportUrl`, `privacyPolicyUrl` and `iconUrl`.

**`riskLevel`** is a plain reading of the manifest, not a verdict:

- `high`: it asks for `debugger`, `nativeMessaging` or `proxy`. Or it can reach every website and also asks for a permission that reads or reroutes browsing, such as `cookies`, `webRequest`, `scripting`, `history` or `clipboardRead`.
- `medium`: it can reach every website, or it asks for any sensitive permission (`tabs`, `downloads`, `bookmarks` and others; see `sensitivePermissions`).
- `low`: neither.

Many trusted extensions are `high` because their job needs it; an ad blocker must see every page. Use the level to decide what to look at first.

**`changes`** lists each tracked field that moved since the last check, as `{field, before, after}`. The tracked fields are name, version, permissions, host permissions, optional permissions, content-script pages, users, rating, rating count, the two badges and the publisher. It is `null` on the first check.

**`related_extension`**: `extension` (the looked-up id), `position`, `extensionId`, `name`, `itemType`, `category`, `shortDescription`, `rating`, `ratingCount`, `users`, `featured`, `establishedPublisher` and `url`.

**`no_results` (free):** written when an entry gives nothing. Its `reason` is one of `invalid_entry`, `extension_not_found`, `category_empty`, `blocked_by_robots`, `page_unreadable`, `no_related`, `no_changes` or `fetch_failed`, and `message` says what to change. You are never charged for these rows.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Extension record (one `extension` row) | $0.002 ($2 per 1,000 extensions) |
| Related extension (one `related_extension` row) | $0.0005 |
| `no_results` rows, including unchanged extensions under a change filter | free |

Apify also charges its standard tiny run-start fee. The run stops cleanly at your spending limit.

### Tips

- **Permission-drift alerts:** put your allow-list in `extensions`, set `changeFilter` to `version_or_permissions`, and schedule the run daily. You pay only for the extensions that changed. Connect the dataset to Slack, Sheets or a webhook.
- **Competitor watch:** schedule a weekly run on your rivals with `changeFilter: "any_change"`.
- **Category snapshot:** `categories` with `trackChanges` on shows who climbed or lost users between runs.
- An extension's id is the last part of its Store URL.

### For AI agents (MCP)

- Call it with only `extensions`. Every other input has a default.
- Read `type` first. `no_results` rows explain an empty answer in `reason` and `message`.
- For "is this extension safe?", read `riskLevel`, `broadHostAccess` and `sensitivePermissions`, then `establishedPublisher` and `lastUpdated`.

### Limits

- No keyword search and no reviews: the Store's `robots.txt` disallows both, and this Actor keeps to it.
- A category page lists at most 32 extensions; the Actor reads no further.
- `users` is the Store's own figure, which it rounds down (for example 22,000,000).
- The risk level reads only the manifest. It does not inspect the extension's code.
- Publishers that may be private persons have no name or links in the rows.

Questions or a field you need? Open an issue on the Actor's Issues tab.

# Actor input Schema

## `extensions` (type: `array`):

One per line: an extension or theme id (32 letters a to p) or its Chrome Web Store URL (new chromewebstore.google.com or old chrome.google.com/webstore). Duplicates are read once. The sample extension is used only when you name no category either.

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

Also read the top extensions of these Store categories (up to 32 each, as the category page lists them). Each one is a billed extension row.

## `categorySort` (type: `string`):

How a category page is ordered: the Store's default (most relevant) or highest rated.

## `maxPerCategory` (type: `integer`):

The most extensions read (and billed) from each category, from the top. A category page lists at most 32.

## `includeRelated` (type: `boolean`):

After each extension row, add a row for each extension the Store lists as related (about 12; billed per row). Good for finding competitors and alternatives.

## `includeDescription` (type: `boolean`):

Add the Store listing's full description text. The short description is always included. The price is the same.

## `trackChanges` (type: `boolean`):

Remember each extension's version, permissions, users, rating, badges and publisher, and say on the next run what changed (the changes field). Schedule the run to watch extensions.

## `changeFilter` (type: `string`):

all_rows: every extension, changed or not. any_change: only extensions with a change since the last run (and new ones). version_or_permissions: only a new version or changed permissions or host access (and new ones). The filters switch change tracking on.

## `stateKey` (type: `string`):

The name of the memory that keeps the last check of each extension. Use a different name for each watch list you schedule.

## Actor input object example

```json
{
  "extensions": [
    "ddkjiahejlhfcafbddmgiahcphecmpfh",
    "https://chromewebstore.google.com/detail/grammarly-ai-writing-assi/kbfnbcaeplbcioakkpcpgfkobkghlhen"
  ],
  "categories": [],
  "categorySort": "mostRelevant",
  "maxPerCategory": 20,
  "includeRelated": false,
  "includeDescription": false,
  "trackChanges": true,
  "changeFilter": "all_rows",
  "stateKey": "default"
}
```

# Actor output Schema

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

The run's rows in the default dataset, as JSON.

# 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 = {
    "extensions": [
        "ddkjiahejlhfcafbddmgiahcphecmpfh",
        "https://chromewebstore.google.com/detail/grammarly-ai-writing-assi/kbfnbcaeplbcioakkpcpgfkobkghlhen"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ftrytech/chrome-extension-lookup").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 = { "extensions": [
        "ddkjiahejlhfcafbddmgiahcphecmpfh",
        "https://chromewebstore.google.com/detail/grammarly-ai-writing-assi/kbfnbcaeplbcioakkpcpgfkobkghlhen",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ftrytech/chrome-extension-lookup").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 '{
  "extensions": [
    "ddkjiahejlhfcafbddmgiahcphecmpfh",
    "https://chromewebstore.google.com/detail/grammarly-ai-writing-assi/kbfnbcaeplbcioakkpcpgfkobkghlhen"
  ]
}' |
apify call ftrytech/chrome-extension-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ftrytech/chrome-extension-lookup"
        }
    }
}
```

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/W4108ieNq3MtKhiIE/builds/eXjVNszdWuFBaL3Yw/openapi.json
