Skip to content
Glance
Docs

Deterministic alerts

Turn dashboard values and update timing into explicit rules. Glance evaluates the rule you define; no model decides whether an incident is firing, recovered or ready to notify.

1

Choose a condition

Threshold
A threshold rule compares one scalar source with a fixed value using gt, gte, lt, lte, eq or neq. Use it for conditions such as error rate above 5 or inventory equal to zero.
Freshness
A freshness rule watches when its named source was last updated. It becomes stale after staleAfterSeconds; unrelated dashboard updates do not refresh that source's clock.
2

Timing and incident state

sustainSeconds
The condition must remain violated continuously for this long before the rule moves from pending to firing.
cooldownSeconds
A firing rule still evaluates normally, but Glance suppresses a repeat notification until the cooldown has elapsed.
notifyOnRecovery
When enabled, the transition from firing back to healthy creates one recovery delivery for every destination.
Acknowledgement
Acknowledging records the actor and time for the current incident. It does not make a firing rule healthy; only a later healthy evaluation resolves the condition.
3

Create rules over MCP

Call create_alert with the dashboard ID and a complete definition. These two examples differ only in the condition and destination shape.

Threshold — create_alert input
{
  "dashboardId": "operations",
  "definition": {
    "name": "High CPU",
    "enabled": true,
    "kind": "threshold",
    "source": "cpuPercent",
    "operator": "gt",
    "value": 90,
    "sustainSeconds": 120,
    "cooldownSeconds": 900,
    "notifyOnRecovery": true,
    "destinations": [
      { "kind": "email", "to": "ops@example.com" }
    ]
  }
}
Freshness — create_alert input
{
  "dashboardId": "sales",
  "definition": {
    "name": "Pipeline feed stale",
    "enabled": true,
    "kind": "freshness",
    "source": "pipeline",
    "staleAfterSeconds": 300,
    "sustainSeconds": 60,
    "cooldownSeconds": 900,
    "notifyOnRecovery": true,
    "destinations": [
      { "kind": "webhook", "url": "https://hooks.example.com/glance" }
    ]
  }
}
create_alert
{ dashboardId, definition }
Create a threshold or freshness rule and evaluate it immediately.
update_alert
{ dashboardId, ruleId, definition }
Replace a rule's complete definition, then evaluate the replacement.
list_alerts
{ dashboardId, limit?, cursor? }
List dashboard rules, their state and redacted destination labels.
acknowledge_alert
{ dashboardId, ruleId }
Record who acknowledged the current incident and when.
remove_alert
{ dashboardId, ruleId }
Remove a rule without erasing its delivery history.
list_alert_deliveries
{ ruleId?, limit?, cursor? }
Page through tenant-scoped delivery attempts and terminal outcomes.

update_alert is a full replacement, not a patch. Send the entire definition, including every destination you want to keep; omitted fields and destinations are not inherited from the saved rule.

4

Destinations stay write-only

Saved email addresses and webhook URLs are write-only. Read tools and the admin page show a redacted label, never the raw target. Because update_alert replaces the definition, you must re-enter every email address or webhook URL when editing a rule; the previous value cannot be copied back out of Glance.

HTTPS destinations only

Webhooks must use HTTPS. Before sending, Glance resolves DNS and rejects localhost, private, link-local, metadata, multicast and unspecified IPv4 or IPv6 answers. If any answer is blocked, the whole destination is refused.

The validated address is pinned for the TLS request while preserving the hostname for certificate verification, closing DNS-rebinding gaps. Redirects are never followed, and request time and response size are bounded.

5

Delivery history

Each firing or recovery notification starts pending, then becomes delivered or failed. History and attempt counts remain available after a rule is edited or removed, in the dashboard's Alerts panel and through list_alert_deliveries.

Transient network and timeout failures retry with capped exponential backoff. Permanent failures such as an unsafe destination or rejected response become terminal immediately; a transient failure becomes terminal after its maximum attempts. Duplicate or overlapping workers use leased claims and idempotency keys rather than double-sending a delivery.

6

Admin and operations

Manage rules beside the dashboard

Owners and admins can view and manage the alert panel at /dashboard/<dashboard-id>. Other signed-in roles do not see this admin panel; publishers can read rule state and delivery history through MCP.

Open your dashboards
Run the delivery worker every minute

Vercel invokes /api/cron/alerts on a one-minute schedule, which requires a verified Pro project. Set CRON_SECRET; the route accepts authenticated GET or POST and rejects requests without it.

Set RESEND_API_KEY and RESEND_EMAIL_DOMAIN for email from alerts@RESEND_EMAIL_DOMAIN. In local development without Resend configuration, messages are rendered to the console instead of sent.

Migrate before deploying

Run the database migration before deploying application code that reads alert tables. Reversing that order can make alert reads and cron invocations fail while the new release is live.

pnpm db:migrate
Verify the local flow

Against a running dev server and disposable local database, the verification script publishes a dashboard, fires and acknowledges a rule, runs the cron worker, observes recovery, and cleans up. Its blocked loopback destination exercises the SSRF failure path with no outbound webhook.

Manual alert verification
GLANCE_KEY=pk_... CRON_SECRET=... node apps/web/scripts/verify-alerts.mjs

The cron route drains every due row in that local database, so do not run the script against production or a shared development database.

Need the connection and dashboard publishing reference? Return to the publisher docs.