PyPI Package Stats & Metadata
Pricing
$0.40 / 1,000 packages
PyPI Package Stats & Metadata
PyPI package scraper for Python dependency research. Export versions, dependencies, release history and project links as JSON, with optional recent download counts.
Pricing
$0.40 / 1,000 packages
Rating
0.0
(0)
Developer
Grit
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 days ago
Last modified
Categories
Share
PyPI packages scraper returns Python package metadata and optional recent download counts. PyPI API results include versions, dependencies, release history, project links, and timestamps for collected data.
Input example
{"packages": ["sampleproject"],"maxItems": 1,"includeDownloads": false}
The input keys and allowed values follow .actor/input_schema.json.
Output fields
| Field | Type | Example or excerpt from sample |
|---|---|---|
input | string | "sampleproject" |
package | string | "sampleproject" |
status | string | "ok" |
collected_at | string | "2026-10-05T12:07:09.388032Z" |
downloads_status | string | "ok" |
downloads_fetched_at | string | "2026-10-05T12:01:02.242673Z" |
downloads_cached | boolean | true |
downloads_last_day | integer | 16511 |
downloads_last_week | integer | 117011 |
downloads_last_month | integer | 491628 |
errors | array | [] |
warnings | array | [] |
name | string | "sampleproject" |
version | string | "4.0.0" |
summary | string | "A sample Python project" |
description | string | "# A sample Python project\n\n![Python Logo](https://www.python.org/static/community_… |
description_content_type | string | "text/markdown" |
license | string | "BSD-3-Clause" |
license_expression | string or null | null |
license_classifiers | array | ["License :: OSI Approved :: MIT License"] |
requires_python | string | ">=3.9" |
requires_dist | array | ["peppercorn", "check-manifest; extra == \"dev\"", "coverage; extra == \"test\""] |
provides_extra | array | ["dev", "test"] |
project_urls | object | {"Bug Reports": "https://github.com/pypa/sampleproject/issues", "Funding": "https://d… |
home_page | string or null | null |
keywords | string or null | "sample, setuptools, development" |
classifiers | array | ["Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OS… |
yanked | boolean | false |
yanked_reason | string or null | null |
first_release_date | string | "2015-06-14T14:37:56.383366Z" |
latest_release_date | string | "2024-11-06T22:37:09.220617Z" |
release_count | integer | 7 |
releases | array | [{"version": "4.0.0", "released_at": "2024-11-06T22:37:09.220617Z", "file_count": 2, … |
pypi_url | string | "https://pypi.org/project/sampleproject/" |
metadata_source_url | string | "https://pypi.org/pypi/sampleproject/json" |
downloads_source_url | string | "https://pypistats.org/api/packages/sampleproject/recent" |
Output example
Trimmed from sample_output.json; omitted fields remain available in the dataset.
{"input": "sampleproject","package": "sampleproject","status": "ok","collected_at": "2026-10-05T12:07:09.388032Z","downloads_status": "ok","downloads_fetched_at": "2026-10-05T12:01:02.242673Z","downloads_cached": true,"name": "sampleproject"}
Limits and source behavior
maxItemsdefaults to 20 and accepts 1–500. It caps the entire dataset, including error rows.concurrencydefaults to 3 and accepts 1–10. Downloads remain serialized with at leastdownloadIntervalSecsbetween network calls; that setting defaults to 2 and accepts 2–60 seconds.- Successful recent-download responses are cached for the current UTC day in the named
pypi-package-stats-cachekey-value store. This allows runs using the same account/storage namespace to reuse counts.downloads_fetched_atpreserves the original fetch time; it is not the source's last update time. - PyPIStats updates daily and applies IP-based limits. HTTP 429 pauses further stats calls for that run and persists a cooldown of at least 60 seconds or the supplied
Retry-After, whichever is longer. Metadata remains available. Parallel runs sharing an IP can still be limited; the spacing control coordinates one run only. - Transient network errors and selected server errors get at most three attempts with exponential backoff. PyPI retries respect
Retry-After; waits longer than 120 seconds become an error row. A 404 is not retried. - Name search downloads the full simple-index name list before selecting bounded matches. Use explicit names for routine monitoring; allow more memory for large-index searches.
- Release dates use the first surviving file's
upload_time_iso_8601. Empty/deleted releases have a null date. The project'sreleaseskey is deprecated by PyPI; if it disappears, history is empty and a warning is returned. - Download counts describe downloads, not unique users. Publisher-supplied licenses and requirements are not independently audited. Null means unavailable, not zero.
- Spending limits stop further saving after the last affordable result. Already running metadata requests can finish before their results are discarded. The run summary includes exact charged USD and budget status.
FAQ
What are the output limits? maxItems caps output, including errors. Package search matches names and loads the simple index; explicit names are preferable for routine monitoring.
Do I need a proxy or login? Public PyPI and PyPIStats endpoints need no login or proxy.
How is this priced? Proposed pay per event: $0.0004 for each saved package metadata row, including results with unavailable optional downloads. Input and metadata errors are uncharged. These are proposals in PRICING.md; the owner must configure Store billing.
How are rate limits handled? Download lookups are spaced by downloadIntervalSecs; HTTP 429 pauses PyPIStats calls for the run and records a cooldown.
How fresh is the data? PyPI metadata can change. collected_at marks collection, while downloads_fetched_at marks the optional PyPIStats lookup. Download counts are not unique users; publisher supplied metadata is not independently audited.
Use with AI agents / MCP
After the actor is published, connect your agent to the Apify MCP server with an Apify API token. Use call-actor with the published actor identifier and the JSON input shown above. Read the returned dataset with get-dataset-items; the run response itself contains status and storage IDs, not the result rows. Alternatively, use the Apify API to start a run and read its default dataset. Keep the actor input bounded with maxItems, and inspect source links and any error fields before using results in an answer.