# WordPress Plugins Scraper — Installs, Downloads & Reviews (`oswaldocarabano/wordpress-plugins-scraper`) Actor

Scrape the WordPress.org plugin directory: 70+ fields per plugin (installs, 7/30-day downloads, ratings, support, last update, abandoned flag), daily download stats, reviews with developer replies, authors, and category snapshots with an opportunity score. No login. Errors never charged.

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

## Pricing

from $0.60 / 1,000 plugin records

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

## WordPress Plugins Scraper — installs, downloads, reviews and opportunity scores

Extract the **whole WordPress.org plugin directory** (about 76,000 plugins) or any tag, search,
author or list of plugins, with **70+ fields per plugin**: active installs, all-time and
7/30-day downloads with growth, rating and star histogram, support threads and how many were
resolved, last release, an **abandoned** flag, business model, tags, contributors, versions, FAQ
and changelog. Add **daily download series**, **reviews with the developer's reply**, **author
portfolios** and a **category snapshot with a published opportunity score** to find plugin ideas
worth building.

No login, no API key, no browser. Error rows, duplicates and plugins your filters skip are
**never charged**.

### What you can extract

| `outputType` | One row per | Highlights |
|---|---|---|
| `plugins` (default) | plugin | 70+ fields; downloads yesterday / 7 d / 30 d / previous 30 d and 30-day growth included at no extra cost |
| `plugin-stats` | plugin | daily downloads for up to 729 days, today / last week / all-time totals, share of sites on each version |
| `reviews` | review | stars, title, full text, date, public author, replies, developer reply (role, text and delay in hours) |
| `category-snapshot` | tag or search term | demand, ratings, staleness, new entrants, commercial share, **opportunityScore**, abandoned popular plugins, low-rated popular plugins |
| `authors` | developer | every plugin they publish, summed installs and downloads, weighted rating, abandoned and commercial counts, member since |

### Find plugin ideas worth building

- **Abandoned plugins that many sites still run**: `abandonedOnly: true` + `minActiveInstalls: 100000`.
  Sites need a maintained replacement.
- **Popular plugins users dislike**: `maxRating: 3.5` + `minNumRatings: 20` + `minActiveInstalls: 10000`.
  Then pull their 1–2 star `reviews` to read exactly what is missing.
- **Category gaps**: `category-snapshot` for tags such as `woocommerce`, `booking`, `membership`,
  `payment` and compare their opportunity scores; each row lists the abandoned and low-rated
  popular plugins of that category.
- **Momentum**: sort your export by `downloadsGrowth30d` to see what is gaining installs now.

### The opportunity score (published formula)

Every `category-snapshot` row carries `opportunityScore` (0–100) and its four components:

`opportunityScore = 100 × (0.40 × demand + 0.25 × dissatisfaction + 0.20 × staleness + 0.15 × openness)`

- **demand** = log10(1 + total active installs of the category) ÷ `demandLogCap`, capped at 1.
  `demandLogCap` is **8**: 100 million summed active installs saturate demand.
- **dissatisfaction** = share of rated plugins with a rating below 4.
- **staleness** = share of plugins without a release in more than 730 days.
- **openness** = 1 ÷ (1 + `populationCount` ÷ 50): fewer competitors, more room. `populationCount`
  is the size of the **whole** category as WordPress.org announces it (`resultsAnnounced`), so a
  big tag is not made to look open just because fewer plugins were analyzed (formula v1.1;
  `opennessBasis` says `category`, or `sample` if the category size was unknown).

Which plugins are measured: a snapshot reads the category's listing **most installed first** (tags)
or **most relevant first** (searches) and aggregates up to `maxPluginsPerCategory` plugins
(default **1,000**, up to 10,000). Demand, dissatisfaction and staleness are computed on those
`pluginsAnalyzed`; `coverage` = `pluginsAnalyzed` ÷ `resultsAnnounced` tells you how much of the
category that is. For big tags (the `woocommerce` tag announces 9,761 plugins) raise
`maxPluginsPerCategory` if you want the long tail in the shares; compare categories with similar
coverage.

It is deterministic: the same plugins give the same score in every run, so you can compare
categories and track one over time. It is arithmetic on public data, not AI. Active installs are
the lower bounds of the buckets WordPress.org publishes.

### Input examples

Default input `{}`: the 20 most installed plugins with full records and 30-day downloads.

```json
{ "tags": ["woocommerce"], "abandonedOnly": true, "minActiveInstalls": 10000, "maxItems": 50 }
```

```json
{ "outputType": "category-snapshot", "tags": ["booking", "membership", "payment", "forms"] }
```

```json
{ "outputType": "reviews", "pluginUrls": ["https://wordpress.org/plugins/wordpress-seo/"], "reviewsStars": ["1", "2"], "maxReviewsPerPlugin": 100 }
```

```json
{ "outputType": "plugin-stats", "pluginUrls": ["akismet", "classic-editor"], "statsDays": 365 }
```

```json
{ "browse": "all", "maxItems": 100000 }
```

Pasted plugin links are always delivered, whatever the filters. `pluginUrls` also accepts bare
slugs (`wordpress-seo`).

### How each filter works (measured on 17 Oct 2026)

- `search`, `tags`, `authors` and `browse` are sent to WordPress.org. One listing per tag or
  term; a search term inside a tag narrows natively. WordPress.org ignores the author when a search
  term is present, so the actor applies the author itself (author or contributor).
- A search returns the **~1,300 most relevant results** (the term "seo" announces 8,644 and
  serves 1,271). Combine terms with tags to go deeper.
- The popular order repeats some plugins at page boundaries; the actor walks the listing again
  with different page sizes and recovers them (the `woocommerce` tag goes from 77% to 99% of the
  9,761 announced plugins). `browse: "all"` walks the whole directory in a stable order.
- Installs, rating, number of ratings, dates, "tested up to", business model and abandoned are
  **checked by the actor** on each plugin of the listing, before any extra request. With any of
  them on, a run checks up to **100 plugins per requested row (at least 2,000)**; the status
  message shows how many were checked and skipped. Skipped plugins are never charged.

### Output fields (plugin row)

Share of the **whole directory** with a value (n = 76,015 plugins, 17 Oct 2026):

| Field | Filled | Field | Filled |
|---|---:|---|---:|
| name, slug, url, version, short description | 100% | rating (plugins with ratings) | 40.9% |
| activeInstalls + bucket + upper bound | 100% | numRatings, ratings1–5 | 100% |
| downloaded (all time) | 100% | supportThreads, resolved, unresolved | 100% |
| lastUpdated, daysSinceUpdate, abandoned, added | 100% | testedUpTo | 98.4% |
| author / authorUsername / contributors | 99.6–100% | requiresWp | 96.9% |
| tags | 98.2% | requiresPhp | 59.0% |
| descriptionText | 99.8% | installationText | 90.3% |
| changelogText | 89.2% | faqText | 73.4% |
| versions | 81.1% | homepage | 74.7% |
| screenshots | 64.1% | bannerUrl | 44.2% |
| upgradeNotice | 39.2% | donateLink | 37.3% |
| requiresPlugins (dependencies) | 8.9% | blocks | 7.4% |
| businessModel (declared) | 1.2% | iconUrl, downloadLink, supportUrl | 100% |

Download fields (with `includeDownloadStats`, the default) were filled in 100% of 1,500 real
plugin rows; `downloadsGrowth30d` and `downloadsPrev30d` in 67% (plugins younger than 60 days have
no previous period). Non-empty fields per plugin row: **54.7 of 73 over the whole directory**
without the download fields (n = 76,028, 17 Oct 2026); with them (the default) add 3 to 5; in 4,189
rows of 50 mixed test runs on Apify (popular plugins weigh more there) the average was 62.9.

### Other row types (real rows, 17 Oct 2026)

| Row type | n | Average non-empty fields | Fields below 100% |
|---|---:|---:|---|
| plugin-stats | 300 | 27.9 of 29 | rating 90% (plugins without ratings) |
| review | 580 | 17.0 of 22 | developer reply 52% (reviews the developer answered), reviewer username / topic id / last activity 61% (filled when the review page is opened), participants 5% (review-list pages only) |
| author | 300 | 24.2 of 25 | contributor plugin count 27%, member since 99% |
| category-snapshot | 30 tags | 37.4 of 38 | abandoned popular plugins 53% and low-rated popular plugins 87% (empty when a category has none) |

### Compared with other WordPress plugin actors on Apify

Read from each actor's published dataset schema and pricing through the Apify API on 17 Oct
2026 (31 actors that scrape the plugin directory; none had more than 2 users in 30 days):

| | This actor | Best of the others |
|---|---|---|
| Fields per plugin | 55–63 non-empty on average (73 keys; see the table above) | 32 declared (the richest schema) |
| 7/30-day downloads and growth | yes, by default | no one |
| Daily download history (up to 729 days) and version share | yes | no one |
| Category snapshot with a published opportunity score | yes | one actor has a per-plugin score without a published formula |
| Abandoned / low-rated popular plugins per category | yes | no one |
| Reviews with the developer's reply and its delay | yes | reply flag only, at $0.008 per topic |
| Tag coverage when walking a whole tag (`woocommerce`, 9,761 plugins) | 99% (multi-pass) | single pass: ~77% |
| Price per plugin | $0.001 → $0.0006 by plan, $0.00001 start | $0.00115 → $0.00028 by plan, **$0.005 start** |
| Errors, duplicates, filtered rows | never charged | some charge every lookup attempt |

Missing values are always `null`, never omitted. Dates are ISO 8601 (UTC). Contact details
(emails, including obfuscated forms such as "name \[at] domain.com" and emails inside links, and
phone numbers) are removed from names, descriptions, FAQ, changelog, upgrade notices, screenshot
captions and reviews, and no avatars are delivered.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Plugin record (primary) | **$0.001** per plugin ($1.00 per 1,000), lower on higher Apify plans: $0.00078 Silver, $0.0006 Gold and above |
| Plugin download stats | $0.001 per plugin |
| Review | $0.0005 per review |
| Category snapshot | $0.003 per tag or search term |
| Author | $0.001 per author |
| Actor start | $0.00001 |

Never charged: error rows, duplicates within a run, plugins your filters skip, empty reviews,
categories or authors without plugins. Rows served from the cache cost the same and carry
`cachedAt`.

### Speed and limits

Measured on Apify on 17 Oct 2026: the default input `{}` finishes in about 4 seconds; 15,000
plugins take about 80 seconds with 4 GB of memory; the whole directory (76,000 plugins) takes
about 35 minutes with the default 512 MB and a few minutes with 4 GB — for big exports, raise the
memory (the work is CPU-bound). Reviews go at about 1 request per second per connection.

WordPress.org limits requests per connection (about 15 per second on its API and about 1 per
second on its review forum, measured). The actor paces itself, spreads the forum requests across
connections and, when a connection is slowed down, moves to another one; it never solves a
challenge and never logs in.

### FAQ

**Is the install count exact?** No. WordPress.org only publishes buckets ("300,000+"). You get
the lower bound, the label and the upper bound of the bucket.

**How fresh is the data?** By default a plugin record, download series or review that another run
read from WordPress.org in the last **6 hours** (`maxCacheAgeHours`, up to 72) can be served from a
shared cache; those rows carry `cachedAt` (when it was read) and cost the same. Listings and the
rest are always read live. Set `maxCacheAgeHours: 0` to read everything live. Download stats change
once a day.

**Does it scrape themes?** No, plugins only.

**What happens when something fails?** You get one error row explaining what failed and what to
do, the run stays green when the problem is the input, and nothing is charged for it. The `ERRORS`
record of the run lists them all.

This actor is independent and **not affiliated with, endorsed or sponsored by WordPress.org, the
WordPress Foundation or Automattic**. It reads only public pages and public JSON endpoints.

# Actor input Schema

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

One row type per run. <b>plugins</b>: the full plugin record (70+ fields: active installs bucket, downloads, rating and star histogram, support threads, last update, abandoned flag, business model, tags, contributors, versions, FAQ, changelog and, by default, downloads in the last 7 and 30 days with 30-day growth). <b>plugin-stats</b>: the daily download series (up to two years), all-time and weekly totals and the share of sites per version. <b>reviews</b>: reviews with stars, title, full text, date, public author and the developer's reply. <b>category-snapshot</b>: one row per tag or search term with the market metrics and the published opportunityScore (demand, dissatisfaction, staleness, openness) plus the abandoned popular plugins and low-rated popular plugins of that category. <b>authors</b>: one row per developer with every plugin they publish and their summed installs.

## `pluginUrls` (type: `array`):

WordPress.org plugin pages, for example https://wordpress.org/plugins/wordpress-seo/, or just the slug (wordpress-seo). Read by plugins, plugin-stats, reviews and authors (the author of each plugin); every pasted plugin is delivered and the filters below are not applied to it. Entries that are not plugin links get one error row that is not charged.

## `search` (type: `array`):

Plugins that match these words, ranked by WordPress.org relevance (one search per term). WordPress.org returns the ~1,300 most relevant results of a search (measured on "seo": 8,644 announced, 1,271 reachable); combine a term with tags to go deeper. Plain words only (letters, digits, spaces and . , ' & + # -).

## `tags` (type: `array`):

WordPress.org plugin tags, for example woocommerce, seo, payment, forms (the slug in https://wordpress.org/plugins/tags/<tag>/). One listing per tag, ranked by active installs; with search terms, each term is searched inside each tag. For category-snapshot, each tag becomes one snapshot row.

## `authors` (type: `array`):

WordPress.org usernames or profile links (https://profiles.wordpress.org/yoast/). Lists every plugin of each author; with tags, only that author's plugins in those tags. With outputType authors, one row per author.

## `browse` (type: `string`):

<b>popular</b> = ranked by active installs (the default); <b>new</b> = newest first; <b>updated</b> = recently updated first; <b>all</b> = the whole directory (about 76,000 plugins, newest first); <b>blocks</b>, <b>featured</b>, <b>beta</b> = the small curated lists of WordPress.org. "Top rated" is not offered: WordPress.org answers it with the featured list (measured).

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

Rows delivered (and charged) at most. Duplicates, filtered-out plugins and error rows are never charged. When you paste plugin links and leave this empty, every one of them is delivered.

## `minActiveInstalls` (type: `integer`):

For example 100000. Active installs are the bucket WordPress.org shows (10+, 1,000+, 300,000+, 1+ million…). Checked by the actor on each plugin of the listing, before any extra request.

## `maxActiveInstalls` (type: `integer`):

For example 10000 to find niche plugins.

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

Average star rating. Plugins without ratings never match a rating filter.

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

For example 3.5 to find popular plugins that users dislike.

## `minNumRatings` (type: `integer`):

For example 20, so the rating means something.

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

Last release on or after this date (YYYY-MM-DD).

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

Last release on or before this date. For example 2024-10-17 = not updated for two years.

## `addedAfter` (type: `string`):

First published in the directory on or after this date.

## `addedBefore` (type: `string`):

First published on or before this date.

## `testedUpTo` (type: `string`):

For example 6.8: only plugins whose author declares they were tested with WordPress 6.8 or newer.

## `businessModel` (type: `string`):

As declared on WordPress.org: <b>commercial</b> = the author sells a paid version or service; <b>community</b> = community-maintained; <b>none</b> = nothing declared (most plugins).

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

Plugins whose last release is more than 730 days old. With Min active installs (for example 100000) this lists abandoned plugins that many sites still run: replacement opportunities.

## `includeDownloadStats` (type: `boolean`):

One extra small request per plugin (about 1 KB): downloadsYesterday, downloadsLast7d, downloadsLast30d, downloadsPrev30d and downloadsGrowth30d. No extra charge.

## `statsDays` (type: `integer`):

Length of the daily download series, up to 729 days (two years). Measured on WordPress.org: it serves up to 729 days per plugin; younger plugins return the days they have.

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

Only reviews with these star ratings, for example 1 and 2 stars for complaints. Empty = all.

## `maxReviewsPerPlugin` (type: `integer`):

The 30 newest reviews (per star filter) come from the review feed with full text; beyond that the actor walks the review pages and opens each review.

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

For example 2026-01-01.

## `includeDeveloperReplies` (type: `boolean`):

Opens each review that has replies and adds the first reply by someone WordPress.org badges as Plugin Author, Plugin Support or Plugin Contributor: developerReplied, developerReplyRole, developerReplyAt, developerReplyHours and developerReplyText.

## `maxPluginsPerCategory` (type: `integer`):

Plugins analyzed per tag or search term for each snapshot (the most installed first for tags). The woocommerce tag has about 9,800 plugins.

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

When a shared cache is available, plugin records, download series and reviews fetched by any run in the last N hours are reused instead of fetched again (download stats change once a day). Reused rows carry cachedAt and cost the same. 0 = always fetch live.

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

Plugins processed at once. WordPress.org limits requests per connection (about 15 per second on the API and about 1 per second on the review forum); the actor paces and spreads them across connections on its own, so higher values mainly speed up reviews and stats.

## Actor input object example

```json
{
  "outputType": "plugins",
  "pluginUrls": [],
  "search": [],
  "tags": [],
  "authors": [],
  "browse": "popular",
  "maxItems": 10,
  "businessModel": "any",
  "abandonedOnly": false,
  "includeDownloadStats": true,
  "statsDays": 90,
  "reviewsStars": [],
  "maxReviewsPerPlugin": 30,
  "includeDeveloperReplies": true,
  "maxPluginsPerCategory": 1000,
  "maxCacheAgeHours": 6,
  "maxConcurrency": 6
}
```

# Actor output Schema

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

The rows of this run: plugin records, download stats, reviews, category snapshots or authors, 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, plus request and route statistics.

# 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": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("oswaldocarabano/wordpress-plugins-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": 10 }

# Run the Actor and wait for it to finish
run = client.actor("oswaldocarabano/wordpress-plugins-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": 10
}' |
apify call oswaldocarabano/wordpress-plugins-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,oswaldocarabano/wordpress-plugins-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/6ZsSJu4DiVDJ4Q8Vj/builds/gca3asm3g4cIWzvHQ/openapi.json
