# Website Change Monitor - Text Diff (`quillray/website-change-monitor`) Actor

See exactly which lines were added or removed on any web page since your last check. Track pricing, terms and policy pages. Pay only per page checked.

- **URL**: https://apify.com/quillray/website-change-monitor.md
- **Developed by:** [Quillray](https://apify.com/quillray) (community)
- **Categories:** Automation, Marketing
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 page checks

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?

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

## Website Change Monitor – Text Diff

**Find out exactly which lines changed on the pages you care about.**

Give it a list of pages, such as a competitor's pricing page, a terms of service page or a privacy policy. On every run it reads the visible text of each page and compares it with the text from the previous run. You get the lines that were added and the lines that were removed, so you see the change itself and not just a note that something changed. There is no subscription. You pay only for the pages you check.

### What it does

- Checks up to 50 pages per run and returns one row per page: first check, unchanged, changed, blocked or error.
- Lists the added and removed lines as they appear on the page.
- Compares only the visible text, so changes in code, scripts or styles do not raise false alarms.
- Lets you ignore small edits with `minChangeChars`.
- Keeps the last good version of each page in your own Apify account. An error never resets the comparison.
- Follows robots.txt and identifies itself to site owners with its own User-Agent.
- Works with Apify Schedules and integrations, so you can get the result after each run.

### How to use it

1. Click **Try for free**.
2. Paste the page URLs, one per line.
3. Click **Start**. The first run saves the text of each page and reports it as a first check.
4. Run it again later, or add a **schedule** (for example once a day). From the second run on you see what changed.
5. Optional: add an **integration** (email, Slack, Make, Zapier) to get the result after each run. The run's status message tells you what happened, for example `2 of 10 pages changed` or `no changes`.

Example input:

```json
{
  "urls": ["https://example.com/pricing", "https://example.com/terms"],
  "minChangeChars": 20
}
```

### Input

| Field            | Default  | What it does                                                                                 |
| ---------------- | -------- | -------------------------------------------------------------------------------------------- |
| `urls`           | required | 1-50 page addresses (http or https). Duplicates are checked once.                            |
| `minChangeChars` | 1        | Changes smaller than this many characters are reported as unchanged. Use it to ignore noise. |
| `maxDiffLines`   | 200      | The most added and removed lines listed per page (1-1000). The full counts are always given. |

### Output

One row for each page. You can view the results as a table in the Output tab or export them as CSV, Excel or JSON.

Example row after a price change:

```json
{
  "url": "https://example.com/pricing",
  "status": "changed",
  "checkedAt": "2026-10-08T06:00:03.120Z",
  "previousCheckedAt": "2026-10-07T06:00:02.870Z",
  "added": ["Pro plan: $39 per month."],
  "removed": ["Pro plan: $29 per month."],
  "addedCount": 1,
  "removedCount": 1
}
```

What the statuses mean:

- **first-check**: the page is checked for the first time. Its text is saved for the next run.
- **unchanged**: the text is the same as last time, or the change is smaller than `minChangeChars`.
- **changed**: lines were added or removed. See `added` and `removed`.
- **blocked-by-robots**: the site's robots.txt does not allow the page, so it was not fetched.
- **error**: the page could not be checked. The `error` field says why, for example `HTTP 404` or `dns-error`.

Other fields: `finalUrl` (the address after redirects), `addedCount` and `removedCount` (full numbers even when the lists are cut), `truncated` (true when a list was cut) and `note` (extra information).

### Cost

**2.00 USD per 1,000 checked pages** (event `page-checked`). Pages that end with an error or are blocked by robots.txt are free. Platform compute of this actor is not charged to you.

**Example:** 20 pages checked once a day for 30 days is 600 checks and costs 1.20 USD.

Tip: set a **maximum cost per run** in the run options if you want a hard limit. Prices can change, and Apify shows the current ones before you run.

### Limitations

- Pages built by JavaScript are not rendered. Only the HTML the server sends is read, so such pages may show little or no text.
- Dynamic parts of a page, such as dates, counters or ads, can look like changes. A higher `minChangeChars` helps.
- Very large pages (about 1 MB of HTML or text) are skipped with an error.
- One run checks up to 50 pages and stops starting new pages after 15 minutes.
- Run one schedule per list at a time. Two runs that check the same page at the same moment can both report the same change.
- Apify integrations notify you after every run, also when nothing changed. The status message shows which case it was.

### Privacy and responsibility

- **The actor runs in your Apify account.** The publisher of this actor does not store, receive or see your input, your results or the text of the pages you monitor.
- **What is stored, and where.** The visible text of each monitored page (never the HTML), its URL and the time of the check are kept in a Key-Value Store named `website-change-monitor-state` in your Apify account. Results go to your run's dataset. You can view, export and delete both at any time in Apify Console.
- **You choose the pages and you are responsible for that choice.** Monitor only pages you may fetch and keep a copy of text from. Check each site's terms of use and the law that applies to you before you add it. The actor follows robots.txt, but that is not a legal check.
- **Personal data.** The actor does not look for personal data, but a page you monitor may contain some, for example names or contact details. Its text is then stored in your store. Whether that is allowed, and how long you may keep it, is your decision and your responsibility.

### FAQ

**Why does the first run show no changes?** The first run has nothing to compare with. It saves the text of each page, and changes show up from the second run on.

**Does an error reset the comparison?** No. An error or a blocked page never changes the saved text. The next successful check compares with the last good version.

**Can I start over for my pages?** Yes. In Apify Console open Storage, then Key-value stores, and delete the store `website-change-monitor-state`. The next run starts with first checks.

**How do I get an email when a page changes?** Add an Apify integration to the actor or to its schedule. It runs after every run, and the status message tells you whether anything changed.

**Will site owners see this actor?** Yes. It sends its own User-Agent with a link to this page and follows robots.txt. If a site does not allow it, the page is reported as blocked and is not charged.

**Something not working, or missing a feature?** Open an issue on this actor's page. We read every one and reply as soon as we can.

# Actor input Schema

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

Public http(s) pages to check, 1 to 50, each at most 2048 characters. Duplicates are removed after normalizing the URL (host case, default port, #fragment). Addresses with a user name or password are rejected, and private or local addresses give an error row.

## `minChangeChars` (type: `integer`):

A page whose added plus removed lines together have fewer characters than this is reported as unchanged (its stored text is still updated). 1 reports every difference, 0 does the same. Use it to ignore tiny edits such as a counter.

## `maxDiffLines` (type: `integer`):

Upper bound on the added lines and on the removed lines listed per page; a longer list is cut and the row is marked truncated (addedCount and removedCount still hold the full numbers).

## Actor input object example

```json
{
  "urls": [
    "https://example.com/pricing",
    "https://example.com/terms"
  ],
  "minChangeChars": 20,
  "maxDiffLines": 200
}
```

# Actor output Schema

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

One row per page: status, added and removed lines, and the time of the previous check.

# 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://example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("quillray/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 = { "urls": ["https://example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("quillray/website-change-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 '{
  "urls": [
    "https://example.com"
  ]
}' |
apify call quillray/website-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,quillray/website-change-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/0d4h1boTAkQ3HgfIV/builds/Ea7t1fomlsndHdB3L/openapi.json
