# Vendor Incident Monitor - Public Outage Feeds (`maydit/vendor-incident-feed-monitor`) Actor

Track official Apify, Reddit and Cloudflare incident feeds. Publisher updates, source dates and links, keyword filters and saved changes. Recent feed windows; no key or proxy required.

- **URL**: https://apify.com/maydit/vendor-incident-feed-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (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 $1.20 / 1,000 incident observations

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

![Follow vendor incident updates — illustrative workflow](https://api.apify.com/v2/key-value-stores/YGxD9JRpduom8Q5Zd/records/vendor-incident-feed-monitor-8b5c7525118a.png?signature=XEg3arqZs2GMbJXWJpl5)

### Follow vendor incident updates

For vendor watchlists and operational reporting, collect publisher-written incident updates and optionally compare later observations.

**Coverage:** The current official Atom feeds for Apify, Reddit and Cloudflare. Feed windows include scheduled maintenance and are not full archives.

[Open this Actor in Console](https://console.apify.com/actors/BiLYj7iWlY6T5fzJa/input) · [First run](#try-this-actor) · [Results](#result-preview) · [Cost](#usage-and-pricing) · [Full guide](#full-guide)

### Try this Actor

1. Use the existing Apify and Reddit watchlist example below: up to five selected entries per feed and ten saved observations.
2. Review the dataset's source text and timestamps, then inspect the key-value store's `SUMMARY` for feed limits, failures and history updates.

**Read the results correctly:** Publisher dates can describe future maintenance. This Actor does not measure uptime, infer current health or send notifications, and missing entries do not prove resolution.

**Monitor Apify and Reddit Incident Feeds** — copy this input into the JSON editor in Console.

```json
{"vendors":["apify","reddit"],"maxItemsPerSource":5,"maxResults":10}
```

### Result preview

The dataset view highlights these columns:

- **Publisher / vendor** · `vendorName`
- **Canonical incident ID** · `incidentId`
- **Publisher title** · `title`
- **Published update label** · `latestUpdateLabel`
- **Published source date** · `sourcePublishedAt`
- **Source updated at** · `sourceUpdatedAt`

Use the original source links and the field definitions below when interpreting the results. CSV works well for flat columns; JSON preserves nested values.

### Usage and pricing

Base result rate on the FREE tier: **$2 per 1,000 incident observations**. The [Pricing tab](https://apify.com/maydit/vendor-incident-feed-monitor/pricing) shows your plan's result rate and any Actor Start charge. Set a small result limit for the first run; the requested limit is not a guarantee of that many results.

***

### Full guide

Collect official incident-feed observations from **Apify, Reddit and Cloudflare** for vendor watchlists, agency reporting and recurring incident-update workflows. The Actor reads the publishers' public Atom feeds without an API key, login or proxy. It preserves source text and timestamps and can compare new observations with saved history.

#### Start with a small watchlist

Run with `{}` to collect up to ten entries each from Apify and Reddit. The feeds are processed in the requested vendor order, and entries retain publisher order. The Actor supports the three listed vendors; arbitrary status websites and private pages are not supported.

| Vendor input | Official feed |
|---|---|
| `apify` | [Apify incident feed](https://status.apify.com/history.atom) |
| `reddit` | [Reddit incident feed](https://www.redditstatus.com/history.atom) |
| `cloudflare` | [Cloudflare incident feed](https://www.cloudflarestatus.com/history.atom) |

#### Output and source meaning

Each saved row contains `vendor`, `vendorName`, `incidentId` from the canonical incident URL, the exact Atom `sourceEntryId`, `title`, readable `updateText`, `sourcePublishedAt`, `sourceUpdatedAt`, source/feed URLs and `observedAt`. `latestUpdateLabel` is included when the first publisher update paragraph contains a label; it is copied from the markup, not inferred from the prose.

Feed content can include multiple updates for an incident and scheduled maintenance. **A publisher's published date can be a future maintenance time** and is not guaranteed to be the date the announcement was created. Dates and offsets are preserved. The Actor does not calculate outage duration, estimate severity, certify uptime, infer current service health or guarantee that a publisher reported every disruption. Feed metadata may lag the underlying event.

HTML markup is converted to readable text; scripts and styles are removed. Incident pages and linked resources are not fetched. Empty text, malformed timestamps, duplicate incident IDs and links outside the selected vendor's incident path are treated as unusable source data rather than paid error rows.

#### Feed windows and filters

`maxItemsPerSource` chooses the first entries in the publisher's current feed before keyword filtering or history comparison. During validation each feed exposed 25 entries, but publishers control that size and ordering. There is no pagination, archive traversal or claim of full history. A missing entry can simply have fallen outside the window; **no deletion or resolution is inferred from absence**.

`keywords` performs case-insensitive substring matching against title and update text; any listed keyword matches. Empty keywords allow all selected entries. It does not search older feed history. `maxResults` limits confirmed saved rows across sources. SUMMARY distinguishes these selected caps from operational incomplete coverage.

#### Saved comparisons

Enable `comparePrevious` and choose a `snapshotName`. Each incident's title, readable update text, publisher dates and optional update label are watched. The first saved observation is `new`; repeats are `changed` or `unchanged`. Rows expose `changedFields`, `previous` and `previousObservedAt`; without comparison the status is `not_requested`.

`onlyChanges: true` implies comparison. The first run still saves baseline observations; an unchanged repeat succeeds with zero rows. Only confirmed saved output advances history. Failed requests, spending-limit rejected rows and unchanged skipped rows preserve previous observations. The result limit cannot advance history past unsaved entries.

History is scoped by vendor and incident ID within a named store. A reread detects known overlapping writes, but storage does not offer atomic compare-and-swap: **use the same snapshotName sequentially**. A deadline or concurrent change can leave a saved row without its history commit; SUMMARY reports this so repeated output is understandable. Corrupt history is preserved and reported as a failed source.

#### Inputs

| Input | Default | Range / meaning |
|---|---|---|
| `vendors` | Empty, using Apify + Reddit | `apify`, `reddit`, `cloudflare` |
| `maxItemsPerSource` | 10 | 1–100 entries in current publisher order |
| `keywords` | `[]` | Up to 20 plain substring filters |
| `maxResults` | 25 | 1–300 saved rows |
| `comparePrevious`, `onlyChanges` | false | Optional named history |
| `snapshotName` | `default` | 1–40 letters, digits, underscores or hyphens |
| `maxRunSeconds` | 240 | 30–3600 seconds, also bounded by the platform deadline |

#### Three exact examples

##### Apify and Reddit watchlist

Use the [copyable first-run input](#try-this-actor) above.

##### Cloudflare incidents and maintenance

```json
{"vendors":["cloudflare"],"maxItemsPerSource":10,"maxResults":10}
```

##### Persistent comparison

```json
{"vendors":["apify","reddit","cloudflare"],"maxItemsPerSource":3,"maxResults":100,"comparePrevious":true,"snapshotName":"example-vendor-incident-watch"}
```

Repeat the last input with `onlyChanges: true` to omit unchanged entries. Use a separate namespace for production monitoring.

#### Reliability and pricing

Requests are bounded by a shared deadline, public-address validation, robots rules and 3 MiB response/decompression limits. Only fixed official feed endpoints are requested; redirects are rejected. HTTP 429/5xx retries honor Retry-After within the remaining budget. Partial failures and time/spending stops appear in SUMMARY. All-source failures fail the run. Empty feeds, unmatched filters and clean unchanged repeats can legitimately return zero rows with an explanation.

The price is $0.002 per saved incident observation ($2 per 1,000), plus the listed Actor-start event. Repeated unchanged observations cost a result when saved; `onlyChanges` suppresses them. Failed sources and SUMMARY are not paid dataset rows. This provides structured feed observations and saved comparisons; it does not send notifications itself. Connect scheduling and downstream notifications through your Apify workflow.

Node.js 20.19+; pinned Apify SDK 3.7.2. Run `npm ci` and `npm test` for local tests.

### Help with your run

Open the **Issues** tab on this Actor with the run URL, the input field that caused trouble and what you expected to receive. Remove API keys and private information before posting.

[Explore more Mayd-It Actors](https://apify.com/maydit)

### Understand your run

Open **Run report** in the run’s Output tab for saved-record counts, reported source issues and limits, and suggested next steps. Use **CSV export** to take the saved results into a spreadsheet. The existing JSON results and detailed machine-readable summary remain available.

The report reflects this run’s recorded coverage. A successful run or a saved result does not establish that every possible source record was collected.

# Actor input Schema

## `vendors` (type: `array`):

Supported feed IDs: apify, reddit, cloudflare. Empty uses apify and reddit. Only these verified official Atom feeds are supported.

## `maxItemsPerSource` (type: `integer`):

Select the first entries in publisher feed order before keyword filtering and comparison. Feed windows are limited by the publisher; this is not full history.

## `keywords` (type: `array`):

Optional case-insensitive substring matching against title and update text. Any listed keyword matches. Applied after the per-feed window limit; no semantic or severity inference.

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

Maximum confirmed saved incident observations. Unchanged skipped rows do not consume the limit. Selected caps are distinct from source failures.

## `comparePrevious` (type: `boolean`):

Persist only confirmed saved incident observations. First observations are new; repeat sequentially with the same snapshotName.

## `onlyChanges` (type: `boolean`):

Implies comparePrevious. First run emits initial observations. Unchanged repeated observations are skipped and can result in zero saved rows.

## `snapshotName` (type: `string`):

1-40 letters, digits, hyphens or underscores. Use separate namespaces for workflows and never run the same namespace concurrently.

## `maxRunSeconds` (type: `integer`):

Own deadline, also bounded by the platform deadline minus 25 seconds. Requests, retry delays and history work share this budget.

## Actor input object example

```json
{
  "vendors": [
    "apify",
    "reddit"
  ],
  "maxItemsPerSource": 10,
  "keywords": [],
  "maxResults": 25,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

Publisher text and timestamps, canonical incident links and optional saved comparisons. No paid error rows.

## `runReport` (type: `string`):

Readable summary of saved records, reported source coverage, limits and next steps. Available when this run saves its SUMMARY.

## `csvExport` (type: `string`):

Download saved dataset records as a CSV file for spreadsheets and other tools.

## `summary` (type: `string`):

Saved count, selected feed windows, filter and unchanged skips, failed sources, budget stops and committed history.

# 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 = {
    "vendors": [
        "apify",
        "reddit"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/vendor-incident-feed-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 = { "vendors": [
        "apify",
        "reddit",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/vendor-incident-feed-monitor").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 '{
  "vendors": [
    "apify",
    "reddit"
  ]
}' |
apify call maydit/vendor-incident-feed-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maydit/vendor-incident-feed-monitor"
        }
    }
}
```

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/BiLYj7iWlY6T5fzJa/builds/3wDm3DWqpxx9nW0n8/openapi.json
