Monitors
A monitor checks one thing at an interval, from the locations you pick. Create one with new monitor on the dashboard; test runs the check once from the selected locations without saving.
──Common settings
| setting | |
|---|---|
| interval | seconds between checks (defaults for new monitors are in settings → monitors) |
| timeout | ms before a check fails |
| retries | consecutive failures before a location counts as failing (1 to 10) |
| locations | the hub and the agents that run the check |
| group, tags | see groups and tags |
| notifications | channels linked to this monitor one by one, see alerts |
| degraded threshold | share of failing locations that makes it degraded, see below |
| slow threshold | off, automatic or a value in ms |
| ip version | how to treat hosts with IPv4 and IPv6, see IPv6 |
| diagnostics | instance default, on or off, see diagnostics |
| expiry alerts | TLS certificate and domain registration, see alerts |
Paste a curl command in the URL field of an HTTP monitor to fill in the method, headers and body.
──Check types
| type | target | what is checked |
|---|---|---|
| http(s) | https://example.com/health |
status code (default 200-399), headers, body, JSON rules, TLS expiry |
| keyword | URL + text | the response body contains (or does not contain) the text |
| tcp port | host:port |
the connection opens |
| ping | host or IP | ICMP echo, or ICMPv6 |
| dns | name + record type | the name resolves, optionally to an expected value, through the system or a given server |
| postgresql | postgres://user:pass@host:5432/db?sslmode=disable |
connect and run a query (default SELECT 1); optional expected value of the first column |
| mysql / mariadb | mysql://user:pass@host:3306/db (?tls=true|false|skip-verify) |
same as postgresql |
| redis | redis://[user]:pass@host:6379/0, rediss:// for TLS |
AUTH + PING |
| mongodb | mongodb://user:pass@host:27017/?authSource=admin, mongodb+srv:// |
hello, SCRAM-SHA-256/SHA-1 auth, ping; shows primary/secondary |
| docker container | container name or id | down when not running, restarting, paused or unhealthy |
| grpc health | grpc://host:port[/service], grpcs:// for TLS |
grpc.health.v1.Health/Check returns SERVING |
| smtp | smtp://host:25, smtp://host:587, smtps://host:465 |
greeting, EHLO, STARTTLS when offered (certificate verified) |
| mcp server | https://mcp.example.com/mcp |
the MCP handshake and its tools, see MCP servers |
| heartbeat (push) | none: pingtxt gives you a URL | your job calls the URL; down when the calls stop, see heartbeat |
HTTP monitors also take a method, request headers and body, the accepted status codes and whether to skip TLS
verification. Agents older than a check type report unknown monitor type: update them.
──Response checks (JSON)
HTTP and keyword monitors can check the JSON body of the response, for example a health endpoint that returns
{"status": "ready", "checks": {"redis": {"status": "ok", "latencyMs": 3}}}. Add rules under
response checks: all must pass, otherwise the check fails and the result, the incident and the alert say which
rule broke, e.g. checks.redis.status: expected "ok", got "error".
| path | operator | value |
|---|---|---|
status |
equals | ready |
checks.redis.status |
equals | ok |
checks.worker.ageMs |
< | 60000 |
items[0].id |
exists |
- Paths use dots and brackets:
a.b,items[0](oritems.0,items[-1]for the last one),["key.with.dots"]. A leading$.is allowed. - Operators: equals, not equals, contains (substring, array element or object key), not contains, exists, not
exists,
>,>=,<,<=(numbers) and matches (regular expression). - Values are compared by type: numbers as numbers (
3equals3.0),true/false/nullby name, objects and arrays as JSON. - Rules run on agents too. Agents older than this feature fail the check with "update it" instead of passing it unchecked.
──Response time per phase
HTTP and keyword checks measure where the time goes: DNS lookup, connect, TLS handshake, wait for the first byte (the server at work) and transfer of the body. On the monitor page switch the response time chart to by phase, per location or all together; hover a latency in the check log for the breakdown of that check. With redirects the phases of every hop are added up.
The monitor page also shows uptime and response time percentiles (p50, p95, p99) for any period, compared with the period before. Drag on the chart to zoom in.
──Degraded and slow threshold
A monitor is degraded when some of its locations fail, but not more than half. The share that counts is set in settings → monitors (35% by default) and can be changed per monitor, up to 50%. Degraded opens no incident and counts as up for uptime; channels can get it as an event (off by default).
A monitor can also turn degraded when it answers too slowly. Set the slow threshold:
- off (default);
- fixed, in ms (below the timeout): a location is slow when the median of its last 3 successful checks is above it, so one spike changes nothing;
- automatic: each location gets its own threshold, 3 times its usual response time and at least 100 ms more. The usual time is the median of its hourly averages over the last 7 days, so a far-away agent has its own baseline. It starts once a location has 24 hours of history.
Slow locations count like failing ones toward the degraded share, never toward down. With one location, being
slow is enough. The response time chart draws the threshold as a dashed line, and the alert says which location
was slow and by how much. For heartbeat monitors the threshold applies to the ping= duration.
──IPv6
Every check type works over IPv6, and hosts with only AAAA records just work. Put IPv6 addresses in brackets when a
port follows: [2001:db8::1]:443 (tcp), https://[2001:db8::1]/, redis://[2001:db8::1]:6379,
grpc://[2001:db8::1]:50051. Ping and dns take the bare address (2001:db8::1); ping uses ICMPv6.
ip version sets how a check treats a host with both IPv4 and IPv6:
| option | API ip_family |
the check |
|---|---|---|
| instance default | 0 |
uses the default set in settings → monitors |
| IPv4 or IPv6 | 1 |
one connection, whichever family answers first: a broken IPv6 goes unnoticed |
| IPv4 only / IPv6 only | 4 / 6 |
only that family |
| IPv4 and IPv6 | 46 |
both, in parallel: fails when either fails (the message says which), latency is the slower one |
The hub and every agent test whether they reach the Internet over IPv6; the agents page and the monitor form show the result. A location without IPv6 cannot be chosen for IPv6 only or IPv4 and IPv6; IPv4 or IPv6 and the instance default check over IPv4 there. TLS certificate expiry is read over either family. For Docker, see IPv6 in Docker.
──Databases, containers, gRPC and SMTP
Passwords in connection URLs are hidden in the monitor list, from read-only users and in alerts; use a read-only database user. PostgreSQL, MySQL and MongoDB use TLS when the server offers it.
Docker checks talk to the Docker Engine of the location that runs them: the hub or the agent needs
/var/run/docker.sock (or DOCKER_HOST). With Docker, add -v /var/run/docker.sock:/var/run/docker.sock:ro to
the hub or agent container (the entrypoint lets the pingtxt user use it). For an agent installed with systemd,
allow it with sudo systemctl edit pingtxt-agent:
[Service]SupplementaryGroups=docker
Access to the Docker socket is equivalent to root on that machine (:ro does not limit the API). pingtxt only
reads GET /containers/<name>/json, but enable it only where you need container checks.
──MCP servers
A monitor of type mcp server checks a remote Model Context Protocol server. (To let AI assistants use pingtxt itself, see the MCP server of the hub.)
| setting | |
|---|---|
| target | URL of the endpoint, e.g. https://mcp.example.com/mcp |
| transport | auto (default): streamable HTTP, falling back to the legacy HTTP+SSE transport (2024-11-05) when the POST is rejected with 400/404/405/406/415; or force streamable / sse |
| headers | sent with every request, e.g. Authorization: Bearer <token>; a 401 or 403 makes the monitor go down. Hidden from read-only users |
| required tools | optional, comma-separated: down when one of them is not in tools/list |
| minimum tools | optional: down when tools/list returns fewer tools |
Each check runs initialize, sends notifications/initialized, then tools/list (all pages) when the server
advertises tools or a tool condition is set, and finally deletes the session. Tools are never called. The result
shows the server name and version, the protocol version, the transport and the tool count, e.g.
my-server 1.4.0 · mcp 2025-06-18 · streamable · 12 tools. https endpoints get certificate expiry alerts.
──Heartbeat monitors (cron jobs)
For jobs that run on a schedule (backups, cron, queues), create a monitor of type heartbeat (push). It gets a secret URL; the job calls it at the end of every run, with any HTTP method:
0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://status.example.com/api/push/<token> >/dev/null
The monitor goes down when no call arrives within the expected period plus the grace time, and back up at
the next call. Optional query parameters: status=down reports a failed run, msg= stores a short note, ping=
the run time in ms. The URL uses the public URL from the settings and can be regenerated from the monitor page.
──Groups and tags
A monitor sits in one group (or none) and has any number of colored tags. Manage them on the groups page. Then:
- filter the dashboard by group or tag, and show groups as sections;
- add whole groups to a status page: monitors added to the group later show up too;
- pick monitors by group or tag in maintenance windows and notification channels;
- filter the API:
GET /api/monitors?group=<id>(orgroup=none) and?tag=<id>.
──Diagnostics on failure
At the first failure of a check, the location that ran it collects diagnostics right away and sends them with the failed result, so they are ready when the alert goes out:
- DNS: the A/AAAA answers (and CNAME) of the system resolver; for DNS monitors also the answer of their server and the NS records of the name;
- TCP: a connection to each resolved address (up to 4) on the monitor's port;
- TLS: version, certificate subject, issuer, names, expiry and the verification error;
- HTTP: status, redirects (without query strings) and response headers. Cookies,
Authorizationand any header whose name contains token, key, secret, session, csrf or auth are redacted. The body and the request headers are never kept; - traceroute: up to 20 hops with reverse names, as TCP SYNs to the monitor's port (UDP for ping and DNS). It
needs no root: on Linux it reads the ICMP errors like
tracepath, so it works in the non-root containers. Other systems skip it for now.
It takes at most 8 seconds and 16 KB, and runs at most once every 10 minutes per monitor and location. The first
alert of an incident lists one line per failing location and links to the full diagnostics on the incidents page;
webhooks get diagnostics and diagnostics_url, reminders only the link. Diagnostics are never shown on status
pages. They are also in the API (GET /api/incidents/{id}/diagnostics) and the MCP tool
get_incident_diagnostics.
Turn them off in settings → monitors, or per monitor. Diagnostics of incidents are kept 30 days (configurable); those of failures that never became an incident, one day.
──Import from Uptime Kuma
settings → data → import from uptime kuma reads a backup file of Uptime Kuma 1.x (Settings → Backup → Export there) and shows what will be created before anything changes. Groups and tags come along and paused monitors stay paused; notification channels are not imported.