# Public Website Change & Compliance Monitor (`futurefortune/public-website-change-compliance-monitor`) Actor

Monitor public web pages, persist a baseline, and return compact change events for meaningful content changes.

- **URL**: https://apify.com/futurefortune/public-website-change-compliance-monitor.md
- **Developed by:** [Liam King](https://apify.com/futurefortune) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 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.

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

## Public Website Change Monitor

Check public web pages for text changes and see what was added or removed. This Actor saves a baseline, compares it with the next successful check, and returns structured results in Apify.

Use it for small lists of public documentation, policy, pricing, or status pages whose content is available in the initial HTML. Run checks in the cloud without keeping your computer on.

### Try it in two runs

1. Click **Try for free** on the Store page and sign in to Apify. Account credits and the displayed Actor pricing apply.
2. Enter one public URL. Leave **Output only actionable rows** off for the first test.
3. Run the Actor. `first_seen` means the initial baseline was saved.
4. Run again with the same URL, settings, and state namespace. `unchanged` means the normalized content matches; `changed` means its hash differs and meets the configured threshold.
5. Inspect the Output tab. Export results as JSON or CSV through Apify.

```json
{
  "urls": ["https://example.com"],
  "mode": "text",
  "ignoreNumbers": false,
  "minChangeRatio": 0,
  "notifyOnly": false,
  "respectRobots": true,
  "stateKey": "my-first-monitor",
  "timeoutMs": 30000
}
```

Replace the example URL with a page you are authorized to monitor. Start with one page to confirm it returns the content you need.

### Useful monitoring jobs

| Job | Suggested starting settings |
| --- | --- |
| Public pricing page | Keep `ignoreNumbers` false so numeric price changes remain visible. |
| Documentation or policy page | Use text mode and inspect the added/removed line preview. |
| Small agency watchlist | Use a different `stateKey` for each independent monitoring job. |

Each run checks the supplied URLs once. For recurring checks, save the input as an Apify task and configure an Apify schedule. Start with daily checks if that meets your needs. Avoid overlapping runs that share the same state namespace.

### Settings

| Setting | What it does |
| --- | --- |
| `urls` | Between 1 and 100 public HTTP(S) URLs per run. |
| `selector` | Optional basic `#id`, `.class`, or tag selector. This is a simple extractor, not a full browser CSS engine; test it on your page before scheduling. |
| `mode` | `text` removes tags and common script/style noise; `html` compares cleaned markup. |
| `ignorePatterns` | Regular expressions removed before comparison. Start without these, then add only patterns you understand. |
| `ignoreNumbers` | Replaces numbers before comparison. Leave false when tracking prices or dates. |
| `minChangeRatio` | A heuristic line-change threshold. Start at 0; it is not a percentage of characters changed. |
| `notifyOnly` | Suppresses unchanged, below-threshold, and robots-blocked rows. First-seen, changed, and error rows remain. It does not send notifications. |
| `respectRobots` | Enables the current basic robots.txt check. A blocked or unreadable robots file produces `robots_blocked`. |
| `stateKey` | Persistent monitoring namespace. Reuse it across runs; choose a new one when changing comparison settings or restarting a baseline. |
| `timeoutMs` | Page request timeout, between 5,000 and 120,000 milliseconds. |

### Understand your results

| Status | Meaning |
| --- | --- |
| `first_seen` | Baseline saved; there is no previous observation to compare. |
| `unchanged` | Normalized content matches the previous successful check. |
| `changed` | Content hash changed and passed the threshold. |
| `below_threshold` | Content changed but did not pass the threshold. The baseline still advances. |
| `robots_blocked` | The robots check prevented the page request. |
| `error` | The page could not be processed. Inspect the error message. |

Successful page rows include URL, check time, HTTP status, hashes, added/removed lines, and a compact preview. The diff shows up to 20 added and 20 removed lines. Counts and the threshold score use that bounded diff; they are not a complete audit of a large document. Reordered or repeated lines may not be represented fully.

### Pricing

The configured launch price is **US$0.01 per dataset row**, plus **US$0.00001 per Actor start**, with platform usage included in the event price. Check the Pricing tab for current rates before running.

With `notifyOnly: false`, first-seen, unchanged, changed, below-threshold, error, and robots-blocked rows all count as results. A result charge does not mean a change was detected. With `notifyOnly: true`, fewer rows may be written, but errors and first observations still produce output.

For example, 10 URLs checked daily for 30 days with one row per URL per run produces 300 rows: US$3.00 in result charges plus US$0.00030 in start charges, before any applicable taxes or account-specific adjustments. This is an illustration, not a promise of usage or results.

### Limits and troubleshooting

- Fetches the initial page HTML. JavaScript rendering, screenshots, login sessions, and anti-bot bypass are not included.
- Does not send email, Slack, or SMS alerts. Use a separately configured workflow if you need notifications.
- A missing selector can yield empty extracted content. Verify your selection before relying on a scheduled check.
- Baselines keep up to 250,000 characters. Use small pages; large-page comparisons may be incomplete.
- The current robots handling is basic. Choose authorized targets; a permitted request is not a determination of legal rights.
- This tool tracks text changes. It does not determine legal compliance or provide a compliance certification.

If a page fails, check its URL, HTTP status, robots access, and whether its useful content needs browser rendering. For support, open an issue on this Actor's **Issues** tab with a public example URL, sanitized input, and the observed status. Do not post credentials or private information.

# Actor input Schema

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

Public HTTP or HTTPS pages to monitor. Do not provide login URLs or private pages.

## `selector` (type: `string`):

Optional simple selector such as #price, .availability, or main.

## `mode` (type: `string`):

Choose whether to compare normalized text or cleaned HTML.

## `ignorePatterns` (type: `array`):

Regular expressions to remove before comparison.

## `ignoreNumbers` (type: `boolean`):

Ignore numeric changes such as prices, dates, and counters.

## `minChangeRatio` (type: `number`):

Only report changes at or above this fraction of the page.

## `notifyOnly` (type: `boolean`):

Output only first-seen and changed pages.

## `respectRobots` (type: `boolean`):

Respect the website's robots.txt instructions.

## `stateKey` (type: `string`):

Name used to keep separate monitoring histories.

## `timeoutMs` (type: `integer`):

Maximum request time in milliseconds.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "selector": "",
  "mode": "text",
  "ignorePatterns": [],
  "ignoreNumbers": false,
  "minChangeRatio": 0,
  "notifyOnly": false,
  "respectRobots": true,
  "stateKey": "website-change-monitor",
  "timeoutMs": 30000
}
```

# Actor output Schema

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

The dataset containing first-seen, unchanged, changed, blocked, and error results.

# 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("futurefortune/public-website-change-compliance-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("futurefortune/public-website-change-compliance-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 futurefortune/public-website-change-compliance-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,futurefortune/public-website-change-compliance-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/oO0lHIAMynnoQHzQ1/builds/Np2Mw6zvymgMwGSql/openapi.json
