# npm & PyPI Package Version Check with OSV (`miacx/npm-pypi-package-version-check`) Actor

Check exact npm and PyPI package versions against registry data and OSV vulnerability IDs. Reports missing versions without installing packages.

- **URL**: https://apify.com/miacx/npm-pypi-package-version-check.md
- **Developed by:** [mia.cx](https://apify.com/miacx) (community)
- **Categories:** Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 version checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## npm & PyPI Package Version Check with OSV

Check a dependency pin before an agent writes it into a project.
Send exact npm or PyPI versions; get registry existence, deprecation, yanking and known OSV vulnerability IDs.
Packages are never installed. OSV results are evidence, not a safety verdict.
A completed check costs $0.0009, plus $0.00005 per run start at default memory.

### Try it

```json
{"items":[{"ecosystem":"npm","name":"is-number","version":"7.0.0"},{"ecosystem":"PyPI","name":"six","version":"1.17.0"}],"maxResults":100}
```

Empty input `{}` checks those same two versions. An explicit empty `items` array is invalid.
No upstream API key is needed.

### Use from an agent

Add `https://mcp.apify.com?tools=miacx/npm-pypi-package-version-check` to your MCP client and sign in to Apify.
Call the dedicated Actor tool, then use `get-dataset-items` to read the completed run's dataset.
Or set `APIFY_TOKEN` to your Apify API token and call the API:

```sh
curl --fail-with-body 'https://api.apify.com/v2/actors/miacx~npm-pypi-package-version-check/run-sync-get-dataset-items' \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"items":[{"ecosystem":"npm","name":"is-number","version":"7.0.0"},{"ecosystem":"PyPI","name":"six","version":"1.17.0"}],"maxResults":100}'
```

### What you get

The dataset contains one row per processed input item, in input order, including duplicates and failures.
Read `status` first. `ok` means the check completed; read `packageExists` and `versionExists` for its verdict.
Failed or partial checks use a machine error code as their dataset status.

Selected fields from the synthetic registry/OSV fixture in `test/core.test.ts`, replayed through the core:

```json
{
  "normalized": {"ecosystem":"npm","name":"@scope/pkg","version":"1.0.0"},
  "duplicateOf": null,
  "status": "ok",
  "code": "verified",
  "packageExists": true,
  "versionExists": true,
  "latestStable": "1.0.0",
  "deprecated": null,
  "yanked": null,
  "vulnerabilities": {
    "status": "ok",
    "code": "known_vulnerabilities",
    "sourceUrl": "https://api.osv.dev/v1/querybatch",
    "fetchedAt": "1970-01-01T00:00:00.000Z",
    "ids": ["GHSA-fixture"]
  }
}
```

The fixture package, advisory ID and fixed clock are test data, not a live package check.
Rows also contain the original `input` and registry evidence with `status`, `code`, `sourceUrl` and `fetchedAt`.

`packageExists` and `versionExists` are null when the registry verdict is unknown.
`latestStable` is the registry-advertised latest version, only when stable; it is null otherwise.
`deprecated` is the requested npm version's message, capped at 500 characters, or null when absent or unavailable.

PyPI `yanked` contains `state` (`none`, `partial`, `all` or `no_files`) and up to five distinct reasons.
A release with no files still exists in metadata. Missing releases and npm rows have `yanked: null`.

OSV `ids` are unique and sorted. An empty array means a completed lookup found no known IDs.
Null means unavailable or not queried; missing versions do not trigger OSV requests. Advisory details are not fetched.
`duplicateOf` points to the first equivalent row using a zero-based index.
The key-value store's `OUTPUT` report retains the core's `ok`, `partial` and `error` statuses and usage counts.

### Input

| Field | Default | Accepted input |
| --- | --- | --- |
| `items` | The two packages above | 1–100 objects containing `ecosystem`, `name` and `version`. At most 30 unique packages are fetched. |
| `items[].ecosystem` | Supply in each object | `npm` or `PyPI`, with this capitalization. |
| `items[].name` | Supply in each object | 1–214 characters. npm accepts scopes; PyPI normalizes case, dots, underscores and hyphens. |
| `items[].version` | Supply in each object | 1–128 characters. Canonical npm SemVer or exact PyPI PEP 440 version. |
| `maxResults` | `100` | 1–100. Limits the processed input prefix, further bounded by remaining charge capacity. |

npm rejects ranges, tags, shorthand and leading `v`. PyPI compares equivalent releases, including trailing zero segments.
Invalid entries return `invalid_exact_entry`. PyPI numeric components beyond JavaScript's safe integer range are unsupported.
The complete schema is [schemas/input.schema.json](schemas/input.schema.json).

### Pricing

A Version check costs $0.0009. One unique completed check counts, including a missing package or version.
Existing versions count only when the OSV lookup also completes. Partial and error rows incur no Version check events.
Equivalent duplicates share one check event within a run.

The two-package example costs $0.00185 when both checks complete, including startup.
One thousand Version checks cost $0.90, plus $0.00005 per run start at default memory.
The default memory is 256 MB. Apify counts one start event per GB of memory, with a minimum of one event.
The $0.00005 run start at default memory applies even with no billable checks.

`maxResults` and charge capacity limit the input prefix before checking.
Duplicate and invalid entries occupy prefix slots. A budget below one check event produces no rows.
A refused charge stops publication; `OUTPUT` contains only published rows.

### Limits and data freshness

- Input is capped at 32,000 encoded bytes; output at 1,000,000 bytes. Each batch has a 25-second upstream deadline.
- Registry responses allow 4,000,000 bytes each and 16,000,000 streamed bytes in total, with at most 96 request attempts.
- Metadata allows 30,000 version keys and 10,000 files per PyPI release. Large packages can fail without a per-version fallback.
- OSV allows 2,000 IDs per item, 200 characters per ID and an 8,000-byte evidence budget per row. Oversized evidence stays unknown.
- Only official npm, PyPI and OSV HTTPS endpoints are used. Redirects are refused.

Evidence is shared within a run and discarded afterwards. Later runs fetch again.
`fetchedAt` marks source response receipt, not publication or update time; failed requests have null timestamps.
No package installation, code execution, malware scan or runtime LLM call occurs.

### If a row fails

| Status or code | Next step |
| --- | --- |
| `invalid_exact_entry` | Supply a valid registry name and exact version. |
| `osv_unavailable` | Read `vulnerabilities.code`; retry later. Existing registry evidence remains available. |
| `package_limit` | Split the batch into groups of at most 30 unique packages. |
| `byte_limit`, `invalid_registry_payload`, `output_limit` | Read the source evidence; metadata or response shape exceeded supported limits. |
| `deadline`, `dns_not_found`, `network_error`, `http_429` | Retry later. A deadline can include an upstream retry delay that would exceed the run budget. |

`package_missing` and `version_missing` are completed verdicts with `status: "ok"`, not transport errors.
Use the [full output schema](schemas/output.schema.json) for the versioned report.

# Actor input Schema

## `items` (type: `array`):

Array of 1–100 objects with ecosystem, name and version, for example {"ecosystem":"npm","name":"is-number","version":"7.0.0"}. Defaults to is-number@7.0.0 and PyPI six@1.17.0. Empty arrays are invalid. At most 30 unique packages are fetched. Duplicate exact checks share evidence and one charge per run; maxResults and budget can shorten the input prefix.

## `maxResults` (type: `integer`):

Integer from 1 to 100, default 100. Processes the first N input rows, further limited by the run's remaining Version check event capacity. Duplicates and invalid entries occupy prefix slots even though they incur no check event. A budget below one event produces no rows.

## Actor input object example

```json
{
  "items": [
    {
      "ecosystem": "npm",
      "name": "is-number",
      "version": "7.0.0"
    },
    {
      "ecosystem": "PyPI",
      "name": "six",
      "version": "1.17.0"
    }
  ],
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `report` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("miacx/npm-pypi-package-version-check").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("miacx/npm-pypi-package-version-check").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call miacx/npm-pypi-package-version-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,miacx/npm-pypi-package-version-check"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ggeiNitWuzmybrt4q/builds/XV9mPzbzR6fQMdath/openapi.json
