npm Package Health Score API — Dependency Risk Scorer avatar

npm Package Health Score API — Dependency Risk Scorer

Pricing

from $3.30 / 1,000 results

Go to Apify Store
npm Package Health Score API — Dependency Risk Scorer

npm Package Health Score API — Dependency Risk Scorer

npm package health score API. Rate any npm dependency 0-100 with a letter grade from keyless public signals: downloads, release recency & cadence, maintainers, license, deprecation, deps. One row per package with top risks. Keyless. A clean MCP tool for AI coding agents.

Pricing

from $3.30 / 1,000 results

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

3 days ago

Last modified

Share

Score the health of any npm package from 0 to 100 with a letter grade, using only keyless, public signals — download volume and momentum, release recency and cadence, maintainer bus factor, license, version maturity, dependency surface, plus SLSA build provenance, registry signatures and install-script detection. Give it a list of package names and get back one clean, structured row per package so engineers and AI coding agents can decide whether a dependency is safe to adopt.

No API key. No login. No GitHub token required.

Who it's for

  • Engineering leads vetting a dependency before it enters the tree.
  • DevSecOps / AppSec teams triaging supply-chain risk across a lockfile.
  • OSPO and procurement teams assessing license and maintenance posture.
  • AI coding agents that need an "is this package safe to add?" tool.

What it does

  1. Runs a live drift check before anything is billed — a popularity canary, a document-shape check, and a negative control (a name that cannot exist must return 404). If npm's downloads API starts answering zero, the run fails rather than silently re-grading every package.
  2. Fetches the registry document and the 30-day download series, each with three attempts and backoff.
  3. Scores eight weighted inputs into a 0–100 composite and an A–F grade.
  4. Surfaces the supply-chain signals already inside the registry document: SLSA provenance, registry signature, install scripts, bundled types, engine range, repository, package age, total versions, and the deprecation reason.

How a failure is reported — read this before you trust a score

A score is only as good as its inputs, and a missing input changes the answer. Measured live on 2026-08-01: express scores 87 (grade A) with real download data and 59 (grade C) when api.npmjs.org does not answer — a two-grade swing, with the row publishing downloads_last_month: 0 and the rationale "Low adoption: 0 downloads/month" about a package doing 505,265,187 downloads a month.

So this actor distinguishes three states on every numeric input:

ValueMeaning
A numberFetched and real.
0The source answered, and the answer is zero.
nullNot fetched. Never read this as zero.
  • downloads_status is ok, no_data (HTTP 404 — npm holds no download record, so 0 is a genuine answer), or unavailable (the API did not answer after three attempts, so downloads_last_month is null).
  • registry_status is ok, not_found (HTTP 404 — a verified negative: the package does not exist), or unavailable.
  • health_score is published only when every weighted input was obtained. Otherwise it is null, score_status is "partial", score_inputs_missing names exactly what is missing, and health_score_partial carries the score renormalized over the weight that was evaluable.
  • maintainers, dependencies_count and deprecated are null when the registry document could not be read — not 0, 0 and false. (Previously an unread version object scored full marks for "Zero runtime dependencies".)
  • If every package lookup fails, the run fails and emits nothing.

Example input

{
"packages": ["express", "left-pad", "@babel/core"],
"includeTrend": true
}

Scoped packages are supported. You can also pass a single package string, or a comma/space-separated list.

Output fields

FieldDescription
packageThe package name as requested.
latest_versionVersion on the latest dist-tag.
health_score0–100 composite. null when any weighted input was unavailable.
gradeA (≥85), B (≥70), C (≥55), D (≥40), F, or N/A.
health_score_partialThe score renormalized over the inputs that were obtained. Not comparable with a complete health_score.
score_statuscomplete, partial, or unavailable.
score_inputs_missingWhich weighted inputs could not be obtained.
score_weight_evaluated_pctShare of the 100-point weight model actually evaluated.
sub_scoresThe eight 0–100 sub-scores. A sub-score is null when its input was missing.
last_publish_datePublish date of the latest version.
days_since_publishDays since that publish.
publishes_last_2yReleases in the last 730 days (the cadence input).
publishes_last_1yReleases in the last 365 days.
downloads_last_month30-day download total. null when the API did not answer.
download_trend_pctMomentum: second half of the window vs the first.
maintainersMaintainer count (bus factor). null when the document was unreadable.
licenseDeclared license string.
deprecatedtrue / false / null.
deprecated_messageThe reason npm publishes, e.g. "use String.prototype.padStart()".
dependencies_countRuntime dependencies on the latest version.
dev_dependencies_countDeclared devDependencies.
top_risksRanked plain-language risks. Never asserts anything that was not measured.
supply_chain_risksInstall scripts, missing provenance, missing signature, no repository, deprecation. Kept separate from top_risks.
rationaleOne-paragraph summary of positives and risks.
package_age_daysDays since the first ever publish.
first_publish_dateDate of the first ever publish.
total_versionsVersions the registry holds.
dist_tagsAll dist-tags, sorted.
has_prerelease_tagTrue when tags other than latest exist (next, beta, latest-4, …).
repository_urlSource repository, normalized to a browsable https URL.
homepageDeclared package homepage.
bugs_urlDeclared issue tracker.
descriptionPackage description.
keywordsPackage keywords.
unpacked_size_bytesInstalled size of the latest tarball.
file_countFiles in the published tarball.
tarball_urlRegistry tarball URL.
has_provenanceSLSA build-provenance attestation — the strongest published supply-chain trust signal.
has_registry_signaturenpm registry signature on the tarball.
has_install_scriptArbitrary code runs on npm install.
has_typesShips bundled TypeScript definitions.
engines_nodeDeclared supported Node range.
has_fundingA funding target is declared.
last_publishernpm account that published the latest version.
npm_starsUsers who have starred the package.
registry_statusok, not_found, or unavailable.
registry_errorThe transport error behind unavailable.
downloads_statusok, no_data, or unavailable.
downloads_errorThe transport error behind unavailable.
row_partialTrue when any source did not answer for this package.
errorPresent on a not-found or failed row.
source_urlnpmjs.com page for the package.
retrieved_atISO timestamp of the lookup.

Populating the optional columns. deprecated_message populates for a deprecated package — the prefill (express, left-pad) exercises it, since left-pad is deprecated with "use String.prototype.padStart()". has_provenance is true for packages published with SLSA attestations (@babel/core as of 2026-08-01) and false for express. engines_node, has_funding and has_types vary by package; the three-package example above covers all of them. registry_error, downloads_error and error are null on a healthy run — that is good news, not a dead column.

Scoring model (weights sum to 100)

InputWeightNotes
Download volume25log-scaled; 10M/month saturates.
Release recency20≤30 days = 100, ≥730 days = 0.
Release cadence15~8 releases in 2 years saturates.
Download trend10Second half of the 30-day window vs the first.
Maintainer count10Bus factor: 1 → 50, 2 → 75, 3+ → 100.
License10Permissive 100, copyleft 60, other 50, none 0.
Version maturity5≥1.0.0 → 100.
Dependency count50 deps → 100, −5 per dep.

A deprecated package is capped at 20 regardless of the other inputs. The weights are unchanged, so scores remain comparable with earlier runs.

Use as an MCP tool

Exposed to AI coding agents via mcp.apify.com as a "score this npm package" tool. The three-state contract matters here: an agent must not read downloads_last_month: null as zero adoption, or health_score: null as a bad score. Check score_status first.

FAQ

Are scores comparable between runs? Yes — the weights have not changed. Only compare health_score values carrying score_status: "complete".

Why is health_score sometimes null? Because a weighted input could not be fetched. Use health_score_partial together with score_weight_evaluated_pct for a labelled approximation.

Does it detect a typo'd package name? Yes — registry_status: "not_found" with health_score: null, which is a verified negative rather than a low score. A live negative control also fails the run if the registry ever starts returning 200 for names that do not exist.

Is this a determination? No. It is a screening tool over public registry signals. It does not audit code, run tests, or evaluate transitive risk.

Data sources (keyless, no anti-bot)

  • https://registry.npmjs.org/<package> — the full packument.
  • https://api.npmjs.org/downloads/range/last-month/<package> — daily downloads.

Pricing (Pay Per Result)

Billed per dataset record returned: one row per package, including rows for packages that do not exist (a verified negative is an answer). Runs that fail a drift assertion, or lose every lookup, emit nothing and bill nothing.

  • SBOM Vulnerability Scanner — scan a whole lockfile against OSV.dev and the CISA KEV catalog, then score the flagged packages here.