# Website Change Monitor: Page Changes, Uptime & SSL Expiry (`swiftkit/website-monitor`) Actor

Watch web pages for content changes (exact lines added and removed), downtime, slow responses and expiring SSL certificates. Schedule it and get alerts by email, Slack or webhook through Apify. Optional CSS selector and ignore rules. $2 per 1,000 checks.

- **URL**: https://apify.com/swiftkit/website-monitor.md
- **Developed by:** [SwiftKit](https://apify.com/swiftkit) (community)
- **Categories:** Developer tools, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 page checkeds

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: Page Changes, Uptime & SSL Expiry

Watch any web pages and find out **what changed since the last check**: the exact lines that were
added and removed. In the same check you also get **uptime**, **response time** and **SSL
certificate expiry**. Schedule it (hourly, daily) and let Apify alert you by email, Slack or webhook.

- **Content changes:** line-by-line diff of the visible text, with a one-line summary
  ("3 lines added, 1 removed, e.g. 'Pro plan $49/month'")
- **Watch just one part** of a page with a CSS selector (`#pricing`, `.price`, `main article`)
- **Ignore noise:** regular expressions for counters, timestamps or rotating banners
- **Uptime:** up/down, HTTP status, final URL after redirects, response time, slow flag
- **SSL:** valid or not, issuer, expiry date, days left, "expires soon" flag
- **One `alert` flag per page:** changed, down, slow, or certificate problem
- **Only-alerts mode:** list just the pages that need attention, so an empty result means all good

### Typical uses

- **Competitor tracking:** pricing pages, feature lists, job pages, terms.
- **Your own sites:** uptime, slowness and certificate expiry across many domains.
- **Content watching:** product availability text, documentation, policy pages, announcements.

### How to set it up

1. Add the pages and run it once. The first run saves a snapshot (`change: "first_check"`).
2. Click **Schedule** and pick how often (e.g. every hour or every morning).
3. Under **Integrations**, add an email, Slack or webhook notification for when the run succeeds.
   With "Only list pages that need attention" on, the result is empty when nothing happened.

Snapshots are stored in a named key-value store in **your own** Apify account
(`swiftkit-monitor-<monitor name>`), so each run compares with the previous one. Use different
monitor names to keep separate histories.

### Input

| Option | Default | What it does |
|---|---|---|
| Pages to watch | – | Full URLs |
| Only this part of the page | – | CSS selector |
| Ignore text matching | – | Regexes removed before comparing |
| Check SSL certificate | on | Validity, issuer, days left |
| Warn when SSL expires within | 21 days | Sets `sslExpiresSoon` |
| Slow if response takes more than | 3,000 ms | Sets `slow` |
| Only list pages that need attention | off | Hide quiet pages |
| Monitor name | `default` | Separate histories |

### Output

A real check where a page's text changed (one line edited, one removed):

```json
{
  "url": "https://example.com/",
  "checkedAt": "2026-10-04T01:52:41.064Z",
  "previousCheckAt": "2026-10-04T01:52:11.073Z",
  "up": true,
  "httpStatus": 200,
  "responseTimeMs": 51,
  "sslValid": true,
  "sslDaysLeft": 82,
  "change": "changed",
  "changed": true,
  "summary": "1 line(s) added, 2 removed, e.g. \"This domain is for use in documentation examples...\"",
  "addedLines": ["This domain is for use in documentation examples without needing permission. ..."],
  "removedLines": ["This domain is for use in docs examples without needing permission. ...", "Old promo line that was removed"],
  "alert": true
}
```

`change` is one of `first_check`, `no_change`, `changed`, `down` or `not_html`.

### Pricing

You pay **per page checked**, the same whether it changed or not. See the Pricing tab.

### Limits, honestly

- Pages are read as HTML without running JavaScript. Content that only appears after scripts run
  (some single-page apps) isn't seen. Watch a part that's in the HTML, or use an API endpoint.
- The diff compares visible text, not layout, images or styles.
- Pages behind a login or a bot check can't be monitored.
- Uptime is checked from Apify's servers once per run; it's not a multi-location uptime service.

### More tools from SwiftKit

- [SEO Audit Crawler](https://apify.com/swiftkit/seo-audit): find broken links, missing titles and noindex pages
- [WHOIS & Domain Expiry Checker](https://apify.com/swiftkit/domain-lookup): know when your domains expire
- [Website Screenshots](https://apify.com/swiftkit/website-screenshots): visual snapshots of many pages
- [Website to Markdown for AI](https://apify.com/swiftkit/web-to-markdown): clean page content for LLMs

### Questions?

Open an issue on the Issues tab.

# Actor input Schema

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

Full page addresses, e.g. a competitor's pricing page, a product page, your own homepage.

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

CSS selector to watch just one part, e.g. #pricing, .price, main article. Empty = the whole visible page.

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

Regular expressions removed before comparing, so counters and timestamps don't trigger alerts, e.g. \d+ minutes ago or Updated: .\*

## `checkSsl` (type: `boolean`):

Report certificate validity, issuer and days until expiry.

## `sslWarnDays` (type: `integer`):

Sets sslExpiresSoon and the alert flag.

## `slowMs` (type: `integer`):

Sets the slow and alert flags.

## `onlyChanges` (type: `boolean`):

Leave out pages with no change, up, fast and a healthy certificate. Handy with email alerts: an empty result means all good.

## `monitorName` (type: `string`):

Keeps separate histories for separate monitors (e.g. competitors, own-sites). Use the same name every run.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://news.ycombinator.com/newest"
  ],
  "checkSsl": true,
  "sslWarnDays": 21,
  "slowMs": 3000,
  "onlyChanges": false,
  "monitorName": "default"
}
```

# Actor output Schema

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

One row per checked page.

# 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",
        "https://news.ycombinator.com/newest"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("swiftkit/website-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",
        "https://news.ycombinator.com/newest",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("swiftkit/website-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",
    "https://news.ycombinator.com/newest"
  ]
}' |
apify call swiftkit/website-monitor --silent --output-dataset

```

## MCP server setup

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