Conditions
Write checks as expressions
A condition is left comparator right. Placeholders are filled from the probe result. Every condition on the monitor must pass or the check is down.
[STATUS] == 200[RESPONSE_TIME] < 400[CERTIFICATE_EXPIRATION] > 48h[DOMAIN_EXPIRATION] > 720h[DNS_RCODE] == NOERROR[BODY] == pat(*"ok"*)has([BODY].errors) == falseComparators
== != < <= > >=. [CONNECTED], [IP], and [DNS_RCODE] only use equality. Numbers compare numerically. Everything else is compared as strings.
Placeholders
Which ones exist depends on the monitor type.
| Placeholder | What it does |
|---|---|
[STATUS] | HTTP status code. HTTP and GraphQL only. |
[BODY] | Decoded JSON when the payload is JSON, otherwise the raw string. Use .path or [0] for JSON. First DNS answer for DNS checks. |
[CONNECTED] | Whether the probe reached the target. Boolean true / false. |
[RESPONSE_TIME] | Latency in milliseconds. Compare to a number (400), not a duration (400ms). |
[IP] | Resolved peer address. |
[CERTIFICATE_EXPIRATION] | Seconds until the TLS certificate expires. Compare with durations such as 48h. |
[DOMAIN_EXPIRATION] | Seconds until the domain expires (RDAP, then WHOIS). Not on DNS or heartbeat. Minimum interval 5 minutes. |
[DNS_RCODE] | DNS response code (NOERROR, NXDOMAIN, …). DNS only. |
JSON bodies
If the payload parses as JSON, [BODY] is that object. Dot paths and indexes work: [BODY].status, [BODY].items[0].id. If a path is missing, that condition fails (unless you wrap it in has()). Non-JSON bodies stay a string; paths are invalid on them.
Functions
pat(pattern)— glob match, case-insensitive.[BODY] == pat(*"ok"*). Only with==and!=.has(path)—trueif the path exists.has([BODY].errors) == false.len(value)— string length or number of array items.any(a, b, c)— membership.[IP] == any(1.1.1.1, 1.0.0.1). Only with==and!=.
Durations and numbers
Literals ending in ms, s, m, h, or d become seconds (milliseconds round up to at least 1s). Use them for [CERTIFICATE_EXPIRATION] and [DOMAIN_EXPIRATION].
[RESPONSE_TIME] is already milliseconds. Write [RESPONSE_TIME] < 400, not 400ms — a duration would be converted to seconds and the comparison would be wrong.
Booleans are true / false. Quoted strings keep their quotes stripped. null is a literal. Unquoted tokens are strings.
Domain expiration
[DOMAIN_EXPIRATION] is available on every type except DNS and heartbeat. Nominal looks up expiry with RDAP first, then WHOIS, and caches the result. It only does that lookup when a condition actually uses the placeholder. The monitor interval must be at least 300 seconds so registries are not hammered.
All must pass
Conditions are ANDed. There is no OR at the expression level; use any() for a list of allowed values on one side. A failed path or a failed comparator fails the whole check, and the stored message is Condition failed: … for the first one that did not pass.