# Monitoring Actor (`hamza.alwan/monitoring-actor`) Actor

- **URL**: https://apify.com/hamza.alwan/monitoring-actor.md
- **Developed by:** [Hamza Alwan](https://apify.com/hamza.alwan) (community)
- **Categories:** Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

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

## Actor Monitoring — Usage Reports & Run Comparison

Track cost, reliability, and output volume across every Apify Actor and Task in your account — without building dashboards or writing glue code. Point it at your account, pick a mode, and it collects the runs, crunches the numbers, and delivers a polished email digest plus an Excel workbook and a self-contained HTML dashboard saved to storage.

It runs in three modes:

- **Monthly usage report** — an Excel workbook, a self-contained HTML dashboard, and an email digest covering runs, cost, success rate, and product volume across your account over the last N calendar months, with month-over-month trends.
- **Weekly usage report** — the same workbook, dashboard, and digest over the last N calendar weeks (Monday–Sunday), with week-over-week trends. Schedule it weekly in Apify.
- **Run comparison** — checks the latest run of each monitored Actor/Task against a baseline (previous run, pinned run, or historical average) and emails an alert when items, runtime, cost, or specific dataset fields change.

All modes share the same run collection, filtering, and email delivery, so one configuration covers ongoing usage reporting and regression alerting.

### Quick start

**Monthly report** — three fields, everything else has a working default:

```json
{
    "actorMode": "monthly",
    "emailRecipients": ["you@example.com"],
    "actorNameInclude": ["my-scraper"]
}
```

**Weekly report** — same fields, `weekly` mode; reports on the last 4 calendar weeks by default:

```json
{
    "actorMode": "weekly",
    "emailRecipients": ["you@example.com"],
    "actorNameInclude": ["my-scraper"]
}
```

**Run comparison** — same three fields, different mode. Defaults to comparing the last two `SUCCEEDED` runs of each matching Actor/Task:

```json
{
    "actorMode": "compare",
    "emailRecipients": ["you@example.com"],
    "actorNameInclude": ["my-scraper"]
}
```

Leave `emailRecipients` empty to skip email — every artifact is still written to the key-value store and dataset.

### Input reference

Fields are grouped into form sections in this order; a monthly or weekly user never needs to scroll past section 4, a compare user never needs section 4 at all.

#### 1. Get started

| Field | Type | Default | Description |
|---|---|---|---|
| `actorMode` | string (`monthly` | `weekly` | `compare`) | `monthly` | Which report to build. |
| `emailRecipients` | array of strings | `[]` | Who receives the email. Empty = no email, artifacts still saved. |
| `actorNameInclude` | array of strings | `[]` (all actors) | Only monitor Actors whose name contains one of these substrings. |

#### 2. Actor & task scope

| Field | Type | Default | Description |
|---|---|---|---|
| `useDirectActorRuns` | boolean | `false` | Collect runs directly per Actor instead of via saved Tasks. |
| `actorNameExclude` | array of strings | `[]` | Skip Actors matching these substrings. |
| `actorNamePattern` | string (regex) | unset | Replaces the include/exclude substring lists when set. |
| `taskNameInclude` | array of strings | `[]` (all tasks) | Only monitor Tasks matching these substrings. Ignored when `useDirectActorRuns` is on. |
| `taskNameExclude` | array of strings | `[]` | Skip Tasks matching these substrings. Ignored when `useDirectActorRuns` is on. |
| `taskNamePattern` | string (regex) | unset | Replaces the Task include/exclude lists when set. Ignored when `useDirectActorRuns` is on. |
| `actorIds` | array of strings | unset | Explicit Actor IDs; skips name-based discovery. |
| `filterRunsByStatus` | array (`SUCCEEDED`/`FAILED`/`ABORTED`/`RUNNING`/`TIMED-OUT`) | all statuses in monthly/weekly, `SUCCEEDED` only in compare | Only collect runs with these statuses. |
| `runInputFilters` | array of objects | unset | Include/exclude runs by their input values, e.g. `{"field": "country", "operator": "equals", "value": "US", "action": "include"}`. Operators: `equals`, `notEquals`, `exists`, `notExists`, `in`, `notIn`, `contains`. Max 20 rules. Explicitly compared run IDs are never filtered out. |
| `runInputFilterMode` | string (`all` | `any`) | `all` | How multiple *include* rules combine; exclude rules always drop a run on match. |

#### 3. Email & delivery

| Field | Type | Default | Description |
|---|---|---|---|
| `outputMode` | string (`email` | `dataset` | `both`) | `email` | Where results go. `dataset` skips email even with recipients set; storage artifacts are always saved. |
| `emailSubject` | string | mode-appropriate default | Template with `{mode}`, `{date}`, `{actorCount}`, `{status}` placeholders. |
| `emailSections` | object | all `true` | Toggle sections: `showCostBreakdown`, `showRunLinks` (both modes); `showSchemaChanges`, `showTrendAnalysis`, `showAnomalyDetection`, `showBuildChanges`, `showFieldDiscovery` (compare only). |
| `emailFooterText` | string | unset | Custom line appended to the email footer. |
| `dryRun` | boolean | `false` | Build everything but send no email — the rendered HTML is saved to the key-value store as `dry-run-email-preview.html`. |

#### 4. Monthly / weekly report

*Applies to `actorMode: monthly` or `weekly` only — ignored in compare mode. Use `monthsToAnalyze`/`includeCurrentMonth` in monthly mode and `weeksToAnalyze`/`includeCurrentWeek` in weekly mode; the rest apply to both.*

| Field | Type | Default | Description |
|---|---|---|---|
| `monthsToAnalyze` | integer (1–24) | `3` | (Monthly) Calendar months of runs to report on. Ignored when a custom date range is set. |
| `includeCurrentMonth` | boolean | `true` | (Monthly) Whether the (partial) current month counts as one of the analyzed months. |
| `weeksToAnalyze` | integer (1–52) | `4` | (Weekly) Calendar weeks (Monday–Sunday) of runs to report on. Ignored when a custom date range is set. |
| `includeCurrentWeek` | boolean | `true` | (Weekly) Whether the (partial) current week counts as one of the analyzed weeks. |
| `dateRangeStart` | string (`YYYY-MM-DD`) | unset | Custom period start; overrides `monthsToAnalyze`/`weeksToAnalyze` when both dates are set. |
| `dateRangeEnd` | string (`YYYY-MM-DD`) | today | Custom period end, inclusive. |
| `topNActors` | integer (1–20) | `5` | Rows in each dashboard ranking (top cost, top failing, health). |
| `customDimensions` | array of objects | group by calendar month (monthly) or ISO week (weekly) | Group the report by run fields instead of by reporting period. Up to 5 dimensions; see [docs/field-comparison.md](docs/field-comparison.md) for recipes. |
| `enableAggregation` | boolean | `true` | Adds the *Aggregated Insights* view: item volume per product dimension with period-over-period growth and yield alerts. |
| `saveHtmlDashboard` | boolean | `true` | Saves the standalone HTML dashboard to the key-value store and links it from the email. |
| `healthScoreWeights` | object | `{successRate: 0.47, zeroItemInverse: 0.29, costEfficiency: 0.24}` | Weights of the 0–100 actor health score; must sum to 1.0. |

#### 5. Compare runs

*Applies to `actorMode: compare` only — ignored in monthly and weekly modes.*

| Field | Type | Default | Description |
|---|---|---|---|
| `compareMode` | string (`last2` | `lastVsBaseline` | `lastVsAverage`) | `last2` | How the baseline is chosen. `lastVsBaseline` needs `baselineRunId`; `lastVsAverage` averages `baselineRunCount` runs. Ignored when explicit run IDs are set. |
| `baselineRunId` | string | unset | Pinned known-good run. Required for `lastVsBaseline`. |
| `baselineRunCount` | integer (2–20) | `5` | Historical runs averaged for `lastVsAverage`. |
| `compareRunId1` | string | unset | Explicit baseline run ID. Takes full precedence over `compareMode`/`baselineRunId` when set together with `compareRunId2`. |
| `compareRunId2` | string | unset | Explicit "current" run ID for a two-run comparison. |
| `maxDatasetItems` | integer (100–10000) | `1000` | Dataset items fetched per run for field-level comparison. |
| `enableCompareExcel` | boolean | `false` | Saves a comparison workbook (`compare-report.xlsx`) to the key-value store. |
| `combineEmails` | boolean | `true` | Send one consolidated email for all compared entities instead of one per entity. Monthly and weekly modes always send a single email. |

#### 6. Compare — field rules

*Applies to `actorMode: compare` only.*

| Field | Type | Default | Description |
|---|---|---|---|
| `fieldsAndCompareStrategy` | object | discovery mode | Which dataset fields to compare and how, e.g. `{"results.price": "average", "items": {"strategy": "count", "lowerIsBetter": false}}`. Use `[]` to reach into arrays of objects (`reviews[].rating`). 25 strategies available — see [docs/field-comparison.md](docs/field-comparison.md). Omitting this field, or passing `{}`, runs field *discovery* instead of comparison. |
| `excludeFields` | array of strings | `[]` | Field paths to skip — from comparison when strategies are configured, from the discovery report otherwise. |

#### 7. Compare — trends & anomalies

*Applies to `actorMode: compare` only; both features need at least 3 runs of history.*

| Field | Type | Default | Description |
|---|---|---|---|
| `enableTrendAnalysis` | boolean | `false` | Linear-regression trend analysis (items/runtime/cost) over recent runs. |
| `trendRunCount` | integer (3–50) | `10` | Recent runs feeding trend analysis. |
| `enableAnomalyDetection` | boolean | `false` | Z-score anomaly flagging. Works independently of trend analysis. |
| `anomalyStdDevMultiplier` | number (1–5) | `2` | Standard-deviation multiplier — lower is more sensitive. |

#### 8. Alerts & notifications

| Field | Type | Default | Description |
|---|---|---|---|
| `alerts` | object | `{changePercent: 5, yieldDropPercent: 20}` | One place for every "how big a change matters" setting: `changePercent` (compare-mode email gate), `itemsCount`/`runtimeSecs`/`costUsd` (**percent-change** severity bands for compare), `avgRuntimeSecs`/`avgCostUsd` (absolute monthly Threshold Breaches in seconds/USD), `custom` (per-field bands; also `failureRate`/`zeroItemRate` for monthly), `yieldDropPercent` (aggregation yield alert). |
| `notifyOnSignificantChange` | boolean | `true` | Compare mode: only email when at least one metric changed by `alerts.changePercent` or more. |
| `alwaysSendSummary` | boolean | `false` | Compare mode: send an "all clear" summary email even when nothing significant changed. |

#### 9. Billing

| Field | Type | Default | Description |
|---|---|---|---|
| `pricePerItem` | number | unset (billing hidden) | Your client-facing USD price per dataset item. Adds Price/Item, Total Price, and Margin (total price = items × price, margin = total price − Apify cost) to both modes. |

#### 10. Limits & advanced

| Field | Type | Default | Description |
|---|---|---|---|
| `maxRuns` | integer (1–50000) | `100` | Cap on runs fetched per monitored Actor/Task. |
| `concurrencyLimit` | integer (1–20) | `10` | Actors/Tasks collected in parallel. |
| `circuitBreakerThreshold` | integer (1–50) | `3` | Abort the run once at least this many actors/tasks fail to collect *and* at least half of the processed items have failed. If the first few processed items all fail (e.g. an invalid token), the run aborts immediately. |
| `token` | string (secret) | `APIFY_TOKEN` env, else account running the Actor | API token of the account to monitor. Input value overrides `APIFY_TOKEN`. |
| `debug` | boolean | `false` | Verbose logs for troubleshooting. |

### Output reference

| Artifact | What it is | Where it lands |
|---|---|---|
| Excel workbook (monthly/weekly) | Multi-sheet report: Contents, Executive Dashboard, Entity Metrics, Category Summary, All Runs, Aggregated Insights, Threshold Breaches, Cost Breakdown | Key-value store, key `{base}-sheet.xlsx` |
| Comparison workbook (compare) | Summary + field-detail + inventory sheets for the compared entities | Key-value store, stable key `compare-report.xlsx` (when `enableCompareExcel` is on) |
| HTML dashboard (monthly/weekly) | Standalone, self-contained HTML page — KPI tiles, trend charts, rankings, health board, no external requests | Key-value store, key `{base}-dashboard.html` (when `saveHtmlDashboard` is on) |
| Categorized run export | Slim JSON of every collected run (id, names, dates, status, items, runtime, cost, build) | Key-value store, key `{base}.json` |
| Report manifest | Links every report artifact together with public URLs | Key-value store, key `{base}-manifest.json` |
| Compare manifest | Run counts, comparison/skip counts, and the compare Excel key (compare mode) | Key-value store, key `compare-manifest.v2` |
| `last-report-summary` | Structured JSON snapshot of the latest run, for the Output tab and downstream automation | Key-value store, key `last-report-summary` |
| Diff lineage | Per-cadence snapshot the next same-cadence run diffs against for the period-over-period comparison | Key-value store, key `report-diff-lineage-{week\|month\|date-range}` |
| Field discovery report | Per-entity auto-discovered field types and suggested strategies, when no `fieldsAndCompareStrategy` is configured | Key-value store, key `field-discovery-report.v2.{entity}` |
| Dataset records | `comparison.v4` rows (compare mode, one per field/run comparison) or `monthly-report.v4` rows (monthly/weekly mode, one per report) plus `processing-failures.v2` on per-item errors | Default dataset — Console has **Overview**, **Comparisons**, and **Usage Reports** views |
| Email | HTML digest sharing the same computed metrics as the Excel/HTML dashboard (monthly/weekly KPI parity). Trend summary labels total-runtime PoP separately from the avg-runtime table column; compare-mode request % is Crawlee-only when request stats are mixed | Sent via `apify/send-mail` when `outputMode` includes `email` and recipients are set |

#### Metric definitions (monthly / weekly / date-range)

| Metric | Definition |
|---|---|
| Success rate | `SUCCEEDED / terminal runs` where terminal = `SUCCEEDED` | `FAILED` | `ABORTED` | `TIMED-OUT`. In-flight statuses (`RUNNING`, `READY`, `ABORTING`, `TIMING-OUT`) are excluded from the denominator. |
| Zero-item success share (`zeroItemSuccessRate`) | Share of **succeeded** runs that produced zero items — not “success rate among zero-item runs.” |
| Period-over-period headlines | Calendar MoM/WoW for `week`/`month` (last two buckets). Custom `date-range` windows use a mid-window half-split aligned with Aggregated Insights. |
| Email `{status}` / subject alert emoji | Driven by reliability signals (failures, zero-item successes, or no terminal successes) — not by cost watchlist tips alone. |
| `weekNumber` transform | ISO week label with year prefix, e.g. `2026-W30`. |

Invalid `emailRecipients` entries produce validation **warnings** and are skipped at send time; they do not abort the Actor.

The Console's **Run** tab (Output section) also surfaces one-click links via `.actor/output_schema.json`: the `last-report-summary` record (whose `artifacts` field carries this run's actual Excel/dashboard/manifest URLs — report artifact keys vary with the reporting period, so they can't be linked directly), the dataset items, and — in compare mode — the compare manifest and comparison workbook.

### Data & privacy

This Actor reads data from the runs it monitors and embeds values from it into its outputs. There is **no redaction layer** — treat every artifact and email as potentially containing third-party PII:

- **Compare mode** embeds actual dataset field values (the ones you compare) into the comparison workbook, dataset records, and alert emails. If a monitored dataset holds personal data (emails, names, addresses, scraped user content), those values appear verbatim in the outputs.
- **`runInputFilters`** match against monitored runs' **input** values, which can themselves contain personal or sensitive data (search terms, targeted URLs, credentials embedded in inputs).

Because outputs can carry this data, restrict accordingly: limit `emailRecipients` to people cleared to see the monitored data, and control who can access this Actor's key-value store and default dataset. Prefer non-sensitive fields for comparison where possible.

### FAQ

**Does this send Slack/webhook notifications?** No. Use [Apify Console's built-in run webhooks](https://docs.apify.com/platform/integrations/webhooks) on this Actor/Task for that.

**Why did my field comparison show no results?** Check `fieldsAndCompareStrategy` isn't an empty object `{}` — that's treated the same as omitting it, which runs field *discovery* (suggestions only) instead of comparison. See [docs/field-comparison.md](docs/field-comparison.md).

**Can I compare two arbitrary runs?** Yes — set `compareRunId1` and `compareRunId2`; they take full precedence over `compareMode` and `baselineRunId`.

**Where do I find real, working example configs?** See [examples/](examples/) and [examples/README.md](examples/README.md). For the full E2E compare/monthly matrix and Console task setup, see [docs/e2e-testing.md](docs/e2e-testing.md).

### Local development

```bash
npm install
npm test
```

Example configs live in [examples/](examples/). Field-comparison recipes are in [docs/field-comparison.md](docs/field-comparison.md). End-to-end flows and Apify Console tasks: [docs/e2e-testing.md](docs/e2e-testing.md).

```bash
## Upsert named E2E tasks onto Actor Nm7rlU4WhoqlJfnNF
APIFY_TOKEN=apify_api_... npm run create:e2e-tasks
```

# Actor input Schema

## `actorMode` (type: `string`):

**Monthly** builds a usage report (Excel workbook, HTML dashboard, email digest) over the last N calendar months. **Weekly** builds the same report over the last N calendar weeks (Monday–Sunday). **Compare** checks the latest run of each monitored actor/task against a baseline and emails an alert when something changed. Default: `monthly`.

## `emailRecipients` (type: `array`):

Email addresses that receive the report. Leave empty to skip email (artifacts are still saved to storage). Default: none.

## `actorNameInclude` (type: `array`):

Only monitor actors whose name contains one of these substrings (case-insensitive). Leave empty to monitor **all** actors in the account. Overridden by *Actor name regex* when that is set. Default: all actors.

## `useDirectActorRuns` (type: `boolean`):

When enabled, runs are collected directly per actor instead of via saved tasks; all task filters below are ignored. Default: `false` (task discovery).

## `actorNameExclude` (type: `array`):

Skip actors whose name contains one of these substrings. Applied after includes; overridden by *Actor name regex*. Default: none.

## `actorNamePattern` (type: `string`):

Regular expression matched against actor names. When set, it replaces the include/exclude substring lists above. Default: unset.

## `taskNameInclude` (type: `array`):

Only monitor saved tasks whose name contains one of these substrings. Ignored when *Use direct actor runs* is enabled. Default: all tasks of the selected actors.

## `taskNameExclude` (type: `array`):

Skip tasks whose name contains one of these substrings. Ignored when *Use direct actor runs* is enabled. Default: none.

## `taskNamePattern` (type: `string`):

Regular expression matched against task names; replaces the task include/exclude lists when set. Ignored when *Use direct actor runs* is enabled. Default: unset.

## `actorIds` (type: `array`):

Monitor exactly these actor IDs, skipping name-based discovery entirely. Default: unset (use name filters).

## `filterRunsByStatus` (type: `array`):

Only collect runs with these statuses. Default when omitted: all statuses in monthly/weekly mode; `SUCCEEDED` only in compare mode.

## `runInputFilters` (type: `array`):

Include or exclude runs by their **input** values. Each rule: `{"field": "country", "operator": "equals", "value": "US", "action": "include"}`. Operators: equals, notEquals, exists, notExists, in, notIn, contains. Maximum 20 rules. Explicitly compared run IDs are never filtered out. Default: no filtering.

## `runInputFilterMode` (type: `string`):

How multiple *include* rules combine. Exclude rules always drop a run on match. Default: `all`.

## `outputMode` (type: `string`):

Where results go. `dataset` skips email even when recipients are set. Storage artifacts (Excel, dashboard, manifest) are always saved. Default: `email`.

## `emailSubject` (type: `string`):

Custom subject. Placeholders: `{mode}`, `{date}`, `{actorCount}`, `{status}`. Default: a mode-appropriate subject.

## `emailSections` (type: `object`):

Toggle report sections on/off. Keys (all default `true`): `showCostBreakdown`, `showRunLinks`; compare-mode only: `showSchemaChanges`, `showTrendAnalysis`, `showAnomalyDetection`, `showBuildChanges`, `showFieldDiscovery`. Default: all sections shown.

## `emailFooterText` (type: `string`):

Custom line appended to the email footer. Default: none.

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

Build everything but send no email — the rendered email HTML is saved to the key-value store as `dry-run-email-preview.html` instead. Default: `false`.

## `monthsToAnalyze` (type: `integer`):

How many calendar months of runs to report on. Ignored when a custom date range is set below. Default: `3`.

## `includeCurrentMonth` (type: `boolean`):

Whether the (partial) current month counts as one of the analyzed months. Applies to `actorMode: monthly` only. Default: `true`.

## `weeksToAnalyze` (type: `integer`):

How many calendar weeks (Monday–Sunday) of runs to report on. Ignored when a custom date range is set below. Default: `4`.

## `includeCurrentWeek` (type: `boolean`):

Whether the (partial) current week counts as one of the analyzed weeks. Applies to `actorMode: weekly` only. Default: `true`.

## `dateRangeStart` (type: `string`):

Custom period start (`YYYY-MM-DD`). When both start and end are set, they replace *Months to analyze*. Required if an end date is set. Default: unset.

## `dateRangeEnd` (type: `string`):

Custom period end (`YYYY-MM-DD`), inclusive. Must be on or after the start date. Default: today.

## `topNActors` (type: `integer`):

How many actors appear in each dashboard ranking (top cost, top failing, health). Default: `5`.

## `customDimensions` (type: `array`):

Group the report by run fields instead of by reporting period. Up to 5 dimensions; each: `{"field": "input.country", "label": "Country", "fallback": "Unknown"}` with optional `buckets`, `sort` (asc/desc/count) and `transform` (dayOfWeek/hourOfDay/weekNumber/successFailure). Default: group by calendar month (monthly mode) or ISO week (weekly mode). See the field-comparison guide for recipes.

## `enableAggregation` (type: `boolean`):

Adds the *Aggregated Insights* view: item volume per product dimension with period-over-period growth and yield alerts. Default: `true`.

## `saveHtmlDashboard` (type: `boolean`):

Saves a self-contained interactive HTML dashboard (KPIs, trend charts, rankings) to the key-value store and links it from the email. Default: `true`.

## `healthScoreWeights` (type: `object`):

Weights of the 0–100 actor health score. Keys (must sum to 1.0): `successRate` (default 0.47), `zeroItemInverse` (0.29), `costEfficiency` (0.24). Omit any key to use its default. Default: unset (use defaults).

## `compareMode` (type: `string`):

How the baseline is chosen for each monitored actor/task. `lastVsBaseline` requires *Baseline run ID*; `lastVsAverage` averages the last *Baseline run count* runs. Ignored entirely when both explicit run IDs below are set. Default: `last2`.

## `baselineRunId` (type: `string`):

Pinned known-good run compared against the latest run. Required when *Comparison mode* is `lastVsBaseline`; ignored when explicit run IDs are set. Default: unset.

## `baselineRunCount` (type: `integer`):

How many historical runs are averaged when *Comparison mode* is `lastVsAverage`. Default: `5`.

## `compareRunId1` (type: `string`):

Compare exactly two runs: this run as baseline versus *Explicit run ID — current*. Both IDs must be set together and must differ. When set, this **takes full precedence** over *Comparison mode* and *Baseline run ID*. Default: unset.

## `compareRunId2` (type: `string`):

The run treated as "current" in an explicit two-run comparison. Must be set together with the baseline run ID above. Default: unset.

## `maxDatasetItems` (type: `integer`):

How many dataset items to fetch per run for field-level comparison. Default: `1000`.

## `enableCompareExcel` (type: `boolean`):

Saves an Excel comparison report (`compare-report.xlsx`) to the key-value store. Default: `false`.

## `combineEmails` (type: `boolean`):

Send one consolidated email covering all compared actors/tasks instead of one email each. Monthly and weekly modes always send a single email. Default: `true`.

## `fieldsAndCompareStrategy` (type: `object`):

Which dataset fields to compare and how, e.g. `{"results.price": "average", "items": {"strategy": "count", "lowerIsBetter": false}}`. Use `[]` to reach into arrays of objects (`reviews[].rating`). 25 strategies available (count, sum, average, coverage, null\_rate, ratio, …) — see the field-comparison guide; `min`/`max` also understand ISO-date strings (e.g. newest `reviews[].reviewDate`). **Omitting this field — or passing an empty object `{}` — runs field *discovery* instead: the report suggests a configuration but compares nothing.** Default: discovery mode.

## `excludeFields` (type: `array`):

Field paths to skip. With strategies configured above: excluded from comparison. Without: omitted from the discovery report. Default: none.

## `enableTrendAnalysis` (type: `boolean`):

Analyzes items/runtime/cost across recent runs (linear regression + streaks) and adds a Trends section to the report. Default: `false`.

## `trendRunCount` (type: `integer`):

How many recent runs feed the trend analysis. Default: `10`.

## `enableAnomalyDetection` (type: `boolean`):

Flags runs whose metrics deviate from recent history by more than the multiplier below (z-score). Works independently of trend analysis. Default: `false`.

## `anomalyStdDevMultiplier` (type: `number`):

Standard-deviation multiplier for flagging anomalies — lower is more sensitive. Default: `2`.

## `alerts` (type: `object`):

One place for every "how big a change matters" setting. Keys (all optional): `changePercent` (default 5 — compare-mode email gate), `itemsCount`/`runtimeSecs`/`costUsd` (each `{warning, critical}` **percent-change** severity bands for compare mode), `avgRuntimeSecs`/`avgCostUsd` (absolute monthly/weekly Threshold Breaches in seconds / USD), `custom` (bands per compared field path; also `failureRate`/`zeroItemRate` for monthly), `yieldDropPercent` (default 20 — aggregation yield alert). Default: sensible compare thresholds.

## `notifyOnSignificantChange` (type: `boolean`):

Compare mode: send the alert email only when at least one metric changed by `alerts.changePercent` or more. Default: `true`.

## `alwaysSendSummary` (type: `boolean`):

Compare mode: when nothing significant changed, still send a short "all clear" summary email. Default: `false`.

## `pricePerItem` (type: `number`):

Your client-facing price per dataset item. When set, reports add Price/Item, Total Price, and Margin (total price = items × price, margin = total price − Apify cost). Default: unset (billing columns hidden).

## `maxRuns` (type: `integer`):

Cap on runs fetched per monitored actor or task. Default: `100`.

## `concurrencyLimit` (type: `integer`):

How many actors/tasks are collected in parallel. Default: `10`.

## `circuitBreakerThreshold` (type: `integer`):

Abort the run once at least this many actors/tasks fail to collect *and* at least half of the processed items have failed. If the first few processed items all fail (e.g. an invalid token), the run aborts immediately without waiting for the rest. Default: `3`.

## `token` (type: `string`):

Token of the account to monitor. Overrides the `APIFY_TOKEN` environment variable when set. Default: `APIFY_TOKEN` if present, otherwise the account running this Actor.

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

Verbose logs for troubleshooting. Default: `false`.

## Actor input object example

```json
{
  "actorMode": "monthly",
  "emailRecipients": [],
  "actorNameInclude": [],
  "useDirectActorRuns": false,
  "taskNameInclude": [],
  "runInputFilterMode": "all",
  "outputMode": "email",
  "emailSections": {
    "showCostBreakdown": true,
    "showSchemaChanges": true,
    "showTrendAnalysis": true,
    "showAnomalyDetection": true,
    "showBuildChanges": true,
    "showRunLinks": true,
    "showFieldDiscovery": true
  },
  "dryRun": false,
  "monthsToAnalyze": 3,
  "includeCurrentMonth": true,
  "weeksToAnalyze": 4,
  "includeCurrentWeek": true,
  "topNActors": 5,
  "enableAggregation": true,
  "saveHtmlDashboard": true,
  "compareMode": "last2",
  "baselineRunCount": 5,
  "maxDatasetItems": 1000,
  "enableCompareExcel": false,
  "combineEmails": true,
  "excludeFields": [],
  "enableTrendAnalysis": false,
  "trendRunCount": 10,
  "enableAnomalyDetection": false,
  "anomalyStdDevMultiplier": 2,
  "alerts": {
    "changePercent": 5,
    "yieldDropPercent": 20
  },
  "notifyOnSignificantChange": true,
  "alwaysSendSummary": false,
  "maxRuns": 100,
  "concurrencyLimit": 10,
  "circuitBreakerThreshold": 3,
  "debug": false
}
```

# Actor output Schema

## `lastReportSummary` (type: `string`):

The stable 'last-report-summary' key-value record — its `artifacts` field carries the actual URLs for this run's Excel workbook, HTML dashboard, manifest, and categorized export (monthly/weekly) or compare Excel/manifest (compare).

## `datasetItems` (type: `string`):

No description

## `compareManifest` (type: `string`):

Only populated in compare mode.

## `compareExcel` (type: `string`):

Only populated in compare mode with enableCompareExcel set.

# 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 = {
    "emailRecipients": [],
    "actorNameInclude": [],
    "taskNameInclude": [],
    "emailSections": {
        "showCostBreakdown": true,
        "showSchemaChanges": true,
        "showTrendAnalysis": true,
        "showAnomalyDetection": true,
        "showBuildChanges": true,
        "showRunLinks": true,
        "showFieldDiscovery": true
    },
    "excludeFields": [],
    "alerts": {
        "changePercent": 5,
        "yieldDropPercent": 20
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("hamza.alwan/monitoring-actor").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 = {
    "emailRecipients": [],
    "actorNameInclude": [],
    "taskNameInclude": [],
    "emailSections": {
        "showCostBreakdown": True,
        "showSchemaChanges": True,
        "showTrendAnalysis": True,
        "showAnomalyDetection": True,
        "showBuildChanges": True,
        "showRunLinks": True,
        "showFieldDiscovery": True,
    },
    "excludeFields": [],
    "alerts": {
        "changePercent": 5,
        "yieldDropPercent": 20,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("hamza.alwan/monitoring-actor").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 '{
  "emailRecipients": [],
  "actorNameInclude": [],
  "taskNameInclude": [],
  "emailSections": {
    "showCostBreakdown": true,
    "showSchemaChanges": true,
    "showTrendAnalysis": true,
    "showAnomalyDetection": true,
    "showBuildChanges": true,
    "showRunLinks": true,
    "showFieldDiscovery": true
  },
  "excludeFields": [],
  "alerts": {
    "changePercent": 5,
    "yieldDropPercent": 20
  }
}' |
apify call hamza.alwan/monitoring-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hamza.alwan/monitoring-actor"
        }
    }
}

```

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/Nm7rlU4WhoqlJfnNF/builds/vN2LPcfS6B1i3j6ji/openapi.json
