Skip to content

YAML Reference

Arian Omrani edited this page Oct 11, 2026 · 2 revisions

YAML reference

Language: English · فارسی

Every key of pulsecheck.yml, its type, default and rules. For explanations and recipes see Configuration. Unknown keys anywhere are errors (pulsecheck validate names the key and where it is).

File rules

Rule Detail
Where -c FILE, else ./pulsecheck.yml, else ~/.config/pulsecheck/pulsecheck.yml
Format YAML. JSON is accepted too (the Cloudflare Worker ships JSON)
${NAME} Replaced in every string value (also inside lists and mappings; not in keys) with the environment variable NAME. A variable that is not set is an error (an empty KEY= line in .env counts as not set). There is no default syntax (${X:-y} is not supported)
.env <folder of the config>/.env is loaded first (KEY=value; # comments; quotes allowed; export allowed). Real environment variables win. Empty values count as not set
Types int accepts 5 or "5", not true. str accepts text or a number. A list must be a list, a mapping must be a mapping
Inline mappings Quote values containing ${VAR} inside { ... }: {url: "https://x/${T}"}

Top level

Key Type Default Meaning
sites list of site required The checks. name must be unique
defaults mapping {} Any site key; merged under every site. The site's own value replaces it (no deep merge: a site headers replaces the default headers completely)
notify notify no urls Global alert targets
messages mapping built-in Alert texts, see messages
maintenance list of maintenance [] Windows that suppress alerts
otel otel off OpenTelemetry export
state_file str pulsecheck.db SQLite file (CLI only). ~ is expanded; a relative path is relative to the config file's folder, so cron finds the same file. Ignored on Vercel/Cloudflare
shoutrrr_bin str auto auto = Docker image if docker info works, else the shoutrrr binary; docker = always the image; any other value = path to a binary. Ignored on Cloudflare
shoutrrr_image str nickfedor/shoutrrr:0.21.2 Image used in auto/docker mode

notify

Key Type Default Meaning
urls list of str [] shoutrrr URLs (see Notifications)
events list of str all four Which alerts to send: down, up, degraded, ssl_warn. A repeated "still down" reminder counts as down

A site-level notify replaces the global one completely, including events.

sites

Common keys (every type):

Key Type Default Meaning
name str required Unique; used in alerts, status and reports
type http | tcp | ping http What to check
timeout int (seconds) 10 Per check (connect / request / ping wait)
down_after int 2 Consecutive failures before the site is down and the first alert is sent
interval int (minutes) 5 Minimum time between checks of this site. A run skips the site if its last check was less than interval minutes minus 1 minute ago (the minute absorbs scheduler jitter)
max_response_ms int | null off A successful check slower than this counts as a failure
slow_ms int | null off A successful check at least this slow is degraded (sends a degraded alert on change)
remind_every int (minutes) 0 (off) While down, repeat the alert (message key reminder) every N minutes. Also the minimum gap between certificate warnings (default once a day)
ip_version 4 | 6 | null system default Connect only over IPv4 or IPv6, for http, tcp, ping and the certificate check. A host with no address of that family is reported down (for example Address family for hostname not supported); there is no silent fallback. IPv6 literals work without this key: url: http://[2001:db8::1]/, host: 2001:db8::1. Skipped on Cloudflare
tags list of str [] Labels for --tag, and {tags} in messages and metrics
notify notify | null global Per-site alert targets
messages mapping {} Per-site alert texts (beat the global messages)

type: http

Key Type Default Meaning
url str required http:// or https:// URL
method str GET HTTP method
headers mapping str→str {} Request headers
body str | null none Request body (ignored for GET/HEAD on Cloudflare)
expected_status list of int [] Status codes that count as up. Empty = any 2xx. Redirects are followed first, so this is the final status
max_redirects int 5 Redirects to follow (CLI/Vercel; ignored on Cloudflare)
ssl_warn_days int | null off https only. Warn when the certificate expires in fewer days than this (at most once a day, or per remind_every); a certificate that has expired fails the check with TLS certificate has expired. Not available on Cloudflare

type: tcp

Key Type Default Meaning
host str required Name or IP
port int required Port. Up = the connection opened. Not available on Cloudflare

type: ping

Key Type Default Meaning
host str required Name or IP. Runs ping -c 1 -W <timeout> <host> (Linux iputils). Not available on Vercel or Cloudflare

messages

Keys you may set (anything else is an error). Unset keys keep the built-in text.

Key Sent when Built-in
down the site went down 🔴 {site} is DOWN: {error}
reminder still down after remind_every 🔴 {site} is still DOWN after {minutes}m: {error}
degraded up but slow (slow_ms) 🟡 {site} is slow ({ms}ms)
up recovered 🟢 {site} is UP ({ms}ms) after {minutes}m
ssl_warn certificate expires soon 🔒 {site}: TLS certificate expires in {days} days
test pulsecheck test-notify pulsecheck test notification

Placeholders (others are errors): {site} {event} {error} {ms} {minutes} {status} {tags} {days}. Use {{ and }} for literal braces. Order: site messages > global messages > built-in.

maintenance

Key Type Default Meaning
start str required "HH:MM" (every day) or "DAY HH:MM" with MON TUE WED THU FRI SAT SUN. UTC
duration int (minutes) required May cross midnight
name str maintenance Label only
sites list of str [] (all) Site names the window applies to

Checks keep running and are stored; the alerts (and OpenTelemetry log records) raised inside the window are dropped, not delivered later. Metrics are still exported.

otel

Key Type Default Meaning
endpoint str required Base URL, for example https://collector:4318. /v1/metrics and /v1/logs are appended
headers mapping str→str {} Extra headers, for example Authorization
service_name str pulsecheck service.name resource attribute
resource mapping str→str {} More resource attributes
metrics bool true pulsecheck.up, .response_time, .http.status_code, .ssl.days_remaining
logs bool true One record per alert

How the values combine

  1. A check result is ok if the transport worked, the status is expected, and it was not slower than max_response_ms.
  2. ok and slower than slow_ms → degraded; ok otherwise → up; not ok → counts a failure, and the site becomes down after down_after failures in a row.
  3. An alert goes out only when the status changes (or a reminder / certificate warning is due), is not inside a maintenance window, and its event is listed in events.

Complete example

state_file: pulsecheck.db
shoutrrr_bin: auto
shoutrrr_image: nickfedor/shoutrrr:0.21.2

notify:
  urls: ["telegram://${TG_TOKEN}@telegram?chats=${TG_CHAT}", "ntfy://ntfy.sh/${NTFY_TOPIC}"]
  events: [down, up, degraded, ssl_warn]

messages:
  down: "🔴 {site} is DOWN: {error}"
  up: "🟢 {site} recovered after {minutes} min"

otel:
  endpoint: https://otel-collector.example.com:4318
  headers: {Authorization: "Bearer ${OTEL_TOKEN}"}
  resource: {env: prod}

maintenance:
  - {name: weekly, start: "SUN 02:00", duration: 60, sites: [api]}

defaults: {timeout: 10, down_after: 2, interval: 5, slow_ms: 3000, remind_every: 60}

sites:
  - name: web
    url: https://example.com
    expected_status: [200, 301]
    max_response_ms: 10000
    ssl_warn_days: 14
    tags: [prod, web]
  - name: api
    url: https://api.example.com/health
    method: POST
    headers: {Authorization: "Bearer ${API_TOKEN}"}
    body: '{"ping": true}'
    max_redirects: 3
    notify: {urls: ["discord://${DISCORD_TOKEN}@${DISCORD_ID}"], events: [down, up]}
    messages: {down: "💳 api DOWN, page on-call: {error}"}
  - {name: db, type: tcp, host: db.internal, port: 5432, interval: 1}
  - {name: gateway, type: ping, host: 10.0.0.1}

What each platform supports

Key / feature CLI, CI, cron Vercel Cloudflare
type: http yes yes yes (max_redirects ignored)
type: tcp yes yes skipped
type: ping yes skipped skipped
ssl_warn_days yes yes ignored
ip_version yes yes, if the platform has that connectivity (not tested) site skipped
state_file, shoutrrr_bin, shoutrrr_image yes ignored ignored
notify.urls any shoutrrr URL built-in 12 services, others via downloaded shoutrrr built-in 12 services
everything else yes yes yes

Other inputs

Name Used by
XDG_CONFIG_HOME, XDG_STATE_HOME where init puts the config / state and log
VISUAL, EDITOR pulsecheck env
CRON_SECRET Vercel: bearer token for /api/cron and /api/status
STATUS_TOKEN Cloudflare: bearer token for /status and /run
KV_REST_API_URL, KV_REST_API_TOKEN (or UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN) Vercel state store
PULSECHECK_SOURCE install.sh: what uv tool install installs

Exit codes

Command 0 1
run finished with --fail-on-down: at least one site is down
validate valid an alert URL was rejected by shoutrrr (a config error stops with a message)
test-notify every channel worked at least one failed, or none configured
update done / up to date the upgrade command failed

Clone this wiki locally