# Website Change Monitor - Page Diff & Alerts (`logiover/website-change-monitor`) Actor

Monitor any website for content changes automatically.

- **URL**: https://apify.com/logiover/website-change-monitor.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Developer tools, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## 🔔 Website Change Monitor — Page Diff & Content Alerts

Monitor any number of web pages for changes automatically. Get detailed diff reports showing exactly **what was added, removed, or modified** since your last check. Run it on a daily or weekly schedule and receive actionable change alerts without manually refreshing pages. This is the **text-content counterpart to visual screenshot monitoring** — faster, cheaper, and easier to parse programmatically.

### 🎯 Why Website Change Monitor?

Manually checking competitor pricing pages, regulation updates, job postings, or product stock status is a waste of time. This actor automates the entire detection pipeline:

1. **Run 1 (Baseline)**: Fetches each URL, extracts the monitored content, computes a SHA-256 hash, and stores the full text snapshot in key-value storage. Returns "baseline saved" for every URL.

2. **Run 2+ (Diff)**: Re-fetches each URL, compares the hash against the stored baseline. If different → computes a line-by-line diff, reports what changed (added/removed lines + % change), and **updates the baseline** so the next run compares against the latest version.

3. **Schedule it**: Set up a daily or weekly recurring run in Apify Console. Each run produces a structured dataset you can pipe to email, Slack, or any webhook via Apify Integrations.

### 🆚 Screenshot Monitoring vs. Change Monitoring

| Feature | Screenshot Capture | Change Monitor |
|---------|-------------------|----------------|
| Detection method | Visual (pixel comparison) | Text (content diff) |
| File size | ~1–5 MB per URL | ~1–5 KB per URL |
| Cost per check | Higher (rendering overhead) | Lower (HTTP fetch only) |
| Best for | Visual regression, design QA | Text content, pricing, availability |
| Machine-readable diff | ❌ | ✅ (added/removed lines, %) |
| Parse with scripts | Hard (requires CV) | Easy (JSON diff report) |

**Use both together** — screenshots for visual changes, change monitor for content changes.

### 📊 Output Fields

| Field | Description |
|-------|-------------|
| `url` | The monitored URL |
| `hasChanged` | `true` if content differs from previous run |
| `changePercent` | Approximate percentage of lines changed (0–100) |
| `addedLines` | Number of new lines detected |
| `removedLines` | Number of lines no longer present |
| `currentContentHash` | SHA-256 hash of current content |
| `previousContentHash` | SHA-256 hash of previous baseline |
| `diffSummary` | Human-readable summary of added/removed lines (first 5 each) |
| `checkedAt` | ISO 8601 timestamp |

### ⚙️ Smart Filtering

#### Monitor Specific Page Sections
Use `cssSelectors` to focus on what matters. Instead of monitoring the entire page (which includes ads, nav bars, footers), target exactly the content you care about:

```json
["h1", ".price-value", "#job-listings", "[data-testid='stock-status']"]
````

#### Ignore Noisy Elements

Use `ignoreSelectors` to strip out dynamic elements that change on every page load but aren't meaningful — timestamps, ad containers, session IDs, random recommendation widgets:

```json
[".timestamp", "#dynamic-ad", ".recommendations-carousel", ".live-counter"]
```

#### Strip Numbers

Enable `stripNumbers: true` to ignore changes that only involve numbers. Perfect for pages where the meaningful content stays the same but counters, view counts, or timestamps fluctuate:

```
Before: "Viewed 1,234 times | Updated 2026-06-30"
After:  "Viewed #,### times | Updated ####-##-##"
```

### 🎯 Real-World Use Cases

#### Competitor Price Tracking

Monitor `/pricing` pages of 50 competitors. Get alerted when any of them changes their pricing tiers, feature lists, or plan names. Combine with a daily Apify schedule and a Slack webhook integration.

#### Regulation & Legal Compliance

EU Digital Services Act, SEC filings, FDA recalls — government and regulatory pages publish updates without RSS feeds. Monitor them and get diffs of exactly what changed in the regulation text.

#### Job Board Monitoring

Track company career pages for new job postings. Monitor specific CSS selectors that contain job listings. When a new role appears → diff shows the new job title and description.

#### E-Commerce Stock & Price Alerts

Monitor product pages for "Out of Stock" → "In Stock" transitions. Target the stock status element and get alerted when availability changes.

#### News & Blog Monitoring

Track competitors' blog pages or news sections. See when new articles are published and what their headlines are — without visiting each site manually.

### 🚀 Setup for Recurring Monitoring

1. **First run**: Execute once with all your target URLs → establishes baselines
2. **Schedule**: In Apify Console, set up a recurring schedule (daily at 9 AM, hourly, etc.)
3. **Integrate**: Connect the dataset to Make/Zapier/n8n → send email/Slack alerts when `hasChanged: true`
4. **Review**: Check the diff summary to decide if the change is worth acting on

### 💰 Pricing

Pay per event — you're charged only for the HTTP requests made during each monitoring run. No monthly subscription, no minimum usage. Each URL check costs a fraction of a compute unit. Monitoring 100 URLs daily costs approximately $2–5/month on Apify's free tier and scales linearly.

### ❓ FAQ

**Q: How is "change" detected?**
A: The actor computes a SHA-256 hash of the extracted text content. If the hash differs from the stored baseline → change detected. It then does a line-by-line comparison to produce the diff summary.

**Q: Where are baselines stored?**
A: In Apify's key-value store under the actor's namespace. They persist across runs and are automatically updated after each detected change.

**Q: Can I reset baselines?**
A: Yes — delete the key-value store records via Apify Console's Storage tab, or just run once with different input fields to create fresh baselines.

**Q: Does it handle JavaScript-rendered pages?**
A: This actor uses HTTP fetch (got-scraping), which handles server-rendered content. For JavaScript-heavy SPAs, use the Screenshot Capture actor or a custom Playwright-based monitor.

**Keywords:** website change monitor, page change detection, website diff tool, content change alert, web page monitoring, competitor price tracker, regulation change monitor, automated website monitoring, page content tracker, url change detection, website change alert api, content monitoring tool, page diff api, website change detection service, recurring website checker

#### How do I get alerted when a competitor changes their pricing page?

Add the pricing page URLs and target the price section with cssSelectors. On each scheduled run the monitor diffs the text and flags exactly what changed so you can alert via Slack or email.

#### How do I monitor a page while ignoring ads and timestamps?

Use ignoreSelectors to strip ad, nav and timestamp elements before comparison, or enable stripNumbers to skip numeric-only changes, so you only get alerts on meaningful content edits.

### 📝 Changelog

#### 2026-07-01

- Maintenance pass: re-verified end-to-end on live data and confirmed successful runs within the 5-minute quality window on the default input.
- Sharpened Store metadata (SEO title & description) and expanded the FAQ with high-intent, long-tail questions for easier discovery in Google and Apify Store search.
- Added ready-to-run example tasks that cover common real-world use cases.

# Actor input Schema

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

List of URLs to monitor for content changes. On first run a baseline snapshot is saved. Subsequent runs compare against previous snapshots.

## `cssSelectors` (type: `array`):

CSS selectors to target specific page sections for monitoring. Leave empty to monitor the full page text content.

## `stripNumbers` (type: `boolean`):

Ignore numeric-only changes. Useful for pages with dynamic counters, IDs, or timestamps that change every load but are not meaningful changes.

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

CSS selectors for elements to remove before comparison. Useful for stripping ads, nav bars, timestamps, and recommendation widgets.

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

Proxy settings. Use residential proxies if target sites block datacenter IPs.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Main_Page"
    }
  ],
  "cssSelectors": [],
  "stripNumbers": false,
  "ignoreSelectors": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `url` (type: `string`):

The URL monitored for changes

## `hasChanged` (type: `string`):

Whether the page content changed since the last baseline snapshot

## `changePercent` (type: `string`):

Approximate percentage of lines changed (0-100)

## `addedLines` (type: `string`):

Number of new lines detected

## `removedLines` (type: `string`):

Number of lines no longer present

## `currentContentHash` (type: `string`):

SHA-256 hash of the current page content

## `previousContentHash` (type: `string`):

SHA-256 hash of the previous baseline

## `diffSummary` (type: `string`):

Human-readable summary of added and removed lines

## `checkedAt` (type: `string`):

ISO 8601 timestamp of when the check was performed

# 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": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://en.wikipedia.org/wiki/Main_Page"
        }
    ],
    "cssSelectors": [],
    "ignoreSelectors": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/website-change-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": [
        { "url": "https://apify.com" },
        { "url": "https://en.wikipedia.org/wiki/Main_Page" },
    ],
    "cssSelectors": [],
    "ignoreSelectors": [],
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/website-change-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 '{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Main_Page"
    }
  ],
  "cssSelectors": [],
  "ignoreSelectors": []
}' |
apify call logiover/website-change-monitor --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Website Change Monitor - Page Diff & Alerts",
        "description": "Monitor any website for content changes automatically.",
        "version": "1.0",
        "x-build-id": "d4K4CbVw3YEk4uyUr"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/logiover~website-change-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-logiover-website-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/logiover~website-change-monitor/runs": {
            "post": {
                "operationId": "runs-sync-logiover-website-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/logiover~website-change-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-logiover-website-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "URLs to Monitor",
                        "type": "array",
                        "description": "List of URLs to monitor for content changes. On first run a baseline snapshot is saved. Subsequent runs compare against previous snapshots.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "cssSelectors": {
                        "title": "CSS Selectors (Optional)",
                        "type": "array",
                        "description": "CSS selectors to target specific page sections for monitoring. Leave empty to monitor the full page text content.",
                        "default": []
                    },
                    "stripNumbers": {
                        "title": "Strip Numbers",
                        "type": "boolean",
                        "description": "Ignore numeric-only changes. Useful for pages with dynamic counters, IDs, or timestamps that change every load but are not meaningful changes.",
                        "default": false
                    },
                    "ignoreSelectors": {
                        "title": "Ignore Selectors",
                        "type": "array",
                        "description": "CSS selectors for elements to remove before comparison. Useful for stripping ads, nav bars, timestamps, and recommendation widgets.",
                        "default": []
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings. Use residential proxies if target sites block datacenter IPs.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
