← All guides
Start here

What a Verid Monitor Is Made Of

Every monitor is five decisions: where to look, how often, what to capture, when it counts as a change, and who to tell. Learn those five and the rest of Verid is configuration.

Verid Guides·16 min read

What is a monitor?

A monitor is a saved instruction that Verid carries out on a schedule. In plain words it says:

Look at this page every hour. Pull out the price. If the price changes, post a message in Slack.

That single sentence contains everything a monitor is. Broken up, it is five decisions:

Part The question it answers Example
URL Where do I look? https://example.com/pricing
Interval How often do I look? Every 3600 seconds (1 hour)
Extractor What do I capture from the page? The text inside .plan-pro .price
Predicate When does a change deserve an alert? When the price field changes
Deliveries Who do I tell? A Slack channel

Nothing else about Verid makes sense until these five are clear, and once they are, almost every other feature is a variation on one of them. This guide walks through each part, then follows a single check from start to finish so you can see them working together.


Part 1 - The URL: where to look

One monitor watches one URL. If you want to watch three product pages, that is three monitors.

The URL must be a complete, valid web address including https://. It can point at:

  • A normal web page, like a pricing page or a status page
  • A JSON API endpoint, like https://api.example.com/v1/products/42

Verid fetches whatever that address returns. It does not follow links, crawl deeper, or discover other pages on the site. It looks at exactly the address you gave it.

Your monitor also has a name, between 1 and 200 characters. The name is for you and for your alerts, so make it something you will recognize in a Slack message six months from now. "Competitor pricing page" beats "Monitor 4".


Part 2 - The interval: how often to look

The interval is how many seconds Verid waits between checks. After every check, the next one is scheduled for the interval you set, counted from the moment the check finished.

How fast you can go depends on your plan:

Plan Fastest interval Monitors included
Free Once a day (86,400 seconds) 5
Lite Every 2 hours (7,200 seconds) 25
Starter Every hour (3,600 seconds) 50
Pro Every 15 minutes (900 seconds) 250
Scale Every 5 minutes (300 seconds) 1,500

In the dashboard, the interval box is pre-filled with the fastest interval your plan allows, so you can leave it alone unless you want to check less often. If you try to set something faster than your plan permits, Verid rejects it and names the limit in the error.

One thing worth understanding early: Verid reports the difference between two checks, not everything that happened between them. If a price goes from $49 to $59 and back to $49 inside a single hour, an hourly monitor sees $49 both times and reports nothing at all. That is not a bug, it is what a scheduled check means. If you need to catch brief changes, you need a shorter interval, which is one of the real reasons the paid plans exist.


Part 3 - The extractor: what to capture

This is the part people find least obvious, and it is the most important.

Verid does not store the whole page and compare pictures of it. Instead it captures a small set of named fields on every check, and it is those fields that get compared. A field is just a name you choose paired with an instruction for finding a value:

{
  "pro_plan_price": ".plan-pro .price"
}

Here pro_plan_price is your name for the value, and .plan-pro .price is how Verid finds it. The name is entirely yours to pick. It shows up in the dashboard, in the change history, and in your alerts, so name fields after what they mean.

Fields matter because the field is the unit of everything downstream. Changes are detected per field, alert rules are written against a field by name, and your alert tells you which fields changed. Two fields in one monitor are tracked independently.

The six ways to capture a value

The instruction you write depends on the method you pick. There are six:

Method What you write Best for
CSS Selector .plan-pro .price Pages with meaningful class names. The usual first choice.
XPath //span[@id="price"] Finding an element by the text it contains, or reaching a parent
JSONPath $.items[0].price URLs that return JSON rather than a web page
Regex v(\d+\.\d+\.\d+) A value that only exists in the raw page source
Full Page Hash Nothing to write "Tell me if anything at all changed"
AI (LLM) "the current price in USD" Messy or shifting pages, described in plain English

Each of these has its own guide with worked examples. Three notes apply to all of them.

What you get back is usually text. CSS, XPath, Regex and Full Page Hash always hand you text. If the page says $59.00, your field holds the string $59.00, dollar sign included. JSONPath is the exception: it returns the value exactly as it appears in the JSON, so a JSON number stays a number. This distinction matters in Part 4.

A field that matches nothing goes empty rather than disappearing. If your selector finds no element, the field is still there on that check, holding an empty value. That is worth knowing, because an empty value is a different value: a field that goes from $49 to empty counts as a change, and a monitor watching that field will alert you. A broken selector announces itself instead of going quiet, which is the behaviour you want.

Before that happens, Verid gives your selectors a second chance. If a plain request comes back with every field empty, that usually means the page needs JavaScript to render, so Verid automatically retries the same check with a real browser. Only if the browser attempt also finds nothing do your fields end up empty. (This retry does not apply to JSONPath, where empty means the path simply did not match, and a browser would not help.)

A selector that matches several elements gives you a list. Point a field at three separate prices and it holds all three, in page order, and the comparison treats the whole list as one value. If you meant one price, make the selector more specific.

The exception: Full Page Hash

Full Page Hash is the one method with no fields to write, and it is worth understanding because it is the default in the dashboard.

In the create form, the first question is "What do you want to monitor?" with two answers. Choosing The whole page selects Full Page Hash. Choosing A specific value lets you pick one of the other five methods and write your fields.

When you pick the whole page, Verid downloads the HTML, strips out the parts that change on every single load (scripts, styles, comments, security tokens, and similar noise), and computes a SHA-256 hash of what is left. It stores two fields for you automatically:

{
  "page_hash": "a3f5b2c1d4e6f7890abc...",
  "content_length": "42381"
}

page_hash is the fingerprint, and content_length is the character count of the normalized content. If either changes, the page changed. The trade-off is that a hash tells you that something changed, never what. It is the fastest way to start and the least informative to receive.


Part 4 - The predicate: when a change deserves an alert

Here is the distinction that saves the most confusion:

A change and an alert are not the same thing.

Verid records every change it finds, whether or not it tells you about it. The predicate is the rule that decides which changes are worth interrupting you for. A price that moved by one cent is a change. Whether it is an alert is your call.

There are nine kinds of rule:

Predicate Fires when
any_field_changes Any field in the monitor changed
field_changes One named field changed, whatever it changed to
field_increases_by_percent A named field rose by at least X percent
field_decreases_by_percent A named field fell by at least X percent
field_increases_by_absolute A named field rose by at least X
field_decreases_by_absolute A named field fell by at least X
field_matches_regex A named field changed, and the new value matches a pattern
field_equals A named field changed, and the new value equals something exact
composite Several of the above combined with AND or OR

any_field_changes is the default, and for a whole-page monitor it is the only rule that makes sense, since there is nothing to name.

Two rules about predicates that are easy to miss and cost real time:

Every field-specific rule requires that field to have changed first. A rule like "alert me when stock_status equals In Stock" does not fire on every check where the value happens to be In Stock. It fires on a check where stock_status changed and the new value is In Stock. Predicates describe changes, not states.

The numeric rules need a value that reads as a number. Percent and absolute thresholds parse your captured text as a number. $59.00 does not read as a number, because of the dollar sign, so a threshold rule on that field will silently never fire. If you want a threshold, capture the number by itself: use a regex capture group, an XPath onto a numeric attribute, a JSONPath at a numeric JSON value, or an AI prompt that asks for a bare number. If you just want to know about any movement, field_changes works on text and needs no parsing at all.


Part 5 - The deliveries: who gets told

A delivery is one place an alert goes. A monitor can have several, and it can have none.

Type What you provide
Webhook An HTTPS URL of your own, plus optional custom headers
Slack A Slack incoming webhook URL
Discord A Discord webhook URL
Email An email address

With no deliveries at all, the monitor still runs and still records every change. You just have to open the dashboard to see them. That is a legitimate setup for something you review weekly rather than react to.

How many endpoints one monitor can have depends on your plan: 1 on Free, 2 on Lite, 3 on Starter, 10 on Pro, and 25 on Scale.

Every endpoint on a monitor fires on the same predicate. There is no way to send price drops to one channel and stock changes to another from a single monitor. When you need different rules for different audiences, make two monitors on the same URL with different predicates and different deliveries.

Webhook deliveries are signed so your endpoint can prove the request came from Verid. The signing secret is deliberately never included when you read a monitor back. You fetch it once from GET /v1/monitors/{id}/signing-secret and keep it on your side.


How the five parts work together on one check

Every check follows the same path:

  1. Fetch. Verid requests your URL.
  2. Extract. It applies your extractor and produces the named fields.
  3. Compare. It compares those fields against the fields from the last successful check, field by field. The result lists which fields changed, plus their old and new values. Fields that did not change are left out of the comparison entirely.
  4. Decide. It evaluates your predicate against that comparison.
  5. Deliver. If the predicate says yes and something actually changed, every delivery endpoint fires.

Everything from that check is saved as a run: the values captured, the comparison, whether an alert was triggered, and every delivery attempt. Runs are your audit trail and the first place to look when something behaves unexpectedly.

Two behaviours of this pipeline are worth knowing in advance.

The first check has nothing to compare against. With no previous successful run, Verid treats every field as new. Your old values are empty and every field counts as changed, so a monitor set to any_field_changes normally does send an alert on its very first check. That first alert is expected. It is establishing the baseline, and the checks after it compare against real history.

A check can succeed, find changes, and still send nothing. That is your predicate doing its job. The run will show the change with the alert marked as not triggered, which is exactly how you confirm a threshold is set where you meant it.


A complete monitor, end to end

Say you want to know when a competitor changes the price of their Pro plan.

In the dashboard:

  1. Name it Competitor pricing page and paste the URL.
  2. Under "What do you want to monitor?", choose A specific value.
  3. Leave the extraction method on CSS Selector, and add a field named pro_plan_price with the selector .plan-pro .price.
  4. Click the test button. Verid fetches the page live and shows you what your selector actually captured. Do this every time. It is the difference between a monitor and a monitor that quietly watches nothing.
  5. Set the trigger condition to Specific field changes and enter pro_plan_price.
  6. Leave the interval at the pre-filled value.
  7. Add a Slack notification and paste your Slack webhook URL.

The same monitor through the API:

{
  "name": "Competitor pricing page",
  "url": "https://example.com/pricing",
  "schedule_interval_seconds": 3600,
  "extract_config": {
    "method": "css",
    "fields": {
      "pro_plan_price": ".plan-pro .price"
    }
  },
  "diff_predicate": {
    "type": "field_changes",
    "field": "pro_plan_price"
  },
  "deliveries": [
    {
      "type": "slack",
      "webhookUrl": "https://hooks.slack.com/services/T000/B000/XXXX"
    }
  ]
}

What the first check captures:

{
  "pro_plan_price": "$49"
}

What the next check captures after they raise the price:

{
  "pro_plan_price": "$59"
}

The comparison Verid computes:

{
  "fields_changed": ["pro_plan_price"],
  "before": { "pro_plan_price": "$49" },
  "after": { "pro_plan_price": "$59" }
}

pro_plan_price changed, the predicate is satisfied, so the Slack delivery fires. A webhook endpoint on the same monitor would receive:

{
  "id": "8f14e45f-ceea-467a-9a1b-2b3c4d5e6f70",
  "version": "2026-05-01",
  "monitor_id": "3f9a1c72-8d4e-4b1a-9f2e-7c6d5b4a3e21",
  "run_id": "b21c9f08-4a7d-4c3e-8b15-9e0f1a2b3c4d",
  "fired_at": "2026-08-12T09:00:04.512Z",
  "diff": {
    "fields_changed": ["pro_plan_price"],
    "before": { "pro_plan_price": "$49" },
    "after": { "pro_plan_price": "$59" }
  },
  "monitor": {
    "url": "https://example.com/pricing",
    "name": "Competitor pricing page"
  }
}

Notice that the alert carries the old value and the new value. Your Slack message or your own service can act on the actual numbers, not just the fact that something moved.


The optional parts

Four settings sit outside the five core decisions. You can ignore all of them at first.

Fetch mode. By default this is Auto, and it is the right answer nearly always. Verid tries a plain, fast request first and steps up to a real browser by itself when a page turns out to need one. Setting it to Browser forces the browser on every check, which is worth doing when you already know the content only appears after JavaScript runs.

Custom request headers. Up to 20 headers sent with each request, for pages that need an API key or a specific Accept header. A few headers are reserved and Verid will refuse them, including Cookie and Host. Bear in mind that a token which later expires turns into a monitor that fails.

Templates. The create form offers a list of ready-made starting points for common jobs, such as a GitHub release, an npm version, or an RSS feed. A template pre-fills the extractor and the predicate for you. Treat it as a starting point, then test it and adjust, because it cannot know the specific page you are pointing at.

Visual monitors. If you want to watch how a page looks rather than what it says, that is a separate kind of monitor with its own screenshot comparison and no selectors to write. Create it from the Visual monitors section instead of this form.


Monitor statuses

A monitor is always in one of these states, and only the first one runs on schedule.

Status Meaning
active Running on its interval
paused You paused it. Nothing runs until you resume it.
error Verid stopped it after 10 failed checks in a row, and emailed you about it
billing_paused Stopped for a billing reason
deleted Removed

The error status is the one to understand. A single failed check is not unusual, and Verid keeps trying on schedule. Ten consecutive failures means something is genuinely broken, most often that the site now blocks the request or that the page was redesigned and your selector points at nothing. Verid stops rather than retrying forever, tells you, and waits for you to fix the configuration and resume it. A successful check at any point resets the counter to zero.


Common issues

Problem What is happening
Monitor runs, no alerts, but you expected some Either nothing changed, or the predicate is stricter than you intended. Open the latest run and check whether the comparison found changes but the alert was not triggered.
A threshold rule never fires The captured value is not readable as a number, most likely because it includes a currency symbol or a comma. Capture the number on its own.
An alert on the very first check Expected. The first check has no history to compare against, so every field counts as new.
A field suddenly went empty Its expression matched nothing on this run, even after the browser retry. The page structure probably changed. Test it again against the live page.
Too many alerts Usually the extractor is capturing more than you meant, or the predicate is any_field_changes where a threshold belongs.
Status changed to error Ten consecutive failed checks. Check the last run's error, fix the configuration, and resume.

Ready to try it? Point Verid at your URL and get a signed alert on every change. 5 monitors free, no credit card.

Try Verid for free

5 monitors, no credit card required.