# Container Image Tag Monitor (`junipr/container-image-tag-monitor`) Actor

Monitor container image tags/digests for changes, additions, removals, and version shifts.

- **URL**: https://apify.com/junipr/container-image-tag-monitor.md
- **Developed by:** [junipr](https://apify.com/junipr) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.50 / 1,000 target checkeds

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

## Container Image Tag Monitor

Compare public container registry tag inventories and produce structured rows for tag additions, removals, mutable-tag digest changes, status changes, architecture changes, and semantic-version movement.

### What It Monitors

- Added and removed tags.
- Digest changes for mutable tags such as `latest`.
- Tag availability or status changes.
- Published time, architecture, and image size changes.
- Major, minor, patch, and prerelease semantic-version movement.

The parser accepts Docker Hub tag responses, OCI tag-list responses, generic JSON tag collections, and structured registry records. Digests are reported only when the source supplies them; the actor never derives a digest from page text.

### Input

Use `targets` for multiple images, or provide direct single-image fields at the top level.

| Field | Purpose |
| --- | --- |
| `targets` | Capped previous/current image tag comparisons. |
| `registry` | Registry type or host label. |
| `imageName` | Repository or image name. |
| `sourceUrl` / `urls` | Public registry API URLs. Retrieval occurs only when `fetchUrls` is true and current data is absent. |
| `previousSnapshot` / `currentSnapshot` | Docker Hub, OCI, or supported generic JSON. |
| `previousTags` / `currentTags` | Structured tag records. |
| `records` | Pre-paired records containing old and new tag values. |
| `includeUnchanged` | Include tags whose supported fields did not change. |
| `includeReport` | Write results, summary, and Markdown report records. |
| `maxTargets` | Image cap, from 1 through 50. |
| `maxTagsPerTarget` | Tag cap per side, from 1 through 5,000. |
| `maxItems` | Dataset row cap. |
| `maxTextBytes` | Snapshot size cap, up to 2,000,000 bytes. |

```json
{
  "registry": "docker-hub",
  "imageName": "acme/api",
  "previousTags": [
    {
      "name": "latest",
      "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "status": "active",
      "architectures": ["linux/amd64"]
    }
  ],
  "currentTags": [
    {
      "name": "latest",
      "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "status": "active",
      "architectures": ["linux/amd64", "linux/arm64"]
    },
    {
      "name": "2.0.0",
      "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "status": "active"
    }
  ],
  "maxItems": 25,
  "includeReport": true
}
```

### Dataset Rows

Each row identifies one tag change or source diagnostic. Important fields include:

- `registry`, `imageName`, and `tag`.
- `changeType`, `oldDigest`, `newDigest`, `oldStatus`, and `newStatus`.
- `oldArchitectures`, `newArchitectures`, `oldSizeBytes`, and `newSizeBytes`.
- `oldPublishedAt`, `newPublishedAt`, `versionDirection`, and `semverJump`.
- Source identifiers, severity, score, checked time, and recommendation.
- `diagnosticCode` and `sourceError` for blocked retrieval or an empty tag parse.

Change types are `tag-added`, `tag-removed`, `digest-changed`, `tag-status-changed`, `metadata-changed`, and `unchanged`.

### Stored Artifacts

- Dataset: one row per tag change, unchanged tag, or diagnostic that passes configured filters and caps.
- `CONTAINER_IMAGE_TAG_MONITOR_RESULTS.json`: emitted rows.
- `CONTAINER_IMAGE_TAG_MONITOR_SUMMARY.json`: tag, digest, status, architecture, version, diagnostic, and charge-limit counts.
- `CONTAINER_IMAGE_TAG_MONITOR_REPORT.md`: readable image tag change digest.

### Usage Charges

The actor uses pay per event. Platform usage is included in these event prices.

| Event | Price | When charged |
| --- | ---: | --- |
| `actor-start` | $0.02000 | Once before paid work starts. |
| `target-checked` | $0.00650 | Before each image target is processed. |
| `snapshot-compared` | $0.00650 | Before a successfully prepared tag pair is compared. |
| `change-detected` | $0.01300 | Before each changed tag row is emitted. |
| `digest-generated` | $0.05000 | Before JSON result and summary records are written. |
| `executive-report-generated` | $0.10000 | Before the Markdown report is written. |

If Apify reports that a charge was limited or only partly accepted, the actor stops before the corresponding paid output. Set `includeReport` to false when KVS report artifacts are not needed.

### Public Tasks

Five capped task inputs cover mutable tags, new version tags, removed tags, architecture changes, and a registry digest. Each task uses concrete registry data and bounded output.

### Retrieval Safety

- Only public `http` and `https` URLs are accepted.
- Credentials in URLs and redirects are rejected.
- Loopback, link-local, and private network destinations are blocked unless `allowPrivateUrls` is explicitly enabled for controlled testing.
- Response length, retained snapshot bytes, target count, tag count, and request duration are bounded.
- Fetch failures and empty parses produce explicit diagnostic rows. Missing tags or digests are not synthesized.

### Limitations

- Private registries and credentialed endpoints are not supported.
- OCI tag-list endpoints usually omit digests and image metadata; those fields remain null unless supplied by the source.
- Registry pagination is controlled by the provided URL and the actor's caps. The actor does not crawl unbounded page sequences.
- Scheduling and baseline retention are managed by the caller. Pass prior tag data into each comparison.

# Actor input Schema

## `targets` (type: `array`):

Capped previous/current comparisons.

## `sourceId` (type: `string`):

Stable identifier for a direct single-target comparison.

## `title` (type: `string`):

Human-readable direct target name.

## `sourceUrl` (type: `string`):

Public current-state URL fetched only when enabled.

## `urls` (type: `array`):

Public URLs converted into capped fetch targets.

## `previousSnapshot` (type: `string`):

Previous JSON, HTML, or text snapshot.

## `currentSnapshot` (type: `string`):

Current JSON, HTML, or text snapshot.

## `records` (type: `array`):

Records that already contain previous/current comparison fields.

## `fetchUrls` (type: `boolean`):

Fetch sourceUrl only when the current snapshot is omitted.

## `fetchTimeoutMs` (type: `integer`):

Per-request timeout in milliseconds.

## `allowPrivateUrls` (type: `boolean`):

Permit private or loopback hosts only for controlled testing.

## `maxTargets` (type: `integer`):

Maximum comparisons in one run.

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

Maximum billable dataset rows emitted by one run.

## `maxTagsPerTarget` (type: `integer`):

Maximum records read from each side of one target.

## `maxTextBytes` (type: `integer`):

Maximum bytes retained for each snapshot.

## `includeUnchanged` (type: `boolean`):

Include records with no comparable changes.

## `includeReport` (type: `boolean`):

Write results, summary, and Markdown report artifacts.

## `dryRun` (type: `boolean`):

Validate input without paid output.

## `debug` (type: `boolean`):

Enable debug logging.

## `registry` (type: `string`):

Registry type or host for a direct comparison.

## `imageName` (type: `string`):

Container repository or image name.

## `previousTags` (type: `array`):

Previous registry tag records.

## `currentTags` (type: `array`):

Current registry tag records.

## Actor input object example

```json
{
  "targets": [],
  "sourceId": "",
  "title": "",
  "sourceUrl": "",
  "urls": [],
  "previousSnapshot": "",
  "currentSnapshot": "",
  "records": [],
  "fetchUrls": false,
  "fetchTimeoutMs": 10000,
  "allowPrivateUrls": false,
  "maxTargets": 1,
  "maxItems": 100,
  "maxTagsPerTarget": 500,
  "maxTextBytes": 250000,
  "includeUnchanged": false,
  "includeReport": true,
  "dryRun": false,
  "debug": false,
  "registry": "docker-hub",
  "imageName": "",
  "previousTags": [],
  "currentTags": []
}
```

# Actor output Schema

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

Compare Docker Hub, OCI, and structured registry tag snapshots.

## `artifact1` (type: `string`):

CONTAINER\_IMAGE\_TAG\_MONITOR\_RESULTS.json

## `artifact2` (type: `string`):

CONTAINER\_IMAGE\_TAG\_MONITOR\_SUMMARY.json

## `artifact3` (type: `string`):

CONTAINER\_IMAGE\_TAG\_MONITOR\_REPORT.md

# 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("junipr/container-image-tag-monitor").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("junipr/container-image-tag-monitor").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 '{}' |
apify call junipr/container-image-tag-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=junipr/container-image-tag-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/1hbw7yQktoMMxIh0Y/builds/vC9LhLRtnnGZwwgEU/openapi.json
