Last month, a popular npm package with 10M+ weekly downloads got compromised. Teams scrambled to check if their projects were affected. Most used npm audit — but that only catches known vulnerabilities in your lockfile.
What if you could programmatically check ANY package for security issues, track its download trends, and monitor its dependency chain — all through free APIs? You can.
Here are 4 npm-related APIs that most developers don't know exist.
1. npm Registry API — Package Metadata Without Auth
The npm registry itself is a CouchDB instance with a public REST API:
// Get full package metadata
const response = await fetch('https://registry.npmjs.org/express');
const data = await response.json();
console.log(`Latest version: ${data['dist-tags'].latest}`);
console.log(`Total versions: ${Object.keys(data.versions).length}`);
console.log(`License: ${data.license}`);
console.log(`Weekly downloads: check api.npmjs.org`);
No API key. No rate limits (be polite). JSON response.
What you can extract:
- Every version ever published
- All dependencies and devDependencies for each version
- Maintainers and their emails
- Repository URL, homepage, bugs URL
- Publish dates for every version
2. npm Downloads API — Track Popularity Trends
// Daily downloads for last month
const res = await fetch('https://api.npmjs.org/downloads/point/last-month/express');
const data = await res.json();
console.log(`${data.package}: ${data.downloads.toLocaleString()} downloads last month`);
// Compare packages
const packages = ['express', 'fastify', 'koa', 'hapi'];
for (const pkg of packages) {
const r = await fetch(`https://api.npmjs.org/downloads/point/last-month/${pkg}`);
const d = await r.json();
console.log(`${pkg}: ${d.downloads.toLocaleString()}`);
}
// express: 35,234,567
// fastify: 4,891,234
// koa: 1,234,567
// hapi: 456,789
Range queries:
// Downloads per day for a specific range
const url = 'https://api.npmjs.org/downloads/range/2025-01-01:2025-03-24/react';
const res = await fetch(url);
const data = await res.json();
// Plot the trend
data.downloads.forEach(d => {
const bar = '#'.repeat(Math.floor(d.downloads / 500000));
console.log(`${d.day} | ${bar} ${d.downloads.toLocaleString()}`);
});
3. GitHub Advisory Database API — Security Vulnerabilities
GitHub maintains a free, public advisory database for npm packages:
// Search advisories for a package
const query = `
{
securityAdvisories(first: 5, orderBy: {field: PUBLISHED_AT, direction: DESC}, ecosystem: NPM) {
nodes {
summary
severity
publishedAt
vulnerabilities(first: 3) {
nodes {
package { name }
vulnerableVersionRange
firstPatchedVersion { identifier }
}
}
}
}
}`;
// Use via GitHub GraphQL API (needs token for GraphQL, but REST is free)
// Or use the REST endpoint:
const res = await fetch('https://api.github.com/advisories?ecosystem=npm&per_page=5');
const advisories = await res.json();
advisories.forEach(a => {
console.log(`[${a.severity}] ${a.summary}`);
console.log(` Published: ${a.published_at}`);
});
4. Bundlephobia API — Check Package Size
// How much will this package add to your bundle?
const res = await fetch('https://bundlephobia.com/api/size?package=lodash@latest');
const data = await res.json();
console.log(`${data.name}@${data.version}`);
console.log(` Size: ${(data.size / 1024).toFixed(1)} KB`);
console.log(` Gzipped: ${(data.gzip / 1024).toFixed(1)} KB`);
console.log(` Download time (3G): ${data.downloadTime}ms`);
Compare alternatives:
const alternatives = ['lodash', 'underscore', 'ramda', 'remeda'];
for (const pkg of alternatives) {
const r = await fetch(`https://bundlephobia.com/api/size?package=${pkg}@latest`);
const d = await r.json();
console.log(`${pkg}: ${(d.gzip / 1024).toFixed(1)} KB gzipped`);
}
// lodash: 25.2 KB
// underscore: 7.1 KB
// ramda: 12.4 KB
// remeda: 5.8 KB
Putting It All Together: Package Health Check
async function packageHealthCheck(name) {
console.log(`\n=== Health Check: ${name} ===\n`);
// 1. Basic metadata
const meta = await (await fetch(`https://registry.npmjs.org/${name}`)).json();
const latest = meta['dist-tags'].latest;
console.log(`Latest: ${latest}`);
console.log(`Versions: ${Object.keys(meta.versions).length}`);
console.log(`License: ${meta.license}`);
// 2. Downloads
const dl = await (await fetch(`https://api.npmjs.org/downloads/point/last-month/${name}`)).json();
console.log(`Downloads/month: ${dl.downloads.toLocaleString()}`);
// 3. Bundle size
try {
const size = await (await fetch(`https://bundlephobia.com/api/size?package=${name}@latest`)).json();
console.log(`Bundle size: ${(size.gzip / 1024).toFixed(1)} KB gzipped`);
} catch(e) {
console.log('Bundle size: N/A');
}
// 4. Dependencies count
const deps = meta.versions[latest].dependencies || {};
console.log(`Dependencies: ${Object.keys(deps).length}`);
// 5. Last publish date
const time = meta.time[latest];
const daysSince = Math.floor((Date.now() - new Date(time)) / 86400000);
console.log(`Last published: ${time.split('T')[0]} (${daysSince} days ago)`);
if (daysSince > 365) console.log(' ⚠️ WARNING: Not updated in over a year');
if (Object.keys(deps).length > 20) console.log(' ⚠️ WARNING: Heavy dependency tree');
}
packageHealthCheck('express');
API Reference
| API | Base URL | Auth | Use case |
|---|---|---|---|
| npm Registry | registry.npmjs.org |
None | Package metadata, versions, deps |
| npm Downloads | api.npmjs.org |
None | Download counts, trends |
| GitHub Advisories | api.github.com/advisories |
None (REST) | Security vulnerabilities |
| Bundlephobia | bundlephobia.com/api |
None | Bundle size analysis |
When These APIs Are Not Enough
- Private packages: Need npm token for private registry
- Real-time malware detection: Use Socket.dev or Snyk
License compliance: Use FOSSA for enterprise-grade scanning
- NASA Has 5 Free APIs — asteroids, Mars photos, space weather
Do you check your dependencies before installing? What tools do you use? I am curious what the community's stack looks like for supply chain security.
More free tools: 77 Web Scraping Tools & APIs
Have you ever found a vulnerable package in your project? Share your story — the scariest dependency vulnerability you caught. 👇
Top comments (0)