npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

astro-pkg-stats

v0.1.0

Published

Astro component and helpers that show npm and Packagist (Composer/Laravel) download statistics for your packages.

Readme

astro-pkg-stats

An Astro component (plus plain TypeScript helpers) that shows download statistics for packages you publish — on npm and on Packagist (the PHP/Composer registry Laravel packages use).

Give it your npm username and/or Packagist vendor name and it automatically finds every package you publish, fetches download counts, and renders a ready-made stats widget. No API keys, no manual package lists required (though you can add one if you want).

Features

  • Two ecosystems, one widget — npm and Packagist stats side by side, merged into one ranked table.
  • Multiple accounts supported — track more than one npm username and/or more than one Packagist vendor at once (see Multiple accounts).
  • Auto-discovery — pass a username/vendor and every package under it is found automatically; you never have to keep a package list up to date by hand.
  • No API keys — both npm's and Packagist's public stats endpoints are open and free to use.
  • Works with any rendering mode — data is fetched server-side in the component's frontmatter, so it works with static builds, SSR, and hybrid rendering alike.
  • Cached to disk — repeated builds and astro dev reloads reuse the same data for an hour by default instead of re-fetching every time (see Caching).
  • Light/dark aware — the component's built-in styles follow prefers-color-scheme and a data-theme toggle automatically.
  • Astro 4–7 supported.

Install

npm install astro-pkg-stats

Quick start

---
import { PackageStats } from "astro-pkg-stats";
---

<PackageStats
  title="My downloads"
  npm={{ username: "your-npm-username" }}
  packagist={{ vendor: "your-packagist-vendor" }}
/>

You can use either source alone — drop npm or packagist entirely if you don't publish there.

Props

| Prop | Type | Description | | ----------- | ------------------------------------------------------------ | ---------------------------------------------------------------- | | title | string | Heading text. Default: "Package downloads". | | class | string | Extra class(es) on the root <section>. | | npm | { username?: string \| string[]; packages?: string[] } | npm account(s) and/or explicit package names to include. | | packagist | { vendor?: string \| string[]; packages?: string[] } | Packagist vendor(s) and/or explicit vendor/package names. | | cache | false \| { ttl?: number; dir?: string } | Cache tuning — see Caching. |

Multiple accounts and vendors

username and vendor each accept either a single string or an array of strings. This is for people who publish under more than one npm account (a personal account plus an org/team account, say) or more than one Packagist vendor namespace — everything gets merged into a single, deduped, ranked table:

<PackageStats
  title="My downloads"
  npm={{ username: ["your-personal-npm-username", "your-org-npm-username"] }}
  packagist={{ vendor: ["your-personal-vendor", "your-company-vendor"] }}
/>

All usernames/vendors are looked up in parallel, so adding more of them doesn't meaningfully slow down the fetch. Duplicate package names (e.g. if the same package somehow turns up under two lookups) are only counted once.

Explicit package lists

You can also list exact package names, in addition to or instead of a username/vendor — useful for including someone else's package you care about, or a package that isn't under your main account/vendor namespace:

<PackageStats
  npm={{
    username: "your-npm-username",
    packages: ["some-other-persons-package"],
  }}
  packagist={{
    packages: ["vendor/a-package-not-under-your-vendor"],
  }}
/>

packages works fine on its own too, with no username/vendor at all, if you'd rather curate the exact list yourself.

Using the data yourself

Everything the component uses is also exported directly, if you want to build your own UI or use the numbers outside of Astro templates:

import { getPackageStats } from "astro-pkg-stats";

const { packages, totals } = await getPackageStats({
  npm: { username: ["your-npm-username", "your-org-username"] },
  packagist: { vendor: "your-packagist-vendor" },
});

// packages: PackageStat[] — one entry per package, sorted by monthly downloads desc
// totals: { daily, weekly, monthly, total, packageCount }

Lower-level helpers are also available if you need finer control:

| Function | Purpose | | ---------------------------------- | ----------------------------------------------------------------- | | listNpmPackagesByMaintainer(username) | List package names maintained by one npm user. | | fetchNpmStats(packageNames) | Fetch daily/weekly/monthly downloads for a list of npm packages. | | listPackagistPackagesByVendor(vendor) | List vendor/package names published by one Packagist vendor. | | fetchPackagistStats(fullNames) | Fetch daily/monthly/total downloads for a list of Packagist packages. |

Caching

Every call to getPackageStats (and so every render of <PackageStats>) is cached to a JSON file under node_modules/.cache/astro-pkg-stats/, keyed by the npm usernames, Packagist vendors, and explicit package lists you passed in. By default an entry is reused for 1 hour, which means:

  • astro dev reloads reuse the same data instead of re-fetching on every save.
  • Rebuilding a static site repeatedly (e.g. in CI, or locally) only hits npm/Packagist once per hour, even across multiple usernames/vendors.

Tune or disable it per-component via the cache prop (or per-call via getPackageStats({ ..., cache })):

<!-- cache for 6 hours instead of the 1 hour default -->
<PackageStats npm={{ username: "you" }} cache={{ ttl: 6 * 60 * 60 * 1000 }} />

<!-- use a custom cache directory -->
<PackageStats npm={{ username: "you" }} cache={{ dir: "./.cache/pkg-stats" }} />

<!-- always fetch fresh, never read/write the cache -->
<PackageStats npm={{ username: "you" }} cache={false} />

ttl is in milliseconds; dir defaults to node_modules/.cache/astro-pkg-stats (relative to process.cwd()).

Forcing a refresh

The cache lives in node_modules, so a clean npm install/npm ci already clears it. To force fresh data without reinstalling, use the bundled CLI:

npx astro-pkg-stats clear
# or, equivalently:
npx astro-pkg-stats refresh

Run it, then re-run astro dev/astro build — the next fetch will hit npm/Packagist again and repopulate the cache. Add --dir <path> if you customized the cache directory via the cache.dir option:

npx astro-pkg-stats clear --dir ./.cache/pkg-stats

You can also wire it into your own scripts, e.g. in package.json:

{
  "scripts": {
    "stats:refresh": "astro-pkg-stats clear && astro build"
  }
}

How it works

  • npm: package names come from the registry search API (registry.npmjs.org/-/v1/search?text=maintainer:<username>, one request per username); download counts come from api.npmjs.org/downloads/point/<period>/..., batched in requests of up to 128 packages at a time (scoped @scope/name packages are fetched individually, since npm's bulk endpoint doesn't support them).
  • Packagist: package names come from packagist.org/packages/list.json?vendor=<vendor> (one request per vendor); download counts (daily/monthly/total) come from packagist.org/packages/<vendor>/<package>.json, one request per package.
  • Results from every source are merged into a single list, sorted by monthly downloads descending, with totals summed across everything.
  • A failed fetch (bad username, network error, etc.) is caught and shown as an inline error message in the component rather than breaking the whole page build.

Example project

See example/ for a minimal Astro site using the component. To try it locally:

npm install          # install this package's own dependencies
cd example
npm install           # installs astro-pkg-stats from the parent folder via file:..
npm run build          # or `npm run dev`

Edit example/src/pages/index.astro to point at your own npm/Packagist account(s).

License

MIT