# PyPI Package Download Statistics Scraper (`automation-lab/pypi-package-download-stats`) Actor

Export recent totals, daily download trends, and Python-version breakdowns for named PyPI packages and recurring dependency adoption monitoring.

- **URL**: https://apify.com/automation-lab/pypi-package-download-stats.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.01 / 1,000 package extracteds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## PyPI Package Download Statistics

Export **PyPI package download statistics** for exact package names as structured, timestamped dataset rows. The Actor combines recent one-day, one-week, and one-month totals with daily trends and Python major/minor-version breakdowns.

Use it to compare dependency adoption, watch ecosystem changes on a schedule, or feed package-usage signals into a spreadsheet, warehouse, dashboard, or internal data pipeline. It runs anonymously against public PyPI metadata and ClickPy's public read-only PyPI download dataset; no PyPI account, API key, browser, or user-supplied proxy configuration is required.

### What does this Actor do?

For each package name, the Actor:

1. resolves public PyPI identity and current-version metadata;
2. retrieves recent download totals;
3. retrieves the requested daily and Python-version time series;
4. keeps the latest requested dates;
5. writes normalized rows to the default Apify dataset.

Every successful package starts with a `summary` row. Selected reports then add `daily`, `python_major`, or `python_minor` rows. This row-oriented shape is convenient for SQL, pivot tables, time-series charts, and scheduled comparisons.

### Who is it for?

- **Platform and infrastructure teams** comparing adoption of candidate dependencies.
- **Open-source maintainers** tracking package reach and supported Python-runtime usage.
- **Developer-relations teams** monitoring package adoption after releases or campaigns.
- **Security and supply-chain teams** adding usage context to dependency inventories.
- **Data analysts** building recurring Python ecosystem datasets.

### Why use this PyPI statistics exporter?

- Batch up to 20 exact package names in one run.
- Get recent totals and timestamped breakdowns in one stable schema.
- Choose only the reports your workflow needs.
- Bound history to 1–180 available dates and output to 20,000 rows.
- Schedule runs with Apify and compare snapshots downstream.
- Pay once per successfully fetched package, not once per historical row.
- Use lightweight public JSON requests rather than browser automation.

### What data can I extract?

| Field | Meaning |
| --- | --- |
| `recordType` | `summary`, `daily`, `python_major`, or `python_minor` |
| `package` | Canonical package name from PyPI metadata, or the requested name when metadata is unavailable |
| `displayName` | Name from current PyPI package metadata when available |
| `currentVersion` | Current release shown by PyPI when the run executes |
| `date` | Statistics date on timestamped rows |
| `category` | Mirror scope or Python major/minor version |
| `downloads` | Downloads for the row's date and category |
| `lastDay` | Recent one-day total on a summary row |
| `lastWeek` | Recent seven-day total on a summary row |
| `lastMonth` | Recent thirty-day total on a summary row |
| `includesMirrors` | Requested mirror scope for daily totals |
| `sourceUrl` | Public endpoint represented by the row |
| `retrievedAt` | UTC timestamp when the package was fetched |

Unavailable enrichment values are `null`; they are never replaced with invented values.

### How to run the Actor

1. Open the Actor in Apify Console.
2. Add one or more exact names under **PyPI package names**.
3. Select daily, Python-major, and/or Python-minor reports.
4. Choose the number of recent dates to keep.
5. Optionally include mirror downloads in daily totals.
6. Click **Start**.
7. Open the default dataset to preview, download, or integrate the rows.

A practical first input is:

```json
{
  "packages": ["requests", "pandas", "fastapi"],
  "reports": ["daily", "pythonMajor"],
  "days": 30,
  "includeMirrors": false,
  "maxRows": 5000
}
```

### Input parameters

#### `packages`

Required array of 1–20 exact PyPI project names. Names may contain letters, numbers, dots, underscores, and hyphens. Duplicate names in one input are removed.

#### `reports`

Choose one or more values:

- `daily` — daily download totals;
- `pythonMajor` — daily counts grouped by major runtime such as `3`;
- `pythonMinor` — daily counts grouped by runtime such as `3.11`.

A recent-totals summary is always included and does not need a separate selection.

#### `days`

Number of latest available dates to retain in every selected time series. Allowed range: 1–180. Statistics can lag the current date, so “30 days” means the latest 30 dates returned by the source rather than an assurance that today is present.

#### `includeMirrors`

When `true`, `daily` rows use totals including downloads reported by mirrors. When `false`, daily rows exclude mirrors. Python-version reports use the source's version categories and are not separately split by mirror status.

#### `maxRows`

Global safety limit across summary and breakdown rows. Allowed range: 1–20,000. The Actor stops accepting output when the limit is reached.

### Output example

A current summary row has this shape:

```json
{
  "recordType": "summary",
  "package": "requests",
  "displayName": "requests",
  "currentVersion": "2.34.2",
  "date": null,
  "category": null,
  "downloads": null,
  "lastDay": 27982200,
  "lastWeek": 268877908,
  "lastMonth": 1497444432,
  "includesMirrors": false,
  "sourceUrl": "https://clickpy.clickhouse.com/dashboard/requests",
  "retrievedAt": "2026-09-07T20:09:26.542Z"
}
```

A timestamped breakdown row uses `date`, `category`, and `downloads`; recent-total fields are `null`. Counts change whenever the public source updates.

### Understanding the record types

#### Summary

One row per successfully fetched package. Use `lastDay`, `lastWeek`, and `lastMonth` for quick package comparisons.

#### Daily

One row per date for the selected mirror scope. Use these rows for trend lines, moving averages, or before-and-after release analysis.

#### Python major version

One row per date and Python major category. This shows the broad Python 2/3 or future major-version distribution reported by the source.

#### Python minor version

One row per date and reported minor category. Use it to assess runtime adoption, but remember that client metadata can be missing or nonstandard.

### How much does it cost to monitor PyPI packages?

The Actor uses pay-per-event pricing:

- **$0.00005** once when a run starts;
- **$0.0066767 per successfully fetched package on the Bronze tier**.

Timestamped rows included for that package have no separate event charge. At Bronze pricing, 1 package costs about **$0.00673**, 10 packages about **$0.06682**, and 20 packages about **$0.13358**. Other account tiers use the prices shown by Apify before the run starts.

A package is charged only after useful rows are saved. Invalid inputs and a package request that fails before output do not create a package event.

### Schedule dependency adoption monitoring

Create an Apify Schedule to run daily or weekly with a stable package list. Send each completed dataset to your warehouse, or use an integration to append rows to a spreadsheet. Compare `retrievedAt` snapshots and source dates downstream rather than expecting the Actor to maintain hidden state between runs.

For example, track `fastapi`, `flask`, and `django` with `daily` and `pythonMajor` reports. This gives both package-level totals and runtime-adoption context in every run.

### Export to spreadsheets and data pipelines

The default dataset is available as JSON, CSV, Excel, XML, RSS, and other Apify-supported formats. For tabular tools:

1. filter `recordType = summary` for package-level comparison;
2. filter `recordType = daily` for one line per package/date;
3. pivot Python rows by `category` to produce version-share charts;
4. use `retrievedAt` to identify the collection snapshot.

Avoid summing the summary totals together with daily or Python rows: they represent overlapping views of the same download activity.

### Run through the Apify API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~pypi-package-download-stats/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"packages":["requests","pandas"],"reports":["daily"],"days":30}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/pypi-package-download-stats').call({
  packages: ['requests', 'pandas'],
  reports: ['daily', 'pythonMajor'],
  days: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("automation-lab/pypi-package-download-stats").call(run_input={
    "packages": ["requests", "pandas"],
    "reports": ["daily", "pythonMajor"],
    "days": 30,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with Apify MCP

Add this Actor as a tool in Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/pypi-package-download-stats"
```

#### Claude Desktop

Add this server in Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/pypi-package-download-stats"
    }
  }
}
```

#### Cursor

Use the same JSON under Cursor **Settings → MCP**, then enable the `apify` server.

#### VS Code

Add the same HTTP server URL to your VS Code MCP configuration and start the `apify` server from the MCP tools view.

Example prompts:

- “Fetch 30 days of daily download statistics for requests, httpx, and aiohttp.”
- “Compare Python minor-version usage for pandas and polars over the latest 60 dates.”
- “Run my PyPI dependency monitoring task and summarize changes from the previous dataset.”

### Reliability and retries

The Actor queries ClickPy's public read-only ClickHouse service over pre-aggregated tables sourced from official PyPI download logs. It retries temporary throttling, server errors, timeouts, and network failures with bounded backoff; no proxy or browser is required.

It does not hide a failed statistics fetch as an empty successful result. If optional PyPI metadata is unavailable but statistics work, rows are still emitted with nullable metadata.

### Limits and data interpretation

- The Actor accepts exact names; it does not search PyPI by keyword.
- Public download data is aggregated and can be delayed or revised.
- Download counts are not equivalent to unique people, production installations, or revenue.
- CI systems, caches, mirrors, bots, and repeated installs can affect totals.
- Python-version categories depend on installer metadata observed by the source.
- PyPI no longer exposes trustworthy download counts by individual package release through this route; `currentVersion` is identity context, not a per-release download statistic.
- The maximum supported history is the latest 180 dates exposed by the public ClickPy dataset.
- The Actor does not send alerts or calculate change percentages itself; use schedules and downstream comparison for those jobs.

### Legality and responsible use

The Actor reads anonymous public aggregate statistics and public package metadata. Follow the source's terms, attribution guidance, and request etiquette. Do not use aggregate download counts to identify individuals or make unsupported claims about specific organizations. Apply appropriate review before using popularity signals in security, procurement, or governance decisions.

### Troubleshooting

#### Why did the run fail with a throttling message?

A shared public statistics endpoint may be temporarily busy. The Actor already applies bounded retries. Wait before starting another run, reduce the number of packages or reports, and avoid launching many parallel Tasks against the same source.

#### Why is the newest date not today?

PyPI download statistics are processed in batches. `days` selects the latest available source dates and does not manufacture missing dates.

#### Why are there many Python-version rows?

Each date can contain several runtime categories. Lower `days`, choose only `pythonMajor`, or reduce `maxRows` when you need a smaller dataset.

#### Why is `currentVersion` null?

The metadata enrichment request can fail while the statistics endpoint succeeds. Package statistics remain useful and retain the requested package name.

#### Does `includeMirrors` affect Python-version rows?

No. It selects the daily overall mirror category. Version reports use the categories returned by their dedicated endpoints.

### FAQ

#### Can I monitor multiple packages?

Yes. Supply up to 20 unique exact package names. Runs process them sequentially to respect public endpoint etiquette.

#### Can I get weekly and monthly history rows?

The summary includes recent one-week and one-month totals. Timestamped history is daily; aggregate it downstream into calendar weeks or months when needed.

#### Can I get downloads by package release version?

No. The Actor exports Python interpreter-version breakdowns, not download counts for each package release. `currentVersion` reports the current PyPI release only.

#### Does it require a PyPI token?

No. Both data sources used by the Actor are anonymous public endpoints.

#### Can I use the results in a recurring workflow?

Yes. Run the same input on an Apify Schedule and persist or compare the resulting datasets in your destination system.

### Related automation-lab Actors

- [Artifact Hub Packages Scraper](https://apify.com/automation-lab/artifact-hub-packages-scraper) for cloud-native package metadata.
- [npm Package Intelligence Scraper](https://apify.com/automation-lab/npm-package-intelligence-scraper) for npm metadata and ecosystem signals.

These tools cover different sources and should not be treated as substitutes for PyPI's aggregate download statistics.

### Support

For reproducible support requests, include the Actor run URL, redacted input, package names, selected reports, and the first relevant error message. Do not post your Apify token or other credentials.

# Actor input Schema

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

One to 20 exact package names, such as requests, pandas, or fastapi.

## `reports` (type: `array`):

Choose the timestamped breakdowns to include. Every package also gets one recent-totals summary row.

## `days` (type: `integer`):

Keep the latest 1–180 available dates in each timestamped report.

## `includeMirrors` (type: `boolean`):

Include downloads reported by package mirrors in daily totals. Python-version reports are not split by mirror status.

## `maxRows` (type: `integer`):

Stop after this many summary and timestamped rows across all packages.

## Actor input object example

```json
{
  "packages": [
    "requests",
    "pandas",
    "fastapi"
  ],
  "reports": [
    "daily",
    "pythonMajor"
  ],
  "days": 30,
  "includeMirrors": false,
  "maxRows": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

Open normalized summary and timestamped breakdown rows in the overview table.

# 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": [
        "requests",
        "pandas",
        "fastapi"
    ],
    "reports": [
        "daily",
        "pythonMajor"
    ],
    "days": 30,
    "includeMirrors": false,
    "maxRows": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/pypi-package-download-stats").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": [
        "requests",
        "pandas",
        "fastapi",
    ],
    "reports": [
        "daily",
        "pythonMajor",
    ],
    "days": 30,
    "includeMirrors": False,
    "maxRows": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/pypi-package-download-stats").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": [
    "requests",
    "pandas",
    "fastapi"
  ],
  "reports": [
    "daily",
    "pythonMajor"
  ],
  "days": 30,
  "includeMirrors": false,
  "maxRows": 20
}' |
apify call automation-lab/pypi-package-download-stats --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/pypi-package-download-stats"
        }
    }
}
```

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/pAkxCKQ9bDHfTgAP7/builds/NGdvN4pOPJSgWdGyi/openapi.json
