> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spidra.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitors

> Watch a template, a preset or a list of pages on a schedule, and get an email, webhook, Slack or Discord alert only when something changes.

A monitor runs a job on a schedule, compares each check with the last one, and tells you what changed: new jobs on a board, a price drop, new places on Google Maps, a change on a page. When nothing changed, you hear nothing.

Open **Monitors** in the dashboard sidebar, or use the [API](https://docs.spidra.io/api-reference/monitors/create.md).

## Start a monitor

* **From a template:** fill in the form and press **Watch for changes**.
* **From a preset:** on the [Presets](https://docs.spidra.io/presets.md) page, open a preset's menu and choose **Watch for changes**.
* **For pages:** on the Monitors page, press **New monitor** and paste up to 50 URLs.

One panel opens with the schedule, what to alert on, and where to send alerts. It shows the cost per month before you press **Start watching**.

The first check runs straight away. It records a starting point and doesn't alert. Every check after that is compared with the one before.

## What you can watch

| Source | Best for |
| - | - |
| A **template** with its inputs | Lists with a stable key per row: places, products, jobs, listings, posts. New, changed and removed items are exact. |
| A **preset** | Any saved scrape, batch, map, search or template preset. |
| **Pages** (up to 50 URLs) | "Tell me when this page changes." |

A monitor can watch up to 10 sources and sends one alert per check for all of them.

## What counts as a change

| Alert me when | For | How |
| - | - | - |
| **New items appear** | New jobs, listings, places, posts | Rows that weren't in the last check |
| **A field changes** | Prices, stock, ratings, follower counts | The same item, with a field you choose changed |
| **Something is removed** | Sold homes, closed jobs | Items that are gone |
| **The page changes** | Any page | Lines added to or removed from the page's text |
| **Every run** | A daily export | The results, every time |

Two optional filters cut the noise:

* **A rule** on a field: is below, is at most, is above, is at least, equals, contains, drops by % or more, rises by % or more. For example "price drops by 10% or more", or "rating is at least 4".
* **Only if it matters:** a goal in plain words, such as "only dental clinics with 4 or more stars". When something changed, AI reads the changes and decides whether they match, with a one-line reason. It runs only on checks where something changed. If it can't decide, the alert goes out anyway.

## Schedule

Every 5, 15 or 30 minutes, every hour, every 6 or 12 hours, every day at a time, or every week on a day at a time, in your time zone. Over the API you can also give a cron expression. **Check now** runs one straight away.

Your plan sets the shortest schedule and how many monitors you can have:

| Plan | Shortest schedule | Monitors |
| - | - | - |
| Free | Daily | 2 |
| Starter | Hourly | 10 |
| Builder | Every 15 minutes | 50 |
| Pro | Every 5 minutes | 200 |

Paused monitors count toward the limit.

## Where alerts go

* **Email** to your account's address, on by default. One email per check, with the monitor's name and a summary in the subject ("3 new") and a table of what changed. You can add up to 10 more addresses. Each one gets a confirmation email first and receives nothing until it confirms, and every alert has a link to stop them.
* **Webhook**: a `POST` to your https URL. See below.
* **Slack**: an incoming webhook URL (`https://hooks.slack.com/...`).
* **Discord**: a webhook URL (`https://discord.com/api/webhooks/...`).

**Send a test** sends a sample alert to the channels you picked before you save.

### Webhooks

Each check that alerts sends a JSON body with the header `X-Spidra-Event: monitor.check.completed`. This is the one **Send a test** sends:

```json theme={null}
{
  "event": "monitor.check.completed",
  "monitor": { "id": "test", "name": "Test monitor", "alertOn": "new" },
  "check": { "id": "test", "summary": "Test notification", "url": "https://app.spidra.io/dashboard/monitors/test" },
  "judgment": null,
  "sources": [
    {
      "id": "test",
      "label": "Example",
      "added": [{ "title": "This is what a new item looks like", "url": "https://spidra.io" }],
      "changed": [{ "key": "x", "item": { "title": "And a changed one" }, "fields": [{ "field": "price", "previous": 30, "current": 25 }] }],
      "removed": [],
      "pages": []
    }
  ],
  "sentAt": "2026-10-24T18:50:30.112Z"
}
```

In a real alert, `monitor` and `check` hold your monitor's and check's IDs, `check.url` opens the check in the dashboard, and each source can also have `rows` (with "every run") or `error`. `added`, `changed`, `removed` and `pages` have the same shape as in [Get a Monitor Check](https://docs.spidra.io/api-reference/monitors/get-check.md).

Every webhook is signed. The monitor has a secret (set your own, or read the generated one from [Get a Monitor](https://docs.spidra.io/api-reference/monitors/get.md) under `notify.webhook.secret`), and `X-Spidra-Signature` is `sha256=` followed by the HMAC-SHA256 of the raw request body with that secret. Check it before trusting the payload:

```javascript Node.js theme={null}
import crypto from "node:crypto";

function isFromSpidra(rawBody, signature, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return signature && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
```

```python Python theme={null}
import hashlib, hmac

def is_from_spidra(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature or "", expected)
```

Use the raw body as received. Parsing and re-serializing the JSON changes it and the signature won't match.

## The monitor page

Each monitor has a timeline of checks, newest first: "3 new places", "No change", "Price dropped on 1 item". Open a check to see the changed rows, with old and new values side by side. **Check now**, **Pause**, **Edit** and **Delete** are at the top.

## What it costs

A check costs exactly what the same run costs: a template check costs what the template costs, a page costs 1 credit. The panel shows the credits per month before you save, and [Estimate a Monitor](https://docs.spidra.io/api-reference/monitors/estimate.md) gives it over the API. A Google Maps leads search checked daily is about 30 credits a month. The "only if it matters" goal adds a little AI on checks where something changed.

* When you're out of credits, checks are skipped, not failed, and the monitor stays on.
* A check that is still running when the next one is due makes the next one skip.
* After 5 failed checks in a row, the monitor is paused and you get an email, so a broken source doesn't keep using credits.
* Checks are kept for 30 days.

## Good to know

* A monitor sees what its source returns. If a site can't be read in a check, that check reports the error and the next one tries again.
* Page watching compares the page's text. Busy pages with counters or rotating content change often; a goal helps filter that out.
* Monitors aren't real time. The fastest schedule depends on your plan.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.