Skip to content
Nominal

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) == false

Comparators

== != < <= > >=. [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.

PlaceholderWhat 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)true if 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.