{% extends "base.html" %} {% block title %}{% if monitor %}Edit monitor{% else %}New monitor{% endif %}{% endblock %} {% block content %} {% set mode = form.mode or 'uptime' %}
Monitors / {% if monitor %}{{ monitor.name }} / Edit{% else %}New / {{ modes[mode][0] }}{% endif %}

{% if monitor %}Edit {{ modes[mode][0]|lower }} monitor{% else %}New {{ modes[mode][0]|lower }} monitor{% endif %}

{{ modes[mode][1] }} · {{ plan.name }} plan: up to {{ plan.monitors }} monitors, checks as often as every {{ plan.min_interval }} min.{% if ws_plan_key == 'free' %} Upgrade{% endif %}

{% if error %}
{{ error }}
{% endif %}

Target

{% if not monitor %}
{% endif %}
{% if mode in ('uptime','api','text','price','keyword','health') %}
{% elif mode == 'tcp' %}
We open a TCP connection and measure how long it takes. Works for databases, mail servers, SSH, game servers, anything listening on a port.
{% elif mode == 'domain' %}
We read the registry's RDAP record for the expiry date and registrar, and snapshot A, AAAA, MX, NS, TXT and CNAME records on every check.
{% for t in ['A','AAAA','MX','NS','TXT','CNAME'] %}{% endfor %}
Tip: untick TXT if a service rotates verification records; MX and NS changes are the ones that hijack email and traffic.
{% elif mode == 'dependency' %}
Any Atlassian Statuspage-powered page works (we read /api/v2/status.json).
A major or critical incident at the provider marks this monitor down and opens an incident, so your status page can say "third-party issue" instead of "we're broken". Minor issues send a heads-up only.
{% elif mode == 'heartbeat' %}
Your job calls a unique URL when it finishes. If the ping doesn't arrive in time, we alert you. Optionally call /start first to track run duration, and POST the job's output to keep logs.
1440 = daily, 60 = hourly.
Same syntax as crontab. We expect a ping after each scheduled time.
How late a ping may be before we alert.
Needs /start pings. Alerts when a run takes longer.
{% elif mode == 'flow' %}
Steps run in order. Extract values from a response with json:path, header:name or regex:pattern, then use them anywhere later as {{ '{{' }}name{{ '}}' }}. The flow fails at the first failing step.
{% endif %} {% if mode == 'api' %}
200, 2xx or 200-299
One per line as Name: value, or a JSON object. Use read-only test credentials.
contains text · not_contains text · json path exists · json path == value (also != < > <= >= contains) · header name contains text
{% endif %} {% if mode == 'health' %}
Sent as vigil-health-secret (and oh-dear-health-check-secret) so only we can read the endpoint. Your app returns JSON like {"checkResults":[{"name":"Database","status":"ok"}]}, Laravel Health, Spring Actuator or just {"status":"ok"}.
{% endif %} {% if mode in ('text','price','keyword') %}
Limit the watch to one part of the page. Leave blank to watch the whole page text.
{% endif %} {% if mode == 'price' %}
We read the first number in the selected content.
{% endif %} {% if mode == 'keyword' %}
Comma-separate several; any match counts.
{% endif %} {% if mode in ('uptime','api','text','price','keyword','tcp','health') %}
Private locations run the check from an agent inside your network or another region. Manage locations.
{% endif %}
Comma-separated. Filter the dashboard and scope maintenance windows by tag.

Schedule, thresholds & alerts

{% if mode != 'heartbeat' %}
{% if mode == 'domain' %}
Domain monitors run at most every 30 minutes; the expiry lookup happens twice a day.
{% endif %}
{% endif %} {% if mode in ('uptime','api','text','price','keyword','health','flow') %}
"Degraded" incident after 3 slow checks in a row. Doesn't count as downtime.
{% if mode != 'flow' %}
Checked twice a day for https URLs.
{% endif %}
{% if mode != 'flow' %}
We grade HSTS, CSP, cookie flags, TLS versions and more every week. See the Security tab on the monitor.
{% endif %} {% endif %} {% if mode in ('uptime','api','text','price','keyword','health','flow','tcp') %}
Shows the error budget (minutes of downtime left) and appears in the SLA report.
Learns the normal response time over 7 days and alerts when three checks in a row are far above it. No threshold to guess.
{% endif %} {% if mode != 'heartbeat' %}
Cuts false alarms from a single dropped packet. A monitor is marked down after 2 consecutive failed checks.
{% endif %}
0 = alert once on down and once on recovery. 30 = nag every 30 minutes until it's back or acknowledged.
{% if channels %} {% for c in channels %}{% endfor %}
{% if smtp_enabled %}Nothing selected → we'll email {{ ws.email }}.{% else %}With none selected, alerts only appear in this dashboard.{% endif %}
{% else %}
You have no channels yet. Add Telegram, Slack, Discord, ntfy, Pushover or a webhook to get notified.
{% endif %}
0 = off. Otherwise, a DOWN incident that is still open and unacknowledged after this many minutes is sent to the escalation channels below (your on-call's phone via Pushover, a second Telegram group, PagerDuty webhook…).
{% if plan.escalation and channels %}
{% for c in channels %}{% endfor %}
{% endif %}
Cancel
{% endblock %} {% block scripts %} {% endblock %}