# B2B SaaS Changelog & Feature Intelligence Monitor (`dataflow-tools/saas-changelog-feature-intelligence-monitor`) Actor

Extracts, normalizes, and diffs changelog/release-note data from any SaaS URL via RSS/Atom, Next.js data, HeadwayApp, Canny, Beamer, GitHub Releases, or generic Readability fallback. Outputs clean LLM-ready Markdown and JSON with stateful cross-run change detection.

- **URL**: https://apify.com/dataflow-tools/saas-changelog-feature-intelligence-monitor.md
- **Developed by:** [DataFlow Tools](https://apify.com/dataflow-tools) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 changelog entries

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/actors/running/actors-in-store.md#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

## B2B SaaS Changelog & Feature Intelligence Monitor

Track any SaaS competitor's changelog automatically. This Actor extracts, normalizes, and diffs changelog / release-note data from **any** SaaS URL — RSS feeds, Next.js apps, HeadwayApp, Canny, Beamer, GitHub Releases, or plain custom HTML — and outputs clean, LLM-ready Markdown plus structured JSON. Only genuinely new entries since your last run are flagged, so you can pipe results straight into Slack, Notion, or a `n8n` / `Make.com` workflow without re-processing duplicates.

### Why use this Actor?

- **Works on almost any changelog, out of the box.** A strict extraction waterfall tries the highest-fidelity method first and falls back gracefully:
  1. RSS / Atom / JSON feed discovery
  2. Next.js `__NEXT_DATA__` hydration payload
  3. Platform adapters — HeadwayApp, Canny, Beamer, GitHub Releases
  4. Generic Readability-based fallback for any other custom HTML page
- **Stateful diffing, no duplicate noise.** Every entry gets a stable content hash stored in a Key-Value Store across runs, so scheduled runs only report what's actually new.
- **LLM-ready output.** Every entry ships as clean Markdown (HTML boilerplate stripped) with an estimated token count, ready to drop into a prompt, RAG pipeline, or AI agent.
- **Zero anti-bot headaches.** Changelogs are public pages — this Actor uses a fast, lightweight `CheerioCrawler` (HTTP-only), no headless browser required.
- **Auto-categorized.** Each entry is tagged as `New Feature`, `Improvement`, `Bug Fix`, `Breaking Change`, `Security`, or `General Update` based on content heuristics.

### Use cases

- **Competitive intelligence** — monitor competitors' changelogs and get notified the moment they ship a feature that matters to you.
- **Product management** — keep a single feed of everything shipped across your own product's multiple changelog sources (marketing site + docs + GitHub).
- **AI workflows** — feed new releases into an LLM to auto-draft competitor battlecards, sales talk tracks, or internal Slack digests.
- **VC / market research** — track feature velocity across a portfolio of SaaS companies over time.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `startUrls` | array of strings | ✅ | Absolute `http(s)` URLs to changelog, release-notes, or GitHub Releases pages (e.g. `https://linear.app/changelog`, `https://github.com/vercel/next.js/releases`). |
| `onlyNewSinceLastRun` | boolean | – | When `true` (default), only entries not seen in a previous run are included in the output. Set `false` to always emit the full current snapshot. |
| `maxItemsPerSource` | integer | – | Optional cap on how many entries to keep per source URL (most recent first). Leave empty for no limit. |
| `requestTimeoutSecs` | integer | – | Per-URL timeout in seconds for fetching the page and any discovered feed. Default `60`. |
| `proxyConfiguration` | object | – | Optional Apify Proxy or custom proxy URLs. |

#### Example input

```json
{
  "startUrls": [
    "https://linear.app/changelog",
    "https://github.com/vercel/next.js/releases",
    "https://supabase.com/changelog"
  ],
  "onlyNewSinceLastRun": true,
  "requestTimeoutSecs": 60
}
```

### Output

One dataset record per **changelog entry** (not per source URL) — the actual scraped content, flat and ready to consume:

```json
{
  "sourceUrl": "https://linear.app/changelog",
  "hostname": "linear.app",
  "status": "OK",
  "extractionMethod": "rss",
  "isNew": true,
  "scrapedAt": "2026-08-27T04:10:32.123Z",
  "id": "b2c1e4f9a6d7...",
  "title": "Improved keyboard navigation in the Inbox",
  "contentMarkdown": "We've reworked keyboard shortcuts across the Inbox...\n\n- Jump between threads with J/K\n- Archive with E\n- Snooze with H",
  "features": [
    "Jump between threads with J/K",
    "Archive with E",
    "Snooze with H"
  ],
  "url": "https://linear.app/changelog/2026-08-20-inbox-keyboard-nav",
  "publishedAt": "2026-08-20T00:00:00.000Z",
  "category": "Improvement",
  "tags": [],
  "estimatedTokens": 84
}
```

- `contentMarkdown` — the full release body/content (from the RSS `<content:encoded>`/`<description>`, Atom `<content>`/`<summary>`, or the matched adapter's HTML), converted to clean Markdown.
- `features` — the top bullet-point lines pulled out of `contentMarkdown`, for a quick scannable summary without parsing the full body yourself.
- `isNew` — whether this entry wasn't seen in any previous run (see `onlyNewSinceLastRun` below).

A source URL that fails to process still produces exactly one record, so a single bad URL never crashes the whole run and the failure stays visible in the dataset:

```json
{
  "sourceUrl": "https://example.com/broken",
  "hostname": "example.com",
  "status": "FAILED",
  "error": "Request timed out",
  "scrapedAt": "2026-08-27T04:10:32.123Z"
}
```

### Pricing

This Actor uses Apify's **Pay-Per-Event** model — no flat platform subscription:

| Event | Price | When it's charged |
|---|---|---|
| Base run cost | $0.005 | Once per Actor run |
| Per URL processed | $0.005 | Per source URL crawled |
| Per new changelog detected | $0.02 | Per genuinely new entry found (skipped for duplicates) |

### Integrations

Connect the dataset output to:

- **Slack / Discord** — via Apify's built-in webhook integrations, alert your team the moment a competitor ships something new.
- **n8n / Make.com** — trigger a scenario on new dataset items to auto-summarize with an LLM and post to Notion, Airtable, or a CRM.
- **Zapier** — use the Apify Zapier integration to route new entries into any downstream app.

#### Example recipe: Automated Slack Digest (Make.com / n8n)

Turn this into a daily "what did our competitors ship" digest with zero manual work:

1. **Schedule the Actor** — in the Apify Console, open this Actor → **Schedules** tab → create a new schedule (e.g. `0 8 * * *` for 08:00 AM UTC daily) with your list of competitor `startUrls`.
2. **Keep `onlyNewSinceLastRun: true`** in the schedule's input — this ensures the run only reports items that weren't already seen in a previous run, so your digest never repeats itself.
3. **Add a webhook on run completion** — Actor → **Integrations** → **Webhooks** → create one for the `ACTOR.RUN.SUCCEEDED` event, pointing at:
   - a **Make.com** scenario's "Custom Webhook" trigger, or
   - an **n8n** workflow's "Webhook" node.
4. **Fetch the dataset in your scenario/workflow** — the webhook payload includes `resource.defaultDatasetId`; use Apify's "Get Dataset Items" module/node (or a plain `GET https://api.apify.com/v2/datasets/{datasetId}/items`) to pull the new records.
5. **Filter for `isNew: true`** so the flow (and your Slack channel) stays silent on days with no changes.
6. **Format and post to Slack/Discord** — each dataset record is already one changelog entry, so post one message per record (or group them into one digest) to your team's `#competitor-intel` channel, including `title`, `category`, `url`, and the `features` bullet list or full `contentMarkdown`.

This gives you a fully automated, noise-free "competitor changelog digest" landing in Slack every morning with $0 infrastructure to maintain.

### Model Context Protocol (MCP) Setup

You can also call this Actor as a live tool directly from an AI agent like **Claude Desktop** or **Cursor**, via [Apify's MCP server](https://mcp.apify.com). Once connected, you can just ask your agent things like *"Check linear.app/changelog for anything new"* and it will run this Actor and read the results back into the conversation.

#### Option A — Hosted remote server (recommended, no install)

No `npx`, no local Node process, and it auto-updates. Add a custom MCP connector pointing at:

```text
https://mcp.apify.com
```

- **Claude Desktop**: Settings → Connectors → Add custom connector → paste the URL above → Connect (authorizes via OAuth, no token to copy/paste).
- **Cursor**: Settings → MCP → Add new MCP server → paste the URL above.

#### Option B — Local stdio server

Add this to `claude_desktop_config.json` (Claude Desktop) or `.cursor/mcp.json` (Cursor):

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": [
        "-y",
        "@apify/actors-mcp-server",
        "--actors",
        "dataflow-tools/saas-changelog-feature-intelligence-monitor"
      ],
      "env": {
        "APIFY_TOKEN": "YOUR_APIFY_API_TOKEN"
      }
    }
  }
}
```

- Get `YOUR_APIFY_API_TOKEN` from [Apify Console → Settings → Integrations](https://console.apify.com/settings/integrations).
- The `--actors` value whitelists which Actor(s) show up as tools — swap in a comma-separated list to expose more than one.
- Fully quit and reopen Claude Desktop / Cursor after saving the config for it to pick up the new server.

> **Note:** this only works with *your own* `APIFY_TOKEN` while the Actor is private. To let other people reference `dataflow-tools/saas-changelog-feature-intelligence-monitor` with their own tokens, publish the Actor to the Apify Store first (Console → Actor → Publication tab).

### How it works (extraction waterfall)

1. **RSS/Atom/JSON feed discovery** — looks for `<link rel="alternate">` tags and common feed paths (`/feed`, `/rss.xml`, `/changelog.rss`, etc.).
2. **Next.js hydration data** — parses `<script id="__NEXT_DATA__">` for server-rendered `pageProps` containing changelog entries.
3. **Platform adapters** — dedicated parsers for HeadwayApp, Canny, Beamer widgets, and GitHub Releases (converted to their Atom feed).
4. **Generic fallback** — uses Mozilla's Readability algorithm to extract the main article content from any other page, then splits it into entries by heading.

Whichever method succeeds first is used — later stages are only attempted if earlier ones return no results.

### FAQ

**Does this work on Canny/Headway/Beamer widgets even if they're client-side rendered?**
For platforms that render primarily via JavaScript (e.g. some Beamer embeds), the Actor extracts whatever is present in the initial server-rendered HTML or inlined script payload. If a source renders 100% client-side with no fallback data, the generic Readability extractor is used as a last resort.

**Can I track only new items and never see duplicates again?**
Yes — leave `onlyNewSinceLastRun` at its default (`true`). The Actor persists a stable hash per entry across runs in a named Key-Value Store, so re-running on a schedule only surfaces what's new.

**Can I run this on a schedule?**
Yes — set up an Apify Schedule against this Actor (e.g. daily or hourly) with the same input, and combine it with a webhook to get notified only when `newItemCount > 0`.

**What if a source URL is temporarily down?**
That source's record is marked `"status": "FAILED"` with an `error` message; all other URLs in the same run are processed normally.

# Actor input Schema

## `startUrls` (type: `array`):

Absolute http(s) URLs to changelog, release-notes, or GitHub Releases pages (e.g. https://linear.app/changelog, https://supabase.com/changelog, https://github.com/vercel/next.js/releases).

## `onlyNewSinceLastRun` (type: `boolean`):

When enabled, previously seen items (tracked via a stable per-item hash in the Actor's Key-Value Store) are excluded from the dataset output. Disable to always emit the full current snapshot.

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

Optional cap on how many changelog entries to keep per source URL, most-recent-first as returned by the extractor. Leave empty for no limit.

## `requestTimeoutSecs` (type: `integer`):

Per-URL timeout for fetching the page and any discovered feed URLs.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy or custom proxy URLs to use for fetching source pages.

## Actor input object example

```json
{
  "startUrls": [
    "https://github.com/vercel/next.js/releases"
  ],
  "onlyNewSinceLastRun": true,
  "requestTimeoutSecs": 60,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "startUrls": [
        "https://github.com/vercel/next.js/releases"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataflow-tools/saas-changelog-feature-intelligence-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 = {
    "startUrls": ["https://github.com/vercel/next.js/releases"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dataflow-tools/saas-changelog-feature-intelligence-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 '{
  "startUrls": [
    "https://github.com/vercel/next.js/releases"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dataflow-tools/saas-changelog-feature-intelligence-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataflow-tools/saas-changelog-feature-intelligence-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/9j3bLmbXNVl6Pu5of/builds/fqch64I1rRv3pl1uH/openapi.json
