Assertions and validation rules
For Website/HTTPS and API monitors, Assertion mode replaces the classic status-code and keyword fields with a
list of rules written in HostTracker’s assertion language. Each rule is one line; the check passes only when
every rule passes. Use it when “the page answered 200” is not enough: an API must say "status":"ok", a page
must contain its checkout button, a response must arrive within 2 seconds, a redirect must stay on your domain.
Settings reference
Section titled “Settings reference”| Setting (app label) | API field (settings.*) |
Type / allowed values | Default | Plan limits | What it does for you |
|---|---|---|---|---|---|
| Assertion mode | assertMode |
Boolean | Off | Available on every plan that includes the monitor type | Makes the rule list the response verdict. |
| The rule list | assertsSource (write) |
Text, one rule per line, optional label: rule |
None | Up to 20 rules per monitor; your plan may allow fewer | The rules, as you would type them. Parsed and checked on save. |
| - | asserts (read/write) |
Array of rule objects { name, sub, op, not, val, vals, valSub, valT, nocase } |
None | Same | The compiled form. Send either asserts or assertsSource, not both. |
| - | assertsText (read-only) |
Array of strings | - | - | Your rules rendered back as text. |
How a rule reads
Section titled “How a rule reads”A rule is subject [not] predicate, optionally labelled and optionally followed by nocase:
status isOk"json ok": body.json.path("$.status") eq "ok"time lt 2sbody not contains "Error"header("Content-Type") isJson- Strings need double quotes; numbers can carry units (
2s,500ms,10kb,1mb). notgoes after the subject (body not contains "x"); a leadingnotdoes not parse.- A rule that fails names itself in the alert - short labels tell you which expectation broke.
- There is no
orbetween rules;in [...],containsAny [...]and ranges such asin [200..299]cover most cases.
What you can check
Section titled “What you can check”| Area | Example | Catches |
|---|---|---|
| Status | status isOk, status in [200, 301, 302], status not in [500..599] |
Errors, or a status outside what you allow |
| Body text | body contains "Add to cart", body containsAll ["Checkout", "Total"], body matches "Order #[0-9]{6}" |
A 200 page that lost its content - the failure a status check cannot see |
| Body size | body.size gt 1kb |
A blank or truncated page |
| JSON | body.json.path("$.status") eq "ok", body.json.path("$.items").count ge 1, body isJson |
The API’s own verdict, empty results, an HTML error page instead of JSON |
| Headers | header("Content-Type") isJson, header("Cache-Control") matches "no-store" |
Wrong content type or caching |
| Timing | time lt 2s, time.connect lt 300ms, time.tls lt 500ms, time.dns lt 200ms, time.head lt 1s |
Slowness, and which stage causes it (DNS is not part of time) |
| Redirects | redirects.count le 2, url.scheme eq "https", url.host eq url.original.host, requests[0].status eq 301 |
Chains that grow, leave your domain or change type |
| DNS | dns.ips.count ge 2, dns.ips contains "203.0.113.10" |
Losing redundancy, or an address change |
| Certificate | cert.days.left gt 14 |
A certificate close to expiry, with time to act |
| Change detection | previous.body.hash eq body.hash, delta(body.json.path("$.orders")) lt 100 |
A page that changed, or a value that jumped since the last check |
The full grammar, every subject and predicate, and a recipe catalogue are in the assertion language reference.
Set it up in the app
Section titled “Set it up in the app”- On Sites, open a Website/HTTPS or API monitor and expand Response Validation.
- Switch on Assertion mode. The classic keyword and status fields are hidden, and the list starts with a status rule.
- Add rules with the rule editor, or pick one under Examples - click to add:.
- Save. Rules that do not compile are refused line by line with the reason.
Switching the mode off before saving brings the classic settings back. Saving with the mode off removes the rules from the monitor.
Do it with the API or MCP
Section titled “Do it with the API or MCP”# Scope monitor:writecurl -X PATCH "https://api2.host-tracker.com/monitor/$MONITOR_ID" \ -H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \ -d '{ "settings": { "assertMode": true, "assertsSource": "status isOk\n\"json ok\": body.json.path(\"$.status\") eq \"ok\"\ntime lt 2s" } }'The response shows the stored rules as asserts (compiled) and assertsText (readable). While assertMode is
on, keywords, keywordMode, ignoredStatuses, errorStatuses, errorOnRedirect and preset are refused -
clear them in the same request if the monitor had them. MCP: update_monitor / create_monitor with
settingsJson carrying the same members.
What happens next
Section titled “What happens next”Every check evaluates all rules and reports every failed one in the result (AssertError). A connection
failure - DNS, connect, TLS, timeout, a redirect loop - still fails the check whatever the rules say. A failed
check is re-checked like any other before the monitor turns Down.
Limits and gotchas
Section titled “Limits and gotchas”- Rule count. At most 20 rules per monitor; your plan may set a lower number. More is refused with
403 package_limit(“Your package allows up to N assertion rules per check”). - Change detection is a plan feature. Rules using
previous.,delta(...)ordelta2(...)need the stateful-assertions entitlement (“Stateful assertions are not available on your package” otherwise). Their first check has nothing to compare against, so it counts as a pass marked “warming” (delta2needs three checks). - Large pages. Only the downloaded part of the body (the
max response size, 1 MB by default) is judged. A rule whose outcome
depends on not finding something in a cut-off body -
body contains "x"failing, orbody not contains "x"passing - cannot be proven, and the check fails withContentTooLargeinstead. Raise the max response size or match text nearer the top. - No implicit “any” or “all”. A list compared with a single value (
body.json.path("$.items[*].price") gt 0) does not pass - say which item you mean with.first/.last, count with.count, or test every item within [...]. redirects.*rules need Follow redirects on; Redirect is error cannot be combined with assertion mode.- Through the API, rules sent with
assertMode: falseare evaluated in addition to the classic status and keyword fields.

