# npm Downloads Scraper - Package Trends & Growth (`dataio/npm-registry-download-trends`) Actor

Compare npm packages side by side: weekly, monthly and yearly downloads, a growth trend computed with the registry's missing days excluded, and days since the last release. Track JavaScript library adoption, or search packages by keyword. No API key needed.

- **URL**: https://apify.com/dataio/npm-registry-download-trends.md
- **Developed by:** [Tom Awake](https://apify.com/dataio) (community)
- **Categories:** Developer tools, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 packages

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

### What does npm Downloads Scraper do?

Compare npm libraries on what actually decides a dependency choice: how
many people use them, which way that is going, and whether anyone still
maintains them.

The registry answers those three questions in three separate endpoints,
and none of them gives a trend. Download history is published day by day,
never as a direction.

No API key. No account.

***

### The trend the registry hides — and nearly gets wrong

npm's daily download series **contains gaps**. Not quiet days: actual
missing days, published as zero.

React's last thirty days:

```
2026-08-13  Thu   28,442,032
2026-08-14  Fri            0     <- missing
...
2026-09-03  Thu            0     <- missing
2026-09-07  Mon            0     <- missing
2026-09-08  Tue            0     <- missing
2026-09-09  Wed   32,073,030
```

React does not fall from 28 million to zero and back to 32 million. Four
days were missing that month — **three of them in the second half**.

Take the series at face value and every library looks like it is dying:

| Package | Naive trend | Corrected |
|---|---|---|
| react | −13.0% | **+0.2%** |
| solid-js | −6.1% | **+9.5%** |
| htmx.org | — | **+7.1%** |
| svelte | −22.0% | −2.1% |
| angular | −51.2% | −45.7% |

Zero of ten packages growing, against **seven of ten** once the gaps are
excluded. Angular stays down because that decline is real — the `angular`
package is AngularJS, and it is genuinely being abandoned.

Every row carries `missingDays` so you can see how much of the period was
actually published.

***

### The four things this does that the source does not

**1. A comparison table.**

React 647M monthly downloads, Vue 58M, Svelte 20.6M, Solid 15M — four
numbers side by side, from one run. The registry answers one package per
request; downloads are fetched in batches of 30.

**2. A trend that survives scrutiny.**

Gaps excluded, the last two days dropped as unconsolidated, and blocks of
**seven days** compared — because splitting thirty days in half gives
fifteen against fifteen, which is two weeks and a day, and whichever
block inherits the extra weekend looks like it is falling. Averages per
valid day are compared, not sums.

**3. The small document.**

Fetching a package returns its entire version history: **6.8 MB for
React, 2,951 versions**. The `/latest` endpoint returns the same useful
metadata in **2.1 KB**.

**4. Abandonment, dated.**

`daysSincePublish` says what no quality score says. A library with
millions of weekly downloads and no release in two years is a risk, and it
scores well on every other measure.

***

### Field coverage

Measured on ten front-end frameworks.

| Field | Coverage |
|---|---|
| `package`, `version`, `description`, `license` | 100% |
| `downloadsLastWeek`, `downloadsLastMonth`, `downloadsLastYear` | 100% |
| `trendPct`, `dailyAverage`, `missingDays` | 100% |
| `repository`, `unpackedSizeKb` | 100% |
| `daysSincePublish` | 80% |
| `dependencyCount` | 60% |

#### No npm score is published here, and that is measured

npm exposes four scoring fields. None of them is included, for two
separate reasons.

`score.final` reads 2,459 for React because it is a **search relevance**
score, not a quality rating. Publishing it as "npm score" would invite
exactly the wrong reading.

`score.detail.quality`, `.popularity` and `.maintenance` are worse.
Measured 17 September 2026 across eleven packages, from `react` down to
`is-odd` — a one-line package — all three return **exactly 1.0000 in
every case**:

| Package | quality | popularity | maintenance |
|---|---|---|---|
| react | 1.0000 | 1.0000 | 1.0000 |
| express | 1.0000 | 1.0000 | 1.0000 |
| is-odd | 1.0000 | 1.0000 | 1.0000 |
| pad-left | 1.0000 | 1.0000 | 1.0000 |

npm has frozen these scores. A `quality` column that grades React and
`is-odd` identically promises an assessment that is not happening.

What does measure adoption is in the table above: the download figures,
the slope between them (`trendPct`), and how recently the package was
published.

***

### What it is for

- **Choosing a dependency.** Downloads, trend, maintenance and last
  release for every candidate, in one table.
- **Watching a competitor's open-source project.** Adoption curve without
  asking them.
- **Auditing a stack.** Feed your `package.json` dependency list in and
  see which ones stopped being maintained.
- **Ecosystem research.** Search by keyword and rank by adoption to see
  what a category actually looks like.
- **Developer marketing.** Where your library sits against the
  alternatives, weekly.

Three dataset views ship with the Actor: **Adoption**, **Health** and
**Package profile**.

***

### Limits

Stated plainly, because they affect what you can conclude.

- **Downloads are not users.** CI pipelines, mirrors and Docker builds
  download packages thousands of times a day. Treat the number as
  relative, useful for comparing libraries, not as an install base.
- **`downloadsLastMonth` is npm's own total, gaps included.** It is left
  as the registry reports it, which means it understates by roughly the
  number of missing days. `dailyAverage` is computed on published days
  only and is the more honest figure.
- **A trend needs at least two full weeks.** Below that, `trendPct` is
  empty rather than noisy. Choose **last month** or longer.
- **The three scores are npm's, not ours.** Their methodology is npm's
  and changes without notice.
- **Scoped packages sometimes miss download data.** `@scope/name` is
  supported, but the batch download endpoint is less reliable for them.
- **Package names are exact.** No fuzzy matching — `solid-js` is not
  `solidjs`. Unknown names are reported in the status message rather than
  dropped in silence.
- **PyPI is not covered.** Its download statistics sit behind a service
  that rate-limits hard, and half-reliable numbers are worse than none.

***

### How much does it cost?

You pay per package returned: **$0.006 each**, that is $6.00 per 1,000. There is no start fee, and subscription plans pay less per package.

The example input below asks for up to 100 packages, so it costs **$0.60 at most**.

If a run reaches the spending limit you set, the output stops at that limit and never goes past it. You are never charged for rows that were not delivered.

### Use npm Downloads Scraper as an API

Call it from your own code with the Apify client, here in Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("DataIO/npm-registry-download-trends").call(run_input={
    'packages': ['react', 'vue', 'svelte', 'solid-js'],
    'period': 'last-month',
    'maxItems': 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

It also works from JavaScript, Make, Zapier, n8n, and from AI agents through the Apify MCP server.

### Other actors you might like

- [WordPress Plugin Scraper](https://apify.com/DataIO/wordpress-org-plugin-stats): Installs & Ratings
- [crt.sh Subdomain Finder](https://apify.com/DataIO/crtsh-subdomain-finder): Certificate Search
- [Domain Expiry Checker](https://apify.com/DataIO/rdap-domain-expiry-monitor): RDAP Registrar & Status

### FAQ

#### Is it legal to use this data?

The actor reads public data from its official source, without logging in and without bypassing any access control. What you do with the data, for example contacting people listed in it, is your responsibility under the laws that apply to you, such as GDPR in Europe.

#### Can I run it on a schedule?

Yes. Create a schedule in Apify Console, daily or weekly for example, and each run delivers a fresh dataset, which you can send by email, webhook or integration.

#### Can AI agents use it?

Yes. It is available through the Apify MCP server, and every input field is described in its input schema, so an agent can call it directly.

### Source

The public npm registry (`registry.npmjs.org`) and its download API
(`api.npmjs.org`). No authentication. This Actor is not affiliated with
npm or GitHub.

# Actor input Schema

## `packages` (type: `array`):

Exact npm package names, one per line. Scoped names work too: @types/node. Put competing libraries side by side — that comparison is the point.

## `searchTerm` (type: `string`):

Discover packages by keyword instead of naming them, for example web scraping, date picker, state management.

## `period` (type: `string`):

Window for download counts and the trend. A month gives four weekly blocks, which is the minimum for a trend that means anything.

## `minDownloads` (type: `integer`):

Over the selected period. Useful after a keyword search, where most results have almost no adoption.

## `growingOnly` (type: `boolean`):

Keeps packages whose trend is positive.

## `publishedWithinDays` (type: `integer`):

Removes abandoned packages. A library with millions of weekly downloads and no release in two years is a risk, not an endorsement.

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

One row per package. Each costs about three requests, so 200 packages takes a couple of minutes.

## Actor input object example

```json
{
  "packages": [
    "react",
    "vue",
    "svelte",
    "solid-js"
  ],
  "period": "last-month",
  "growingOnly": false,
  "maxItems": 200
}
```

# Actor output Schema

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

Every row produced by the run, in 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 = {
    "packages": [
        "react",
        "vue",
        "svelte",
        "solid-js"
    ],
    "maxItems": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataio/npm-registry-download-trends").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 = {
    "packages": [
        "react",
        "vue",
        "svelte",
        "solid-js",
    ],
    "maxItems": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("dataio/npm-registry-download-trends").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 '{
  "packages": [
    "react",
    "vue",
    "svelte",
    "solid-js"
  ],
  "maxItems": 200
}' |
apify call dataio/npm-registry-download-trends --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataio/npm-registry-download-trends"
        }
    }
}
```

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/dQVeUfPxNdqXdZXvI/builds/wdPXcBvxcsA1qZiJv/openapi.json
