← All posts
Written by HANZALA SALEEM·Published July 11, 2026·9 min read
Stop Monitoring Noise: How Predicate-Based Alerting Saves Your Sanity

Stop Monitoring Noise: How Predicate-Based Alerting Saves Your Sanity

There is a particular kind of Monday morning you learn to dread after running monitors for a while. You open Slack and find forty-seven alerts from the weekend. Forty-five of them are cookie banners that rotated, a timestamp that ticked over, or an ad slot that refreshed. Two of them matter. You cannot tell which two without reading all forty-seven.

That is alert fatigue, and it is not a personality problem. It is an architectural one.

The architecture most monitoring tools use fires on raw change: any byte that differs from the last snapshot triggers a notification. That made sense once, when "did the page change at all?" was a useful question. It does not make sense anymore, because modern web pages change constantly in ways that have nothing to do with what you are actually watching.

Predicate-based alerting flips the model. Instead of "fire when anything changes," you define a precise condition, and the monitor only fires when that condition is true. Nothing else gets through.

What a Predicate Actually Is

In logic, a predicate is a statement that evaluates to true or false given some input. In web monitoring, it is the same idea applied to the diff between two runs of your monitor.

You extract a specific field. The system compares the new value to the previous one. Your predicate evaluates that comparison. If it returns true, the alert fires. If it returns false, the run is logged silently and nothing is delivered to you.

A simple example: you are monitoring a competitor's product page and you want to know when their price drops by at least five percent. The predicate is:

{
  "type": "field_decreases_by_percent",
  "field": "price",
  "threshold": 5
}

If the price goes from $100 to $96, that is a 4% drop, so the predicate is false and you hear nothing. If it goes to $94, that is a 6% drop, the predicate is true, and you get a webhook. The price bouncing between $100 and $101 because of currency rounding? Silent. A cookie banner loading half a second later than last time? Completely irrelevant, because you never extracted it in the first place.

This is the difference between state monitoring and screenshot diffing.

Why Screenshot Diffing Fails at Scale

Visual monitoring tools compare page screenshots pixel by pixel. Any visual change triggers an alert. In theory this sounds comprehensive. In practice it means you get notified every time:

  • A banner ad rotates to a different creative
  • An animated element is captured mid-transition
  • A "Last updated" timestamp increments
  • A cookie consent overlay appears or disappears
  • A font loads slightly differently across two runs

None of those things matter to your actual monitoring goal. But the tool cannot know that, because it is comparing images rather than values. It has no concept of which parts of the page you care about.

Predicate-based monitoring sidesteps this entirely. You extract only the fields you care about, using CSS selectors, XPath, JSONPath, regex, or even an LLM prompt for pages where the markup keeps shifting. The monitor never even looks at the rest of the page. And then your predicate evaluates only against those extracted fields. The cookie banner is invisible to the entire pipeline.

The Five-Stage Pipeline

Understanding why predicate-based monitoring is quiet by default requires understanding the loop it runs.

Stage 1: Fetch. The monitor retrieves the URL on your configured schedule. Static fetch runs first. If the extraction returns empty fields (JavaScript-rendered content), it automatically retries with a headless browser. Bot-protected sites escalate further to a residential proxy.

Stage 2: Extract. Structured fields are pulled from the response. You define which fields using one of six methods: CSS selector, XPath, JSONPath, regex, full-page hash, or an LLM prompt. The output is always typed values, never raw HTML.

Stage 3: Diff. Each field's new value is compared against the value stored from the previous successful run. The system records exactly which fields changed and what the before/after values were.

Stage 4: Predicate evaluation. Your diff_predicate is evaluated against the diff. This is the gate. If it returns false, the run is recorded and the pipeline stops here. No delivery, no notification.

Stage 5: Deliver. Only if the predicate returned true does a delivery go out. You can route to a signed webhook, a Slack channel, Discord, or email. Every webhook is HMAC-signed so your endpoint can verify it genuinely came from the monitor.

The predicate stage is why this approach is quiet by default. Most runs never reach stage five.

The Nine Predicate Types

Verid's change detection supports nine predicate types, covering the common alerting patterns developers actually need. The full reference lives in the predicates documentation.

Any field changes

{ "type": "any_field_changes" }

The broadest predicate. Fires whenever any extracted field differs from the previous run. Useful when you genuinely want to know about any change to a small set of important fields, or as a starting point before you know which field will change.

Specific field changes

{ "type": "field_changes", "field": "version" }

Fires only when the named field changes. Other fields can shift freely without triggering delivery. Good for version bump monitors, status text changes, or anything where the field identity matters more than the magnitude of change.

Field increases by percentage

{
  "type": "field_increases_by_percent",
  "field": "price",
  "threshold": 10
}

Fires when a numeric field rises by at least the specified percentage. Useful for stock alerts, traffic spikes, or any metric where a significant upward move is the signal.

Field decreases by percentage

{
  "type": "field_decreases_by_percent",
  "field": "price",
  "threshold": 5
}

The mirror predicate. This is the classic repricing trigger: notify a workflow when a competitor's price drops by five percent or more. Small rounding changes never reach you.

Field increases by absolute value

{
  "type": "field_increases_by_absolute",
  "field": "open_issues",
  "threshold": 50
}

Fires when a field increases by at least a fixed amount rather than a percentage. Useful for issue counts, comment counts, sitemap URL counts, or any numeric that makes more sense in absolute terms.

Field decreases by absolute value

{
  "type": "field_decreases_by_absolute",
  "field": "stock_count",
  "threshold": 10
}

The downward version. Useful for inventory monitoring, follower counts, or any countable where a significant drop is meaningful.

Field matches regex

{
  "type": "field_matches_regex",
  "field": "status",
  "pattern": "^(error|failed|critical)"
}

Fires when the new value of a field matches a regular expression. Practical for catching error states, specific keywords appearing in a content field, or format changes. Uses JavaScript regex syntax; remember to escape backslashes in JSON.

Field equals value

{
  "type": "field_equals",
  "field": "availability",
  "value": "In Stock"
}

Fires when a field reaches an exact literal value. The restock alert archetype: wait until availability is exactly "In Stock," then fire. Case-sensitive for strings.

Composite (AND / OR)

{
  "type": "composite",
  "operator": "AND",
  "conditions": [
    { "type": "field_decreases_by_percent", "field": "price", "threshold": 5 },
    { "type": "field_equals", "field": "availability", "value": "In Stock" }
  ]
}

Combine any predicates with AND or OR logic. You can nest composites inside composites for arbitrarily complex rules. The example above fires only when a price drops by five percent AND the item is in stock simultaneously, which is far more useful than either condition alone.

Predicate Comparison Table

Predicate typeFires whenCommon use case
any_field_changesAny extracted field differsBroad change detection
field_changesOne specific field differsVersion bumps, status changes
field_increases_by_percentNumeric field rises by N%Traffic spikes, price surges
field_decreases_by_percentNumeric field drops by N%Competitor price drops
field_increases_by_absoluteNumeric field rises by fixed NNew issues, new URLs in sitemap
field_decreases_by_absoluteNumeric field drops by fixed NInventory drops
field_matches_regexNew value matches a regexError states, keyword detection
field_equalsNew value equals a literalRestock alerts, status transitions
compositeAND / OR of other predicatesMulti-condition business rules

Traditional Monitoring vs. Predicate-Based Monitoring

CapabilityScreenshot / byte-diff toolsPredicate-based monitoring
Alert granularityPage-level or pixel-levelField-level
False positivesHigh (ads, timestamps, banners)Low (only your condition)
Alert logic"Did anything change?""Did this specific thing cross this threshold?"
Composable rulesNoYes, with AND / OR nesting
Structured payloadNo (image diff or raw text)Yes (before/after values per field)
Quiet by defaultNoYes

A Real Example: Dependency Release Monitor

One of the most common and underappreciated monitoring tasks for developers is watching upstream package versions. If React ships a new release and your CI does not know until someone manually checks, that is a gap you can close in about two minutes.

Here is the full monitor creation request for a GitHub release tracker, using the Verid REST API:

curl -X POST https://api.verid.dev/v1/monitors \
  -H "Authorization: Bearer $VERID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "React New Releases",
    "url": "https://api.github.com/repos/facebook/react/releases/latest",
    "schedule_interval_seconds": 3600,
    "extract_config": {
      "method": "json_path",
      "fields": {
        "tag_name": "$.tag_name",
        "published_at": "$.published_at"
      }
    },
    "diff_predicate": {
      "type": "field_changes",
      "field": "tag_name"
    },
    "deliveries": [
      {
        "type": "webhook",
        "url": "https://your-app.com/webhooks/verid"
      }
    ]
  }'

The monitor polls the GitHub API every hour. The predicate fires only when tag_name changes. The published_at field is extracted too, so it appears in the diff payload for context, but it does not trigger delivery on its own.

When a new release ships, your endpoint receives:

{
  "id": "del_01H...",
  "version": "2026-05-01",
  "monitor_id": "uuid",
  "fired_at": "2026-06-01T09:31:00Z",
  "diff": {
    "fields_changed": ["tag_name"],
    "before": { "tag_name": "v18.3.0" },
    "after":  { "tag_name": "v19.0.0" }
  },
  "monitor": {
    "url":  "https://api.github.com/repos/facebook/react/releases/latest",
    "name": "React New Releases"
  }
}

That payload is actionable without any parsing. You know what changed, what it was before, and what it is now.

A More Complex Example: Price Drop Plus In-Stock

Say you are tracking a product that frequently goes out of stock. A price drop on an out-of-stock item is irrelevant. You want a notification only when the price drops and the item can actually be purchased.

A composite predicate with AND logic handles this precisely:

{
  "type": "composite",
  "operator": "AND",
  "conditions": [
    {
      "type": "field_decreases_by_percent",
      "field": "price",
      "threshold": 10
    },
    {
      "type": "field_equals",
      "field": "availability",
      "value": "In Stock"
    }
  ]
}

Both conditions must be true in the same run for delivery to fire. This kind of multi-condition logic would require a custom webhook consumer or external automation in most other monitoring setups. Here it lives entirely in the monitor configuration. See the competitor price tracking use case for a full walkthrough.

Verifying the Webhook Delivery

When a predicate fires and a webhook delivery goes out, every request is signed with HMAC-SHA256. The signature sits in the Verid-Signature header in the format t={timestamp},v1={signature}.

You should always verify this before trusting the payload. A Node.js verification function from the webhooks documentation:

import { createHmac, timingSafeEqual } from 'crypto';

function verifyWebhook(
  header: string,
  rawBody: string,
  secret: string,
  toleranceSecs = 300,
): boolean {
  const parts = Object.fromEntries(
    header.split(',').map((p) => p.split('=')),
  );
  const timestamp = parseInt(parts['t'] ?? '0', 10);
  const signature = parts['v1'];

  if (!timestamp || !signature) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSecs) return false;

  const expected = createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');

  return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'));
}

The 300-second tolerance guards against replay attacks. Equivalent verification snippets for Python, Ruby, Go, and PHP are available in the webhooks docs.

First-Run Behavior and Other Practical Notes

A few things worth knowing before you ship your first monitor:

The first run never fires. There is no previous run to compare against, so the baseline is established silently. This is expected behavior, not a bug.

Numeric string parsing. For percent and absolute predicates, Verid will try to parse strings like "$1,299.00" or "1,450" as numbers. It is cleaner to strip currency symbols in your extractor when you can, because it removes ambiguity.

Boolean fields. The field_equals predicate distinguishes JSON booleans from strings. If your extractor returns the string "true", that is not equal to the JSON boolean true. Worth keeping in mind when monitoring APIs that serialize booleans inconsistently.

Composite nesting. Composite conditions can contain other composites. You can build (A AND B) OR C by nesting one composite inside another. The depth limit is generous enough that most real-world business rules fit within a single config.

When to Use Which Approach

Not every monitor needs a precise predicate. Here is a quick heuristic:

  • If you want to know whether a page changed at all and false positives are tolerable, any_field_changes is fine.
  • If you are watching a structured data source (an API, a JSON endpoint, a known HTML pattern), use a field-specific predicate.
  • If the signal is numerical and the magnitude matters, use the percent or absolute variants.
  • If you want multiple conditions to be true simultaneously, reach for composite with AND.
  • If any one of several conditions is enough, composite with OR is the right shape.

The use cases directory has thirty-plus worked examples across competitive pricing, dependency tracking, regulatory filings, SERP monitoring, inventory restocks, and API contract drift, each showing which extraction method and predicate combination makes sense.

FAQ

What is predicate-based alerting?

Predicate-based alerting is a monitoring approach where a notification fires only when a specific logical condition, called a predicate, evaluates to true against the diff between two monitoring runs. Rather than alerting on any change to a page, you define exact rules like "price dropped by more than five percent" or "status field equals 'error'" and only those conditions produce alerts.

How does predicate-based alerting reduce alert fatigue?

Alert fatigue comes from too many notifications that do not require action. Predicate-based alerting reduces this by filtering at the monitor level: changes that do not satisfy your defined condition are logged but never delivered. Cookie banners, ad rotations, and timestamp changes produce no notifications because the fields you care about are not affected.

Can I combine multiple conditions in a single monitor?

Yes. Composite predicates let you combine any number of conditions with AND or OR logic, and you can nest composites inside each other. A common pattern is using AND to require that a price dropped and the item is in stock simultaneously, so neither condition alone causes a spurious alert.

How do I get started with predicate-based monitoring?

Sign up for a free account at verid.dev (no credit card required), grab your API key, and follow the quickstart guide. The free plan includes five monitors with daily checks and full webhook delivery. The recipes section has copy-paste configs for GitHub release tracking, crypto price alerts, and more, each ready to drop into your first monitor.

Get a signed webhook when this page changes

Point Verid at any URL and get an HMAC-signed webhook on the change you care about. 5 monitors free, no credit card.