DocumentationFirst monitor

Getting started

Your first monitor

Sixty seconds from a running install to a monitor checking something. Every command below has been run; the output is real.

If you have not installed it yet, install.md is four ways in.


1. Create the administrator account#

Open http://localhost:3000. The first visit asks for an email and a password, and nothing else — no organisation name, no plan, no email verification.

The password is hashed with argon2id and there is no recovery path other than the database. Use a password manager.

Through the API, if you prefer:

curl -s -c cookies.txt http://localhost:3000/api/v1/setup \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","password":"correct-horse-battery"}'

The response carries a csrf_token. Keep it: every write echoes it in X-Cairn-CSRF-Token, and the server issues it exactly once. GET /auth/session deliberately does not reissue it.

2. Create a monitor#

In the dashboard: New, pick HTTP, give it a URL, save.

Through the API:

curl -s -b cookies.txt http://localhost:3000/api/v1/monitors \
  -H 'Content-Type: application/json' \
  -H "X-Cairn-CSRF-Token: $CSRF" \
  -d '{
    "name": "Checkout",
    "type": "http",
    "config": { "url": "https://example.com/health" },
    "interval_seconds": 60
  }'

That is the whole minimum. Everything else has a default that works: a 30-second timeout, one retry, no alerting yet.

3. Watch it check#

The monitor starts as pending, not up and not down. A monitor that has never reported has not earned a verdict either way, and rendering it as up would be a claim nobody made.

Within one interval it flips. In the dashboard the row updates on its own — the list holds a live channel scoped to exactly the monitors on screen, so a status change appears within a second or two rather than on a refresh.

Through the API:

curl -s -b cookies.txt \
  "http://localhost:3000/api/v1/monitors/$ID/heartbeats?limit=5" | jq '.data[]'
{
  "monitor_id": "01a02503-3d6a-72a3-a262-1145394c47d7",
  "time": "2026-08-21T15:49:44.574816Z",
  "status": "up",
  "response_time_ms": 84.2,
  "code": "200",
  "attempt": 1,
  "important": true
}

important marks a transition. It is what the activity feed and the alerting path both key on, and it is why an install that has been green for a month has a readable history rather than 43,200 identical rows to scroll past.

Do not wait for the interval if you are impatient: Check now on the monitor, or POST /api/v1/monitors/{id}/check. It runs the same checker through the same ingest path, so a manual check is indistinguishable from a scheduled one — same transition table, same alerts, same certificate observation. A "test" that took a different path would be testing the test. It is rate-limited to one every ten seconds per monitor, because the thing being protected is somebody else's server.

4. Make it tell you#

A monitor with no notification channel is a monitor that goes down quietly.

Notifications → New, pick a type, fill it in, and press Send test. The test is a real delivery and it reports what the provider said, verbatim — not "success", but the provider's own words, because "it says success and nothing arrived" is the failure this exists to catch.

Thirteen channel types ship: email, generic webhook, Slack, Discord, Telegram, Matrix, Gotify, ntfy, Microsoft Teams, PagerDuty, Opsgenie, Twilio/SMS, and Apprise — which is roughly ninety more, if you have Apprise installed.

Two things worth knowing before you pick one:

  • Email needs a relay. Either configure the instance relay in Settings → Mail relay, or give the channel its own SMTP settings. A channel set to use the instance relay when there is none is refused at save time with the alternative spelled out, rather than accepted and silently undeliverable.
  • A channel marked default is attached to every monitor created afterwards. It does not retro-attach to monitors that already exist.

Then attach it: on the monitor form, or in bulk from the monitor list.

Leaving the channel list absent on a monitor attaches the defaults. Setting it to an empty list means a deliberately silent monitor. The two are different and the server keeps them apart, which is what lets you have a monitor you watch and are not paged for.

5. Prove it works#

The most valuable minute you will spend on a monitoring tool is the one where you make it fire on purpose.

Point a throwaway monitor at something that will fail, on a short interval:

curl -s -b cookies.txt http://localhost:3000/api/v1/monitors \
  -H 'Content-Type: application/json' \
  -H "X-Cairn-CSRF-Token: $CSRF" \
  -d '{
    "name": "Deliberately broken",
    "type": "http",
    "config": { "url": "https://httpbin.org/status/500" },
    "interval_seconds": 20,
    "retries": 0,
    "notification_channel_ids": ["'"$CHANNEL_ID"'"]
  }'

Within twenty seconds it goes down and the alert fires. Delete it afterwards.

If nothing arrives, the channel's own row shows its last error — a channel that has quietly stopped working is the failure mode this product cannot have, so the error lives on the channel rather than only in the log.


What next#

  • Monitor types — the nine types, what each one actually checks, and the config that is not obvious.
  • Alerting — every channel, field by field, and webhook templating.
  • A status page — Status pages → New. Pick monitors, publish, and the page is live at /status/{slug}.
  • Coming from Uptime Kuma — do not rebuild by hand.
Edit this page on GitHubdocs/guides/quickstart.md · synced from 47b3cf5