PyPI Package Stats & Metadata avatar

PyPI Package Stats & Metadata

Pricing

$0.40 / 1,000 packages

Go to Apify Store
PyPI Package Stats & Metadata

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

Grit

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

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

FieldTypeExample or excerpt from sample
inputstring"sampleproject"
packagestring"sampleproject"
statusstring"ok"
collected_atstring"2026-10-05T12:07:09.388032Z"
downloads_statusstring"ok"
downloads_fetched_atstring"2026-10-05T12:01:02.242673Z"
downloads_cachedbooleantrue
downloads_last_dayinteger16511
downloads_last_weekinteger117011
downloads_last_monthinteger491628
errorsarray[]
warningsarray[]
namestring"sampleproject"
versionstring"4.0.0"
summarystring"A sample Python project"
descriptionstring"# A sample Python project\n\n![Python Logo](https://www.python.org/static/community_…
description_content_typestring"text/markdown"
licensestring"BSD-3-Clause"
license_expressionstring or nullnull
license_classifiersarray["License :: OSI Approved :: MIT License"]
requires_pythonstring">=3.9"
requires_distarray["peppercorn", "check-manifest; extra == \"dev\"", "coverage; extra == \"test\""]
provides_extraarray["dev", "test"]
project_urlsobject{"Bug Reports": "https://github.com/pypa/sampleproject/issues", "Funding": "https://d…
home_pagestring or nullnull
keywordsstring or null"sample, setuptools, development"
classifiersarray["Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OS…
yankedbooleanfalse
yanked_reasonstring or nullnull
first_release_datestring"2015-06-14T14:37:56.383366Z"
latest_release_datestring"2024-11-06T22:37:09.220617Z"
release_countinteger7
releasesarray[{"version": "4.0.0", "released_at": "2024-11-06T22:37:09.220617Z", "file_count": 2, …
pypi_urlstring"https://pypi.org/project/sampleproject/"
metadata_source_urlstring"https://pypi.org/pypi/sampleproject/json"
downloads_source_urlstring"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

  • maxItems defaults to 20 and accepts 1–500. It caps the entire dataset, including error rows.
  • concurrency defaults to 3 and accepts 1–10. Downloads remain serialized with at least downloadIntervalSecs between 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-cache key-value store. This allows runs using the same account/storage namespace to reuse counts. downloads_fetched_at preserves 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's releases key 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.