# NuGet v3 Feed Extractor (`datamule/nuget-v3-feed-extractor`) Actor

Point at any NuGet v3 service index (nuget.org, Azure Artifacts, MyGet, GitLab, self-hosted BaGet/Gitea) and get one structured row per package: version, downloads, tags, license, authors.

- **URL**: https://apify.com/datamule/nuget-v3-feed-extractor.md
- **Developed by:** [Datamule](https://apify.com/datamule) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## NuGet v3 Feed Extractor

Point at **any NuGet v3 service index** and export its packages as a clean,
structured dataset — one row per package, straight from the feed's own
self-describing v3 API.

The NuGet v3 protocol is **self-describing**: a feed's service `index.json`
advertises its capabilities as a list of resources keyed by `@type`
(`SearchQueryService`, `RegistrationsBaseUrl`, `PackageBaseAddress`, …). This
actor *resolves* the feed's own advertised search endpoint and queries it, so
**one actor works against every v3 feed in existence** — no per-host scraper, no
hardcoded endpoints.

Unlike the nuget.org-only scrapers, this runner points at **any** v3 feed:

- **nuget.org** — the central public registry (450k+ packages)
- **Azure Artifacts** — Azure DevOps package feeds
- **GitLab** — the GitLab package registry
- **MyGet**, **JFrog Artifactory**, **Sonatype Nexus**
- **self-hosted** BaGet / Gitea / Forgejo package registries

### Modes

The run mode is auto-selected from the input fields you set:

| mode | when | emits |
|------|------|-------|
| **search** | `query` is set | one row per package matching the search |
| **list** *(default)* | `query` is empty | one row per package the feed returns for an empty query |
| **discovery** | `discoveryOnly: true` | a single row describing the feed — advertised services, resource count, resolved search URL, total package count |

### Input

```json
{
  "indexUrl": "https://api.nuget.org/v3/index.json",
  "query": "json",
  "prerelease": true,
  "maxRecords": 100
}
```

- **`indexUrl`** *(required)* — the v3 service index URL. Examples:
  `https://api.nuget.org/v3/index.json`,
  `https://www.myget.org/F/nunit/api/v3/index.json`.
- **`query`** — search term. Leave empty for **list** mode (all packages).
- **`prerelease`** — include beta/rc/alpha versions (bool).
- **`packageType`** — optional type filter (`Dependency`, `DotnetTool`,
  `Template`, …) — honoured by feeds that implement it.
- **`discoveryOnly`** — describe the feed only (one row).
- **`maxRecords`** — global cap; pagination stops when reached. Leave empty for
  everything.
- **`apiKey`** / **`extraHeaders`** — optional auth for private feeds (sent as
  `X-NuGet-ApiKey` / raw headers). Never required for public feeds, never logged.

### Output

One flat, fully-nullable row per package:

| field | example |
|-------|---------|
| `packageId` | `Newtonsoft.Json` |
| `latestVersion` | `13.0.5-beta1` |
| `title` / `description` / `summary` | `Json.NET` / … |
| `authors` / `owners` | `James Newton-King` |
| `tags` | `["json"]` |
| `totalDownloads` | `8621110743` |
| `verified` | `true` |
| `versionCount` | `54` |
| `projectUrl` / `licenseUrl` / `iconUrl` | … |
| `packageTypes` | `["Dependency"]` |
| `latestVersionUrl` / `registrationUrl` | … |
| `_indexUrl` / `_searchUrl` / `_totalHits` | feed + resolved-search metadata |
| `_raw` | the lossless original search entry |

Every optional field is nullable and read by key presence, so a feed that
spells `totalDownloads` differently (nuget.org `totalDownloads` vs MyGet
`totaldownloads`) or omits `iconUrl`/`tags` never drops data or crashes — it
just yields `null` for that column.

### Behaviour

- A body that is **not** a v3 service index (HTML, 404 text, JSON without a
  `resources` list) fails fast with a clear message.
- A feed that advertises **no** `SearchQueryService` fails fast honestly in
  search/list mode (discovery mode still reports what it *does* support).
- An empty result is 0 records and a clean exit — never a crash.
- Transient `5xx` / `429` responses are retried with backoff (honours
  `Retry-After`).

### Pricing

Pay-per-event: one **record** event per package row returned.

# Actor input Schema

## `indexUrl` (type: `string`):

URL of a NuGet v3 service index (index.json). The v3 protocol is self-describing: the index advertises the feed's own search endpoint, so ONE actor works against any v3 feed — nuget.org (the central registry), Azure Artifacts, the GitLab package registry, MyGet, JFrog Artifactory, or a self-hosted BaGet / Gitea / Forgejo package registry. Examples: https://api.nuget.org/v3/index.json or https://www.myget.org/F/nunit/api/v3/index.json . The run MODE is chosen automatically from the other fields you set (see below).

## `query` (type: `string`):

SEARCH MODE. A package search term matched against package id / title / description / tags via the feed's advertised SearchQueryService. Leave EMPTY to run LIST MODE (every package the feed returns for an empty query). Set discoveryOnly instead to just inspect the feed.

## `prerelease` (type: `boolean`):

When true, prerelease (beta/rc/alpha) package versions are included in the results. When false, only stable releases. Passed through to the feed's search endpoint. Leave unset for the feed's own default.

## `packageType` (type: `string`):

Optional package-type filter passed through to the feed (e.g. Dependency, DotnetTool, Template, DotnetPlatform). Only feeds that implement the SearchQueryService/3.5.0 packageType parameter honour it; others ignore it. Leave empty for all package types.

## `discoveryOnly` (type: `boolean`):

DISCOVERY MODE. When true, the actor resolves the service index and runs one tiny probe, then emits a SINGLE row describing the feed itself: which services it advertises (@types), how many resources, the resolved search URL, whether search works, and the total package count. A cheap way to check what any v3 feed supports before a full run.

## `maxRecords` (type: `integer`):

A GLOBAL cap on the number of package rows to emit (each row is one package and one billable event). Pagination stops as soon as the cap is reached, so a small value is a cheap, deterministic sample. Leave empty to fetch every matching package — a broad query on nuget.org (450k+ packages) can return a very large set.

## `apiKey` (type: `string`):

Optional API key for a private / registration-required feed (sent as the X-NuGet-ApiKey header). Not required for public feeds. Never logged.

## `extraHeaders` (type: `object`):

Optional extra HTTP headers as a JSON object, e.g. {"Authorization": "Bearer ..."} for a gated Azure Artifacts / GitLab feed. Not required for public feeds. Header values are never logged.

## Actor input object example

```json
{
  "indexUrl": "https://api.nuget.org/v3/index.json"
}
```

# Actor output Schema

## `results` (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 = {
    "indexUrl": "https://api.nuget.org/v3/index.json"
};

// Run the Actor and wait for it to finish
const run = await client.actor("datamule/nuget-v3-feed-extractor").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 = { "indexUrl": "https://api.nuget.org/v3/index.json" }

# Run the Actor and wait for it to finish
run = client.actor("datamule/nuget-v3-feed-extractor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "indexUrl": "https://api.nuget.org/v3/index.json"
}' |
apify call datamule/nuget-v3-feed-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=datamule/nuget-v3-feed-extractor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jRwnx50KIqBj9Qc30/builds/8ekdR3nr9v8BWv3tF/openapi.json
