# Maven Central Artifact Versions, Dates and Upgrade Check (`yadroo/maven-central-artifact-versions`) Actor

Java and JVM dependency checks from the official Maven Central search index: every published version with its UTC release date, the newest release derived from those dates, how old a pinned version is and how many versions it is behind. Batch coordinates, keyword, group and class search.

- **URL**: https://apify.com/yadroo/maven-central-artifact-versions.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Developer tools, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 artifact version reports

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/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

Java and JVM dependency checks from the official Maven Central search index: every published version with its UTC release date, the newest release derived from those dates, how old a pinned version is and how many versions it is behind. Batch coordinates, keyword, group and class search.

Paste the coordinates from your `pom.xml` or `build.gradle` and get one row per artifact: the newest release with its
release date, the newest prerelease separately, the number of published versions, the date of the first release, the
releases of the last twelve months and the recent versions with dates — plus, when you pin a version, its release
date, its age in days, whether it is still current and how many releases you are behind. The source is the search
index of the Central Repository, run by Sonatype: no API key, no account, no proxy and no browser.

### Use cases

- **CI gate on stale pins**: feed the gate the coordinates of your build file and fail the job when `versionsBehind`
  or `latestVersionAgeDays` crosses your threshold.
- **Upgrade tickets with real dates**: "we are 7 releases and 2 years behind on slf4j-api" instead of "there is a
  newer version", with the release date of every version in between.
- **Dependency health review**: `releasesLast365Days`, `firstReleasedAt` and `latestVersionAgeDays` tell you whether
  a library is still shipping before you adopt it.
- **Choosing between two libraries** by release cadence: run both coordinate lists and compare the release history.
- **Finding the artifact that contains a class**: a build fails on a missing class — `c:ObjectMapper` returns the
  artifacts that ship it.
- **Vendor or monorepo inventory**: `g:com.squareup.okhttp3` lists every artifact id a group publishes, with the
  newest release of each.
- **Scheduled "what updated since yesterday"**: switch on `onlyNew` and a daily schedule writes only the artifacts
  whose newest version, prereleases included, changed since the previous run.

### Input

Every field is optional, but a run needs at least one coordinate or one search query.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `coordinates` | string\[] | – | Up to 50 artifacts, one per line, as `groupId:artifactId` or `groupId:artifactId:version`. A version turns the row into an upgrade check. Spaces, surrounding quotes and a trailing `:jar` or `@aar` are ignored. See [Coordinate forms](#coordinate-forms). |
| `searchQueries` | string\[] | – | Up to 10 free-text searches against the same index, passed on exactly as typed. Plain words, or the index qualifiers of [Search qualifiers](#search-qualifiers) (`g:`, `a:`, `c:`, `fc:`, `tags:`, …). |
| `searchMaxItems` | integer | 20 | 1–200. Top N artifacts per search query. Every artifact kept is a billed row. |
| `searchHydrate` | boolean | false | Off: a search hit is written from its index entry — group, artifact id, **the index's own latest version** (which can be an old prerelease), the version count and the date of that entry — and the row says `versionsSource: "index"`. On: every hit also gets its version history read, so it carries dated versions and a derived newest release like a coordinate (`versionsSource: "history"`), at one extra request per hit. Coordinates always get the full history. |
| `includePrereleases` | boolean | false | Off: alpha, beta, RC, milestone, snapshot, dev and preview versions stay out of `latestVersion`, `isLatest`, `versionsBehind` and `newerVersions` — they are still reported in `latestAnyVersion` and in `recentVersions` with `prerelease: true`. On: the newest version wins whatever it is called. See [What counts as a prerelease](#what-counts-as-a-prerelease). |
| `packaging` | string | – (every packaging) | Keep only versions published with this packaging, e.g. `aar` for Android libraries or `pom` for parent and BOM artifacts. Free text with suggestions: case and a leading dot are ignored, and any packaging Central uses is accepted — see [Packaging values](#packaging-values). |
| `releasedSince` | string | – | `YYYY-MM-DD`, UTC. Keep only artifacts whose newest release is on or after this date; `recentVersions` then lists only versions inside the window and `versionsInWindow` counts them. Artifacts filtered out are counted in the run status and are not written or billed. |
| `versionsLimit` | integer | 10 | 0–200. How many recent versions go into `recentVersions` (and how many version strings into `newerVersions`). 0 leaves both arrays out; the counted fields are computed from the whole scanned history either way. |
| `maxVersionsScanned` | integer | 400 | 50–2000. How deep into a history one run reads, newest first, in pages of 200 versions. When the cap cuts a history, the row says so in `historyTruncated`. |
| `onlyNew` | boolean | false | Remember the newest version of every artifact written and, on the next run of the same actor or task, write only the artifacts whose newest version, prereleases included, has changed. The first run writes everything. See [What counts as a change for `onlyNew`](#what-counts-as-a-change-for-onlynew). |
| `maxItems` | integer | 50 | 1–1000. Hard cap on the rows this run writes, and so on what it costs. Coordinates are written first, in the order you gave them, then search hits. |
| `fields` | string\[] | all | Keep only these columns, **in this order**. `id`, `groupId`, `artifactId`, `found`, `versionsSource`, `url` and `fetchedAt` are always kept — the ones you do not list come first, in that order, and naming one of them here moves it to the position you gave it. An unknown column name is reported in the run's status message instead of being dropped in silence. |

### Reference

#### Coordinate forms

All of these mean the same artifact, and the first three also pin a version:

| What you paste | Read as |
|---|---|
| `com.google.code.gson:gson:2.10.1` | group `com.google.code.gson`, artifact `gson`, pinned `2.10.1` |
| `  "com.google.code.gson:gson:2.10.1"  ` | the same (spaces and quotes are stripped) |
| `com.squareup.okhttp3:okhttp:4.12.0@aar` | group, artifact, pinned `4.12.0` (the Gradle `@ext` suffix is ignored) |
| `org.slf4j:slf4j-api` | group and artifact, no pin — a release report instead of an upgrade check |
| `org.example:lib:jar` | group and artifact; `jar` is a packaging, not a version |

A value that cannot be a coordinate at all — a bare artifact name such as `gson`, an empty part, a group id with a
space — fails the run with a message naming the expected shape. An artifact the index does not know returns a row
with `found: false` instead of disappearing.

#### Search qualifiers

The index's own qualifiers, passed on as typed. They may be combined with `AND` / `OR`.

| Query | What it finds |
|---|---|
| `json parser` | plain words over artifact names and descriptions |
| `g:com.squareup.okhttp3` | every artifact a group publishes |
| `a:okhttp` | that artifact id in any group |
| `c:ObjectMapper` | artifacts containing a class with that simple name |
| `fc:com.fasterxml.jackson.databind.ObjectMapper` | artifacts containing that fully qualified class |
| `tags:kotlin` | artifacts the index tagged `kotlin` |
| `p:aar` | artifacts published as Android archives |
| `l:sources` | artifacts that ship a `sources` classifier |

A class or version query (`c:`, `fc:`, `v:`) is answered by the index with single **versions**, so hits are
deduplicated to artifact level: the same artifact found in six versions is one row. On 2026-10-09, the first forty
version answers to `c:ObjectMapper` covered twelve distinct artifacts — which is why a wide class query can yield
fewer artifacts than `searchMaxItems` asks for.

#### Packaging values

Values seen in Central: `jar`, `aar`, `pom`, `bundle`, `war`, `zip`, `module`. `packaging` is a free-text field with
these as suggestions, so case, a leading dot and the spellings `jars`, `osgi-bundle` and `gradle-module` are
accepted. Any other value is passed to the filter as typed — Central uses more packagings than the seven above, and
the run status says when a value was used as typed. A value that is a letter or two away from a known packaging
(`jarr`, `pomm`) is refused with "did you mean …?" rather than silently matching nothing.

#### What counts as a prerelease

A version is treated as a prerelease when it carries one of these markers as its own token, in any case:
`alpha`, `beta`, `rc`, `cr`, `milestone` or `m<N>`, `snapshot`, `dev`, `preview`, `pre`, `prerelease`, `candidate`,
`ea`, `incubating`, `b<N>`. So `5.0.0-alpha.16`, `3.0.0-beta3`, `4.0.0-M3` and `2.0.0.RC1` are prereleases, while
flavour qualifiers are not: `33.4.8-jre`, `1.2.3-android` and `2.0.0.Final` are releases.

When an artifact has published nothing but prereleases (`com.squareup.okhttp3:okhttp-java-net-cookiejar` has only
`5.0.0-alpha.*` versions), `latestVersion` reports the newest of them — there is no release to report instead — and it
is then equal to `latestAnyVersion`.

#### What counts as a change for `onlyNew`

The watch memory keeps the newest version of any kind per artifact (`latestAnyVersion` with its release date), so a
new prerelease counts as a change and brings the artifact back even with `includePrereleases` off — the row then
repeats the same `latestVersion` while `latestAnyVersion` has moved on (`com.squareup.okhttp3:okhttp`:
`latestVersion` 4.12.0, `latestAnyVersion` 5.0.0-alpha.16). Everything else about an artifact — new tags, a changed
packaging, a version count that grew without a newer version — does not bring it back. The first run writes
everything, and a coordinate Central does not hold repeats only when it starts to exist.

#### Where a row's versions come from

Every row says it in `versionsSource`:

| Value | When | What the row holds |
|---|---|---|
| `history` | every coordinate, and search hits with `searchHydrate` on | the scanned version list: `latestVersion` derived from the release dates, `recentVersions`, `firstReleasedAt`, `releasesLast365Days`, and the pinned-version answer |
| `index` | search hits with `searchHydrate` off, and a hit whose history request did not answer | the index entry only: its own `latestVersion` with the entry's date (a prerelease is possible here), `versionCount`, `packaging`. `recentVersions`, `firstReleasedAt` and `releasesLast365Days` stay `null` |

A search hit is never dropped because the index was slow: it is written from what the search itself returned, and the
run status counts those rows.

### Examples

**Is anything we pinned stale?**

```json
{
  "coordinates": [
    "com.google.code.gson:gson:2.10.1",
    "org.apache.commons:commons-lang3:3.12.0",
    "org.slf4j:slf4j-api:1.7.36"
  ],
  "versionsLimit": 5,
  "maxItems": 10
}
```

**Which artifact contains this class?**

```json
{ "searchQueries": ["c:ObjectMapper"], "searchMaxItems": 10, "maxItems": 10 }
```

**Which of our dependencies shipped anything this year?**

```json
{
  "coordinates": [
    "com.google.code.gson:gson",
    "org.apache.logging.log4j:log4j-core",
    "com.google.guava:guava",
    "org.springframework:spring-core",
    "org.apache.commons:commons-lang3"
  ],
  "releasedSince": "2026-01-01",
  "versionsLimit": 5,
  "fields": ["latestVersion", "latestVersionReleasedAt", "versionsInWindow", "recentVersions"],
  "maxItems": 10
}
```

**Everything two vendor groups publish, with real release dates**

```json
{
  "searchQueries": ["g:com.squareup.okhttp3", "g:com.squareup.moshi"],
  "searchHydrate": true,
  "searchMaxItems": 4,
  "versionsLimit": 5,
  "maxItems": 8
}
```

**Release cadence of the libraries we depend on**

```json
{
  "coordinates": [
    "org.jetbrains.kotlin:kotlin-stdlib",
    "org.jetbrains.kotlinx:kotlinx-coroutines-core",
    "com.squareup.okhttp3:okhttp"
  ],
  "versionsLimit": 25,
  "maxItems": 10
}
```

**Android libraries only, as a daily watch**

```json
{
  "searchQueries": ["tags:android"],
  "packaging": "aar",
  "searchMaxItems": 50,
  "onlyNew": true,
  "maxItems": 50
}
```

### Output

One row per artifact. A real row from cloud run `0fWzvkeyRgO4Ebzne` (input `com.google.code.gson:gson:2.10.1`
with `versionsLimit: 5`; `recentVersions` trimmed here with `…`):

```json
{
  "id": "com.google.code.gson:gson",
  "groupId": "com.google.code.gson",
  "artifactId": "gson",
  "found": true,
  "versionsSource": "history",
  "latestVersion": "2.14.0",
  "latestVersionReleasedAt": "2026-04-23T19:01:47.000Z",
  "latestVersionAgeDays": 169,
  "latestAnyVersion": "2.14.0",
  "latestAnyVersionReleasedAt": "2026-04-23T19:01:47.000Z",
  "versionCount": 42,
  "firstReleasedAt": "2008-08-10T14:29:31.000Z",
  "releasesLast365Days": 1,
  "packaging": "jar",
  "tags": [
    "library",
    "json",
    "gson"
  ],
  "recentVersions": [
    {
      "version": "2.14.0",
      "releasedAt": "2026-04-23T19:01:47.000Z",
      "packaging": "jar",
      "prerelease": false
    },
    {
      "version": "2.13.1",
      "releasedAt": "2025-04-24T01:05:20.482Z",
      "packaging": "jar",
      "prerelease": false
    },
    {
      "version": "2.13.0",
      "releasedAt": "2025-04-11T14:30:34.134Z",
      "packaging": "jar",
      "prerelease": false
    }
    …
  ],
  "historyTruncated": false,
  "versionsInWindow": null,
  "matchedQuery": null,
  "pinnedVersion": "2.10.1",
  "pinnedVersionFound": true,
  "pinnedVersionReleasedAt": "2023-01-06T15:44:01.000Z",
  "pinnedVersionAgeDays": 1372,
  "isLatest": false,
  "versionsBehind": 6,
  "newerVersions": [
    "2.14.0",
    "2.13.1",
    "2.13.0",
    "2.12.1",
    "2.12.0"
  ],
  "url": "https://search.maven.org/artifact/com.google.code.gson/gson",
  "fetchedAt": "2026-10-09T21:50:22.957Z"
}
```

| Field | Type | Meaning |
|---|---|---|
| `id` | string | `groupId:artifactId` — the row key |
| `groupId`, `artifactId` | string | The coordinate, always filled |
| `found` | boolean | `false` when the index has no such artifact; the rest of the row is then null |
| `versionsSource` | string | `history` (versions read and dated) or `index` (the index entry only) — see [Where a row's versions come from](#where-a-rows-versions-come-from) |
| `latestVersion` | string | Newest release, derived from the release dates (prereleases excluded unless `includePrereleases`). With `versionsSource: "index"` it is instead the index entry's own latest version, which may be a prerelease |
| `latestVersionReleasedAt` | string | Its release date, ISO 8601 UTC; with `versionsSource: "index"`, the date of the index entry |
| `latestVersionAgeDays` | number | Whole days since that release |
| `latestAnyVersion` | string | Newest version of any kind, prereleases included |
| `latestAnyVersionReleasedAt` | string | Its release date |
| `versionCount` | number | Versions the index holds for the artifact (its own total, not only the scanned ones) |
| `firstReleasedAt` | string | Oldest release read; with `historyTruncated: true` that is the oldest version inside the scanned window. Null with `versionsSource: "index"` |
| `releasesLast365Days` | number | Versions released in the last 365 days, prereleases included. Null with `versionsSource: "index"` |
| `packaging` | string | Packaging of the newest release (`jar`, `aar`, `pom`, …) |
| `tags` | string\[] | Tags the index keeps for that version; null when it has none |
| `recentVersions` | object\[] | Up to `versionsLimit` recent versions: `version`, `releasedAt`, `packaging`, `prerelease`. Only versions inside the window when `releasedSince` is set. Null with `versionsSource: "index"` |
| `historyTruncated` | boolean | True when `maxVersionsScanned` stopped the scan before the oldest version |
| `versionsInWindow` | number | Versions released on or after `releasedSince`; null without that filter |
| `matchedQuery` | string | The search query that produced the row; null for a coordinate |
| `pinnedVersion` | string | The version you pinned; null when you pinned none |
| `pinnedVersionFound` | boolean | False when Central does not have that version |
| `pinnedVersionReleasedAt` | string | Release date of the pinned version |
| `pinnedVersionAgeDays` | number | Whole days since the pinned version was released |
| `isLatest` | boolean | True when nothing newer has been released; false when the pin is unknown to Central; null without a pin |
| `versionsBehind` | number | Releases published after your pin; null without a pin or when the pin is unknown |
| `newerVersions` | string\[] | Up to `versionsLimit` version strings newer than your pin, newest first |
| `url` | string | The artifact's page on the Central search site |
| `fetchedAt` | string | When the row was read, ISO 8601 UTC |

All dates are ISO 8601 in UTC, converted from the index's epoch-millisecond `timestamp`.

Dataset views: **Artifacts** (overview), **Upgrade check** (pinned version, versions behind, newest release),
**Release history** (dates, counts, `recentVersions`, `versionsSource`).

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~maven-central-artifact-versions/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"coordinates":["com.google.code.gson:gson:2.10.1","org.slf4j:slf4j-api:1.7.36"],"maxItems":10}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/maven-central-artifact-versions').call({
    coordinates: ['com.google.code.gson:gson:2.10.1', 'org.slf4j:slf4j-api:1.7.36'],
    maxItems: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/maven-central-artifact-versions").call(run_input={
    "coordinates": ["com.google.code.gson:gson:2.10.1", "org.slf4j:slf4j-api:1.7.36"],
    "maxItems": 10,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the
`yadroo/maven-central-artifact-versions` tool with the same JSON input. `coordinates` is normally the only field an
agent needs to fill; everything else has a working default.

### Pricing

Pay per event: **$0.001 per run start + $0.002 per artifact row**. Every run is charged the start event, even one
that finds nothing. Every row written to the dataset is charged once — including a `found: false` marker row, which is
the answer to a coordinate Central does not have, and a search hit written from the index entry. Artifacts dropped by
`releasedSince` or `packaging` are not written and not billed.

| Run | Rows | What it costs |
|---|---|---|
| The two prefilled coordinates | 2 | $0.001 + 2 × $0.002 = **$0.005** |
| A build file's dependencies | 20 | $0.001 + 20 × $0.002 = **$0.041** |
| A typical run of this actor | 50 | $0.001 + 50 × $0.002 = **$0.101** |
| A keyword search with `searchMaxItems` 200 | 200 | $0.001 + 200 × $0.002 = **$0.401** |

`searchMaxItems` is the knob that decides what a search query costs: a wide word query with a high value here is the
expensive way to use this actor. Apify's plan discounts apply to the row event (Bronze −10 %, Silver −20 %, Gold and
above −30 %); the start event is the same on every plan. The run also stops at the **Maximum cost per run** you set on
the platform and keeps every row you already paid for — the status message then says "Stopped at your spending limit:
N rows delivered".

### Limits & FAQ

**How fast is it?** Measured in the Apify cloud on 2026-10-09. One coordinate with up to 200 versions is one
request, and the index normally answers in under a second: three pinned coordinates came back in 15 seconds, fifteen
keyword hits in 1 second, ten class-search artifacts in 30 seconds, eight artifacts of two groups with their full
histories in 116 seconds. A long run is slower, because this index lets single requests stall for half a minute and
the actor then slows itself down: **50 coordinates took 361 seconds — 49 rows and 79 requests, about 8 artifacts and
13 requests per minute** (run `PsbL05k4q8lUINhnU`; 14 of those 79 requests stalled and were retried, none of the 49
lookups was lost). Plan on seconds for a handful of coordinates and on six to seven minutes for a build file's worth
of them.

**What fits into the run timeout?** The 900-second default timeout is sized for the slow case, not the fast one: the
50 coordinates the input allows took 361 seconds in the measurement above, and a stalling index can halve what a
short run returns — the same input with a 60-second timeout saved 6 rows (run `eissMVtfBF7SPnFJq`). The default does
not cover every extreme the schema permits: 50 coordinates plus ten search queries of 200 hydrated hits each is
thousands of requests. Such a run stops early, keeps every row it has read and says so: "Stopped before the run
timeout: N rows saved". Split the work, or raise the timeout in the run options.

**Rate limit.** Sonatype's REST API guide documents no rate limit for the search endpoint and `robots.txt` sets no
`Crawl-delay`, so this actor applies the house default: one request per second per host with a burst of three, for
every request including retries. There are no 429 answers; what the index does instead is let a request stall for
half a minute or more. Such a request is cut after 12 seconds and tried again — measured on 2026-10-09, the same URL
that stalled answered in 0.3 seconds on the next attempt — with four attempts in all, the last two waiting the full
30 seconds, and the actor **halves its own pace** after every stall, down to one request every four seconds. Asking
less often is what gets a long run through. An artifact whose history still could not be read is reported in the run
status instead of failing the run, and a search hit is then written from its index entry.

**A run stops before its timeout.** When the run would otherwise be killed by the Apify timeout, it stops starting new
work, keeps every row already read and ends successfully with "Stopped before the run timeout: N rows saved" in the
status message. The same happens at your maximum cost per run. Raise the timeout, raise the cost cap, or split the
coordinate list.

**One request per 200 versions.** A history is read in pages of 200 versions, newest first, and never deeper than
`maxVersionsScanned` (default 400). Almost every library fits in one request; an SDK that publishes daily does not —
then `historyTruncated` is `true`, `versionCount` still shows the index's own total, and `firstReleasedAt` is the
oldest version inside the scanned window. Raise `maxVersionsScanned` to read deeper, at one more request per 200
versions.

**Newest by date is not always the highest number.** `latestVersion`, `versionsBehind` and `newerVersions` follow
release dates, as the field table says. Libraries that maintain several lines in parallel publish a patch of an older
line after a newer minor: a `2.18.x` patch released after `2.19.0` becomes the newest release by date, so a pin of
`2.19.0` can show `isLatest: false` with `versionsBehind: 1`. `recentVersions` shows the lines side by side with their
dates, so you can see which release you actually want.

**Central only.** The rows are what the Maven Central search index holds. Artifacts published only to Google's
Android repository (the `androidx.*` groups), to JitPack or to a company Nexus are not in this index and come back as
`found: false`. `SNAPSHOT` versions are not published to Central at all.

**No deprecation or breaking-change data.** Central publishes versions, dates and packaging — nothing about API
compatibility, deprecations or whether an upgrade will break your build. This actor answers "what exists, when was it
released, how far behind am I"; it cannot answer "is it safe to upgrade", because no field for that exists in this
source.

**Why not use the index's own "latest version"?** Because it is often wrong for an upgrade check: on 2026-10-09 the
index entry for `org.apache.logging.log4j:log4j-core` named `3.0.0-beta3` from 2024 while the artifact's newest
release in the same index was `2.26.0` from 2026-05. A row with `versionsSource: "history"` derives the newest release
from the release dates and keeps prereleases in a separate field; a row with `versionsSource: "index"` reports the
entry's value as it is.

**Freshness and gaps.** The index is kept by Central itself and is usually current shortly after a release, but
coverage is uneven for some artifacts — `com.google.guava:guava` holds 150 versions whose newest is from 2025-04.
Treat the rows as what the index holds, not as a guarantee about the repository, and never as real time.

**Empty results.** A coordinate the index does not know gives a `found: false` row. A search query with no match
gives no row and says so in the run status. An input that cannot be a coordinate fails the run with a message naming
the expected shape — never a silent empty success.

**Questions or problems:** open an issue on the Issues tab of this actor.

***

Made by **Yadroo**. Sibling actors:
[npm-package-intel](https://apify.com/yadroo/npm-package-intel),
[pypi-package-intel](https://apify.com/yadroo/pypi-package-intel),
[github-repo-intel](https://apify.com/yadroo/github-repo-intel),
[cisa-kev-vulnerabilities](https://apify.com/yadroo/cisa-kev-vulnerabilities),
[domain-intel](https://apify.com/yadroo/domain-intel).

# Actor input Schema

## `coordinates` (type: `array`):

Artifacts to check, one per line, as `groupId:artifactId`, or `groupId:artifactId:version` to compare a pinned version with the newest release. Surrounding spaces, stray quotes and a trailing `:jar` or `@aar` are ignored. One dataset row per artifact. A coordinate Maven Central does not hold comes back as a row with `found: false` instead of disappearing; a value that cannot be a coordinate at all (an artifact name without a group) stops the run and names the expected shape.

## `searchQueries` (type: `array`):

Free-text searches over the same index, for artifacts whose coordinates you do not know. Plain words search names and descriptions (`json parser`, `jdbc postgres`). Index qualifiers are passed on exactly as typed: `g:com.squareup.okhttp3` for a whole group, `a:okhttp` for an artifact id in any group, `tags:kotlin`, `c:ObjectMapper` for a simple class name, `fc:com.fasterxml.jackson.databind.ObjectMapper`. Each query returns up to `searchMaxItems` artifacts; an artifact found twice is one row.

## `searchMaxItems` (type: `integer`):

Top N artifacts of each search query, ranked by the index itself. Every artifact kept is a billed row, so a wide word search with a high value here is the expensive way to use this actor.

## `searchHydrate` (type: `boolean`):

Off (default): a search hit is written from its index entry - group, artifact id, the index's own latest version, the number of versions and the date of that entry - and the row says `versionsSource: "index"`. On: each hit also gets its version list read, so it carries the same dated history and derived newest release as a coordinate (`versionsSource: "history"`), at one extra request per hit. Coordinates always get the full history, whatever this is set to.

## `includePrereleases` (type: `boolean`):

Off (default): alpha, beta, RC, milestone (`-M3`), snapshot, dev and preview versions stay out of `latestVersion`, `versionsBehind` and `isLatest`, so an upgrade check never points at a beta; they stay visible in `latestAnyVersion` and in `recentVersions` with `prerelease: true`. On: the newest release wins whatever it is called. The index's own latest-version field often names an old prerelease, which is why a read history derives the newest release from release dates.

## `packaging` (type: `string`):

Keep only versions published with this packaging - `aar` for Android libraries, `pom` for parent and bill-of-materials artifacts. Case and a leading dot are ignored, and any packaging the source uses is accepted, not only the suggested ones. Empty (default) = every packaging; each row reports the packaging of its newest release in `packaging`.

## `releasedSince` (type: `string`):

Keep only artifacts whose newest release is on or after this UTC date - the filter for "what is still alive" and "what moved since our last audit". `recentVersions` then lists only versions released inside the window and `versionsInWindow` counts them. Artifacts filtered out are counted in the run status and in SUMMARY, and are neither written nor billed.

## `versionsLimit` (type: `integer`):

How many of the most recent versions go into the `recentVersions` array of a row, each with its version string, UTC release date, packaging and prerelease flag. 0 leaves the array out and keeps rows small; the counted fields (`versionCount`, `versionsBehind`, `releasesLast365Days`) are computed from the whole scanned history either way.

## `maxVersionsScanned` (type: `integer`):

How deep into an artifact's history one run reads, newest first, in pages of 200 versions. Two pages cover all but the busiest artifacts: a library with 150 releases is one request, while an SDK that publishes daily can have well over a thousand versions. Raising this costs requests and time and changes only the dated history fields. When the cap cuts a history, the row says so in `historyTruncated`.

## `onlyNew` (type: `boolean`):

Remember the newest version of every artifact this run writes, and on the next run of the same actor or task write only the artifacts whose newest version (prereleases included) changed since then. Made for a schedule: each run then holds exactly the dependency updates that appeared since the last one, which is what a CI check or a dependency dashboard needs. The first run writes everything. The memory is kept per actor or task, so two tasks watching two stacks do not interfere.

## `maxItems` (type: `integer`):

Hard cap on the rows this run writes, and so on what it costs. Coordinates are written before search hits, in the order you gave them. The run also stops at the maximum cost per run you set on the platform.

## `fields` (type: `array`):

Keep only the named columns, in the order given - for example `id, pinnedVersion, latestVersion, versionsBehind`. Empty = every column. `id`, `groupId`, `artifactId`, `found`, `versionsSource`, `url` and `fetchedAt` are always present; name one of them here and it moves to the position you gave it. Unknown names are reported in the run's status message instead of being dropped in silence.

## Actor input object example

```json
{
  "coordinates": [
    "com.google.code.gson:gson:2.10.1",
    "org.apache.logging.log4j:log4j-core"
  ],
  "searchMaxItems": 20,
  "searchHydrate": false,
  "includePrereleases": false,
  "versionsLimit": 10,
  "maxVersionsScanned": 400,
  "onlyNew": false,
  "maxItems": 50
}
```

# 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 = {
    "coordinates": [
        "com.google.code.gson:gson:2.10.1",
        "org.apache.logging.log4j:log4j-core"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/maven-central-artifact-versions").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 = { "coordinates": [
        "com.google.code.gson:gson:2.10.1",
        "org.apache.logging.log4j:log4j-core",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/maven-central-artifact-versions").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 '{
  "coordinates": [
    "com.google.code.gson:gson:2.10.1",
    "org.apache.logging.log4j:log4j-core"
  ]
}' |
apify call yadroo/maven-central-artifact-versions --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/maven-central-artifact-versions"
        }
    }
}
```

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/PfvQJ5Hyxa7ft9qAg/builds/pc7xSSlkmkSB07QNd/openapi.json
