# AI Content Changes Detector (`sharlmagne/ai-content-changes-detector`) Actor

Monitors pages on a schedule and uses an LLM to judge whether a change is meaningful (pricing update, policy change, new announcement) vs. noise (ads, timestamps, session IDs). Notifies you only when something worth your attention actually happened.

- **URL**: https://apify.com/sharlmagne/ai-content-changes-detector.md
- **Developed by:** [Sharlmagne Henry](https://apify.com/sharlmagne) (community)
- **Categories:** AI, Automation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.15 / meaningful change detected

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

## AI Content Changes Detector

Monitors a list of URLs on a schedule and uses an LLM to judge whether a change is
**meaningful** (pricing update, policy change, new announcement) or just **noise**
(rotating ads, timestamps, session IDs, cookie banners). You only hear about it when
something worth your attention actually happened.

### Who this is for

- Marketers/agencies tracking competitor pricing or promo pages
- Legal/compliance teams watching policy or ToS pages
- Solo devs/SEO folks tracking client competitor sites
- Anyone currently manually refreshing a page to check "did this change?"

#### What does AI Content Changes Detector do?

Give it a list of URLs and it checks each one on the schedule you set, comparing the
current page text against the last time it looked. When it finds a difference, it
doesn't just report "something changed" — it sends the diff to an LLM, which decides
whether the change is actually worth knowing about (a price, a policy, a new section)
or just noise (a rotating ad, a "last updated" timestamp, a session ID in a URL). You
get a one-sentence summary only for the changes that matter.

#### Why use an LLM instead of a plain diff tool?

Plain diff/uptime-style monitors flag every byte that changed, including things that
change on every single page load — ads, view counters, A/B test buckets, cache-busting
query strings. That noise trains you to ignore the alerts, which defeats the point of
monitoring in the first place. Because this actor classifies each diff with an LLM
before deciding to notify you, it filters that noise out automatically and only
surfaces changes a human would actually care about.

#### How do I use it?

1. Create a free Apify account.
2. Open this actor and add one or more URLs to the `urls` input field.
3. Optionally set `changeSensitivity`, `ignoreSelectors`, or `keywordsOfInterest` to tune what counts as meaningful for your use case.
4. Click **Start**. The first run establishes a baseline for each URL — no comparison is possible yet.
5. Add a **Schedule** (Apify's native scheduler, under the Schedules tab) so it re-checks automatically — daily is a common cadence.
6. From the second run onward, you'll get a dataset row per URL every run, and a notification only when something meaningful changed.

### Input

| Field | Type | Required | Notes |
|---|---|---|---|
| `urls` | array of strings | yes | Pages to monitor |
| `changeSensitivity` | `low` | `medium` | `high` | no (default `medium`) | Low = only major/structural/numeric changes. High = also flags smaller wording changes |
| `ignoreSelectors` | array of strings | no | CSS selectors stripped before diffing (ads, timestamps, cookie banners) |
| `keywordsOfInterest` | array of strings | no | Terms the LLM weighs more heavily as meaningful if touched |
| `notificationWebhook` | string | no | POST target for meaningful-change notifications (e.g. a Slack incoming webhook, a Zapier/Make catch hook). You can also use Apify's built-in Slack/email/webhook integrations instead |

### How it works

1. Checks each URL against its previous snapshot, so it only ever looks at what's new.
2. Fetches the current page and extracts the clean, visible text — scripts, styles, and anything matched by `ignoreSelectors` are stripped out first.
3. Diffs the current text against the last snapshot.
4. If there's a diff, sends just the changed snippet (not the whole page) to an LLM, which classifies it as meaningful or noise and writes a one-sentence summary.
5. Every check is logged to the dataset as a row, with `status` one of `baseline` (first check for this URL), `no_change`, `noise`, `meaningful`, or `error`.
6. You're only notified — and only charged the primary event — when a change is classified as `meaningful`.

Use Apify's native **Scheduler** to run this on a recurring cadence (e.g. daily) — no cron setup required.

### Sample output

One row is written to the dataset for every URL checked, every run:

```json
[
  {
    "url": "https://example.com/pricing",
    "timestamp": "2026-08-22T21:21:00.218Z",
    "status": "meaningful",
    "meaningful": true,
    "summary": "Pro Plan price increased from $9/month to $15/month.",
    "diffSnippet": "- Pro Plan: $9/month\n+ Pro Plan: $15/month"
  },
  {
    "url": "https://example.com/blog",
    "timestamp": "2026-08-22T21:21:03.512Z",
    "status": "noise",
    "meaningful": false,
    "summary": "",
    "diffSnippet": "- Last updated: 2 hours ago\n+ Last updated: just now"
  },
  {
    "url": "https://example.com/status",
    "timestamp": "2026-08-22T21:21:05.001Z",
    "status": "no_change",
    "meaningful": false,
    "summary": ""
  }
]
```

`diffSnippet` is only present on rows where a diff was actually sent to the LLM
(`noise` or `meaningful`). Rows with `status: "error"` include an `error` field
instead, describing the fetch failure.

### Pricing (Pay Per Event)

| Event | Trigger | Price |
|---|---|---|
| `meaningful_change_detected` | A real, meaningful change is detected | $0.15 each |
| `url_checked` | Every URL checked, regardless of outcome | $0.002 each |

You're charged for value delivered — a real, meaningful change — not for the actor simply running checks.

### Setup notes

- First run for any URL only establishes a baseline; you won't get a "change" event until the next run finds a diff against it.
- Snapshots persist across scheduled runs, so each check compares against the last one automatically — no need to manage state yourself.
- Respect `robots.txt` and each target site's terms of service — this actor only fetches public, unauthenticated pages you supply.

### Known limitations / edge cases

- Anti-bot pages will fail gracefully per-URL (logged as an error row) rather than crashing the whole run.
- Only the diffed snippet is ever sent to the LLM, capped at ~4000 characters, to control cost and avoid token limits on very large pages.
- Layout-only redesigns can still trigger false positives if `ignoreSelectors` isn't tuned — add selectors for anything that changes on every load (ads, "last updated" timestamps, view counters).

### Is it legal to monitor a page like this?

This actor only fetches public, unauthenticated pages you supply — it doesn't log in,
bypass paywalls, or access anything not already visible to any visitor. That said,
scraping laws and each site's terms of service vary, so it's on you to make sure your
use case respects `robots.txt` and the target site's ToS. If you're unsure, consult a
lawyer.

### Your feedback

Found a bug or have a feature request? Open an issue on this actor's **Issues** tab in
Apify Console.

# Actor input Schema

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

Pages to check for meaningful changes on each run.

## `changeSensitivity` (type: `string`):

Low flags only major/structural or numeric changes. High also flags smaller wording changes.

## `ignoreSelectors` (type: `array`):

CSS selectors to strip before diffing, e.g. ads, cookie banners, timestamps.

## `keywordsOfInterest` (type: `array`):

If a diff touches these terms, the LLM weighs it more heavily as meaningful.

## `notificationWebhook` (type: `string`):

Optional. Where to POST results when a meaningful change is detected (e.g. a Slack incoming webhook URL). You can also rely on Apify's built-in Slack/email/webhook integrations instead of setting this.

## Actor input object example

```json
{
  "urls": [
    "https://news.ycombinator.com/"
  ],
  "changeSensitivity": "medium",
  "ignoreSelectors": [],
  "keywordsOfInterest": []
}
```

# Actor output Schema

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

Every URL checked this run, one row each, with status/meaningful/summary and a diff snippet when a diff was actually classified.

# 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 = {
    "urls": [
        "https://news.ycombinator.com/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sharlmagne/ai-content-changes-detector").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 = { "urls": ["https://news.ycombinator.com/"] }

# Run the Actor and wait for it to finish
run = client.actor("sharlmagne/ai-content-changes-detector").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 '{
  "urls": [
    "https://news.ycombinator.com/"
  ]
}' |
apify call sharlmagne/ai-content-changes-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sharlmagne/ai-content-changes-detector"
        }
    }
}

```

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/gMW7VhFbLa8Xcl6cM/builds/mBUkvAkNO4PepnKA9/openapi.json
